react-timeline-component
Version:
SVG Timeline built in react. For showing dates on a line.
262 lines (215 loc) • 9.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
require('./TimelineComponent.css');
var moment = require('moment');
var _ = require('lodash');
var SVG_WIDTH = 1000;
var SVG_HEIGHT = 40;
var SVG_VERTICAL_PADDING = 80;
var SVG_WORKING_WIDTH = SVG_WIDTH - SVG_VERTICAL_PADDING * 2;
function dateToLabel(date) {
return moment(date).format('MMM DD YYYY').toUpperCase();
}
function sortDataByDates(dates) {
return _.sortBy(dates, 'date');
}
function diffMonthsBetweenDates(firstDate, lastDate) {
return moment(lastDate).diff(moment(firstDate), 'months');
}
function transformTranslate(x, y) {
return 'translate(' + x + ',' + y + ')';
}
function labelGroupPos(dataArray, groupIndex) {
var widthInterval = SVG_WORKING_WIDTH / diffMonthsBetweenDates(dataArray[0].date, dataArray[dataArray.length - 1].date);
if (dataArray[groupIndex - 1] === undefined) {
return -26;
} else {
var totalMonthsSoFar = diffMonthsBetweenDates(dataArray[0].date, dataArray[groupIndex - 1].date);
var monthsBetweenThisDateAndLast = diffMonthsBetweenDates(dataArray[groupIndex - 1].date, dataArray[groupIndex].date);
return (totalMonthsSoFar + monthsBetweenThisDateAndLast) * widthInterval - 26;
}
}
var Circle = function Circle(_ref) {
var x = _ref.x;
var y = _ref.y;
return _react2['default'].createElement('path', { transform: transformTranslate(x, y), d: 'M7 12c2.76 0 5-2.24 5-5S9.76 2 7 2 2 4.24 2 7s2.24 5 5 5z',
strokeOpacity: '.492', stroke: '#2A2A2A', strokeWidth: '.5', fill: '#fff', fillRule: 'evenodd' });
};
Circle.props = {
x: 0,
y: 0
};
var Label = function Label(_ref2) {
var value = _ref2.value;
return _react2['default'].createElement(
'text',
{ x: 0, y: 30,
fontFamily: 'Verdana',
fontSize: '9',
width: '100%' },
dateToLabel(value)
);
};
var TimelineComponent = (function (_React$Component) {
_inherits(TimelineComponent, _React$Component);
function TimelineComponent(props) {
_classCallCheck(this, TimelineComponent);
_get(Object.getPrototypeOf(TimelineComponent.prototype), 'constructor', this).call(this, props);
this.state = {
showingPopover: false
};
}
_createClass(TimelineComponent, [{
key: 'showPopover',
value: function showPopover(index) {
this.setState({
showingPopover: index
});
}
}, {
key: 'hidePopover',
value: function hidePopover() {
this.setState({
showingPopover: false
});
}
}, {
key: 'render',
value: function render() {
var _this = this;
var sortedData = sortDataByDates(this.props.data);
var sortedDataUniqByDate = _.uniq(sortedData, 'date');
function translateX(x) {
return 'translate(' + x + ',0)';
}
var monthMarkers = [];
var monthsBetweenExtremes = diffMonthsBetweenDates(sortedData[0].date, sortedData[sortedData.length - 1].date);
for (var i = -1; i < monthsBetweenExtremes; i++) {
if (monthsBetweenExtremes != 0) {
monthMarkers.push(_react2['default'].createElement('rect', { width: 1, height: 5, y: 0, fill: '#000000',
x: SVG_WORKING_WIDTH / monthsBetweenExtremes * (i + 1),
key: i }));
}
}
return _react2['default'].createElement(
'div',
{ style: { position: 'relative', height: '90px' } },
_react2['default'].createElement(
'svg',
{ width: SVG_WIDTH, height: SVG_HEIGHT },
_react2['default'].createElement(
'g',
{ transform: translateX(SVG_VERTICAL_PADDING) },
_react2['default'].createElement('rect', { width: SVG_WORKING_WIDTH, height: 1 }),
sortedDataUniqByDate.map(function (date, index) {
return _react2['default'].createElement(
'g',
{ transform: translateX(labelGroupPos(sortedDataUniqByDate, index)),
key: index,
onMouseOver: _this.showPopover.bind(_this, index),
onMouseOut: _this.hidePopover.bind(_this),
style: { cursor: 'pointer' } },
_react2['default'].createElement(Circle, { x: 20, y: 4 }),
_react2['default'].createElement(Label, { value: date.date, index: index, uniqueLabelsCount: sortedDataUniqByDate.length })
);
}),
monthMarkers
)
),
_react2['default'].createElement(Popovers, { data: sortedData, showingPopover: this.state.showingPopover })
);
}
}]);
return TimelineComponent;
})(_react2['default'].Component);
exports['default'] = TimelineComponent;
var Popovers = (function (_React$Component2) {
_inherits(Popovers, _React$Component2);
function Popovers() {
_classCallCheck(this, Popovers);
_get(Object.getPrototypeOf(Popovers.prototype), 'constructor', this).apply(this, arguments);
}
_createClass(Popovers, [{
key: 'render',
value: function render() {
var _props = this.props;
var data = _props.data;
var showingPopover = _props.showingPopover;
var style = {
fontFamily: 'sans-serif',
font: 'caption',
fontWeight: 400,
fontSize: 11,
position: 'relative',
left: SVG_VERTICAL_PADDING - 25 + 'px'
};
return _react2['default'].createElement(
'div',
{ style: style },
_.uniq(data, 'date').map(function (date, index) {
return _react2['default'].createElement(Popover, {
data: data,
date: date,
offset: index,
visible: showingPopover === index,
key: index });
})
);
}
}]);
return Popovers;
})(_react2['default'].Component);
var Popover = (function (_React$Component3) {
_inherits(Popover, _React$Component3);
function Popover() {
_classCallCheck(this, Popover);
_get(Object.getPrototypeOf(Popover.prototype), 'constructor', this).apply(this, arguments);
}
_createClass(Popover, [{
key: 'render',
value: function render() {
var _props2 = this.props;
var showingPopover = _props2.showingPopover;
var offset = _props2.offset;
var data = _props2.data;
var date = _props2.date;
var styles = {
position: 'absolute',
left: labelGroupPos(_.uniq(data, 'date'), offset) - 4 + 'px',
border: '2px solid #979797',
backgroundColor: 'white',
padding: '.5em',
borderRadius: '6px',
width: '100px',
minHeight: '2em',
display: this.props.visible ? 'block' : 'none',
zIndex: 1
};
return _react2['default'].createElement(
'div',
{ className: 'timelineComponentPopover', style: styles },
_.where(data, { date: date.date }).map(function (item, itemIndex) {
var textStyles = {
margin: '0 0 .5em 0'
};
return _react2['default'].createElement(
'div',
{ style: textStyles, key: itemIndex },
item.name
);
})
);
}
}]);
return Popover;
})(_react2['default'].Component);
module.exports = exports['default'];