Skip to content

Commit

Permalink
feat(calendar): add pure React based Calendar component
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphael Benitte committed May 10, 2016
1 parent 2acc80b commit a0473e4
Show file tree
Hide file tree
Showing 8 changed files with 340 additions and 147 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
- [`<BubblePlaceholders />`](https://plouc.github.io/nivo/#/bubble/placeholders)
- [`<ResponsiveBubblePlaceholders />`](https://plouc.github.io/nivo/#/bubble/placeholders)
- Calendar
- [`<Calendar />`](https://plouc.github.io/nivo/#/calendar)
- [`<Calendar />`](https://plouc.github.io/nivo/#/calendar/react)
- [`<ResponsiveCalendar />`](https://plouc.github.io/nivo/#/calendar/react)
- [`<CalendarD3 />`](https://plouc.github.io/nivo/#/calendar/d3)
- [`<ResponsiveCalendarD3 />`](https://plouc.github.io/nivo/#/calendar/d3)
- Stack
- [`<Stack />`](https://plouc.github.io/nivo/#/stack)
- [`<ResponsiveStack />`](https://plouc.github.io/nivo/#/stack)
Expand Down
215 changes: 72 additions & 143 deletions src/components/charts/calendar/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,175 +8,104 @@
*/
'use strict';

import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import d3 from 'd3';
import _ from 'lodash';
import Nivo from '../../../Nivo';
import { margin as marginPropType } from '../../../PropTypes';
import decoratorsFromReactChildren from '../../../lib/decoratorsFromReactChildren';
import CalendarLayout from '../../../lib/charts/calendar/CalendarLayout';
import {
DIRECTION_HORIZONTAL,
DIRECTION_VERTICAL
} from '../../../constants/directions'
import React, { Component } from 'react';
import { TransitionMotion, spring } from 'react-motion';
import Nivo from '../../../Nivo';
import CalendarLayout from '../../../lib/charts/calendar/CalendarLayout';
import { calendarPropTypes, calendarDefaultProps } from './CalendarProps';


const color = d3.scale.category20();

class Calendar extends Component {
constructor(props) {
super(props);
componentWillMount() {
this.calendarLayout = CalendarLayout();
}

renderD3(props) {
render() {
const {
direction,
daySpacing, dayBorderWidth, dayBorderColor,
monthBorderWidth, monthBorderColor,
transitionDuration, transitionEasing, transitionStaggering
} = props;
motionStiffness, motionDamping
} = this.props;

const element = d3.select(findDOMNode(this));
const wrapper = element.select('.nivo_calendar_wrapper');

const margin = _.assign({}, Nivo.defaults.margin, props.margin);
const width = props.width - margin.left - margin.right;
const height = props.height - margin.top - margin.bottom;


element.attr({
width: props.width,
height: props.height
});
wrapper.attr('transform', `translate(${margin.left},${margin.top})`);
const margin = _.assign({}, Nivo.defaults.margin, this.props.margin);
const width = this.props.width - margin.left - margin.right;
const height = this.props.height - margin.top - margin.bottom;

const { days, months } = this.calendarLayout.compute({
width, height,
direction,
daySpacing
});


const rects = wrapper.selectAll('.nivo_calendar_day').data(days, d => d.date);

rects
.enter().append('rect')
.attr('class', 'nivo_calendar_day')
.attr('width', d => d.cellSize)
.attr('height', d => d.cellSize)
.attr('x', 0)
.attr('y', 0)
.style({
opacity: 0,
fill: d => color(d.date.getMonth()),
stroke: dayBorderColor,
'stroke-width': dayBorderWidth,
})
;

rects
.transition()
.duration(transitionDuration)
.ease(transitionEasing)
.delay(d => d3.time.dayOfYear(d.date) * transitionStaggering)
.attr('width', d => d.cellSize)
.attr('height', d => d.cellSize)
.attr('x', d => d.x)
.attr('y', d => d.y)
.style({
opacity: 1,
fill: d => color(d.date.getMonth()),
stroke: dayBorderColor,
'stroke-width': dayBorderWidth,
})
;


const paths = wrapper.selectAll('.nivo_calendar_month').data(months, d => d.date);

paths.enter().append('path')
.attr('class', 'nivo_calendar_month')
.style({
fill: 'none',
stroke: monthBorderColor,
'stroke-width': monthBorderWidth,
})
.attr('d', d => d.path)
;

paths
.transition()
.duration(transitionDuration)
.ease(transitionEasing)
.delay((d, i) => i * 30 * transitionStaggering)
.style({
stroke: monthBorderColor,
'stroke-width': monthBorderWidth,
})
.attr('d', d => d.path)
;

this.decorators.forEach(decorator => {
const defaultStyles = days.map(d => {
return {
key: d.date.toString(),
data: d,
style: {
size: d.size,
x: 0,
y: 0,
}
};
});
}

componentWillMount() {
this.calendarLayout = CalendarLayout();
}

shouldComponentUpdate(nextProps, nextState) {
this.decorators = decoratorsFromReactChildren(nextProps.children, 'decorateCalendar');

this.renderD3(nextProps, nextState);

return false;
}

componentDidMount() {
this.decorators = decoratorsFromReactChildren(this.props.children, 'decorateCalendar');

this.renderD3(this.props, this.state);
}
const stiffness = motionStiffness;
const damping = motionDamping;

render() {
return (
<svg ref="svg" className="nivo_calendar">
<g className="nivo_calendar_wrapper" />
<svg className="nivo_calendar" style={{ width: this.props.width, height: this.props.height }}>
<g className="nivo_calendar_wrapper" transform={`translate(${margin.left},${margin.top})`}>
<TransitionMotion
defaultStyles={defaultStyles}
styles={days.map(d => {
return {
key: d.date.toString(),
data: d,
style: {
size: spring(d.size, { stiffness, damping }),
x: spring(d.x, { stiffness, damping }),
y: spring(d.y, { stiffness, damping }),
}
};
})}
>
{interpolatedStyles => (
<g>
{interpolatedStyles.map(d => (
<rect
key={d.key}
x={d.style.x}
y={d.style.y}
width={d.style.size}
height={d.style.size}
style={{
fill: 'rgba(0, 0, 0, .15)',
stroke: dayBorderColor,
strokeWidth: dayBorderWidth,
}}
/>
))}
</g>
)}
</TransitionMotion>
</g>
</svg>
);
}
}

const { number, string, oneOf } = PropTypes;

Calendar.propTypes = {
width: number.isRequired,
height: number.isRequired,
margin: marginPropType,
direction: oneOf([DIRECTION_HORIZONTAL, DIRECTION_VERTICAL]),
daySpacing: number.isRequired,
dayBorderWidth: number.isRequired,
dayBorderColor: string.isRequired,
monthBorderWidth: number.isRequired,
monthBorderColor: string.isRequired,
transitionDuration: number.isRequired,
transitionEasing: string.isRequired,
transitionStaggering: number.isRequired,
};

Calendar.defaultProps = {
margin: Nivo.defaults.margin,
direction: DIRECTION_HORIZONTAL,
daySpacing: 0,
dayBorderWidth: 1,
dayBorderColor: '#000',
monthBorderWidth: 2,
monthBorderColor: '#000',
transitionDuration: Nivo.defaults.transitionDuration,
transitionEasing: Nivo.defaults.transitionEasing,
transitionStaggering: 5,
};
Calendar.propTypes = _.omit(calendarPropTypes, [
'transitionDuration',
'transitionEasing',
'transitionStaggering',
]);

Calendar.defaultProps = _.omit(calendarDefaultProps, [
'transitionDuration',
'transitionEasing',
'transitionStaggering',
]);


export default Calendar;
Loading

0 comments on commit a0473e4

Please sign in to comment.