react-gear-chart
Version:

353 lines (291 loc) • 12.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = undefined;
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _reactMotion = require('react-motion');
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _Tooth = require('./Tooth');
var _Tooth2 = _interopRequireDefault(_Tooth);
var _math = require('../utils/math');
var _shouldUpdate = require('should-update');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var shoudlUpdateStates = ['childFocused'];
var shouldUpdateProps = ['id', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius', 'margin', 'limit', 'clockwise', 'items', 'extra'];
var Styles = {
container: {
display: 'inline-block',
padding: '1em'
},
pointer: {
cursor: 'pointer'
}
/**
* Use Polar Coordinate System with convention:
* https://en.wikipedia.org/wiki/Polar_coordinate_system#/media/File:Polar_graph_paper.svg
*/
};
var GearListChart = function (_PureComponent) {
(0, _inherits3.default)(GearListChart, _PureComponent);
function GearListChart() {
var _ref;
var _temp, _this, _ret;
(0, _classCallCheck3.default)(this, GearListChart);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, (_ref = GearListChart.__proto__ || (0, _getPrototypeOf2.default)(GearListChart)).call.apply(_ref, [this].concat(args))), _this), _this.state = {
childFocused: false
}, _this.mouseEventProxy = function (evt) {
var name = GearListChart.getRegistrationName(evt);
_this.props[name](evt);
if (name === 'onClick') {
var self = _this.chart;
var teeth = self.querySelectorAll('.tooth');
var focusedTooth = self.querySelector('.tooth.focused');
if (focusedTooth && focusedTooth.contains(evt.target) && _this.state.childFocused) {
_this.setState({ childFocused: false });
} else {
_this.setState({ childFocused: true });
}
teeth.forEach(function (t) {
return t.classList.remove('focused');
});
}
}, _this.motionWillEnter = function () {
var clockwiseAnimate = _this.props.clockwiseAnimate;
var totalAnagle = _this.totalAnagle();
var style = {
offsetAngle: clockwiseAnimate ? -totalAnagle : totalAnagle,
opacity: 0
};
return style;
}, _this.motionWillLeave = function () {
var _this$props = _this.props,
clockwiseAnimate = _this$props.clockwiseAnimate,
motionConfig = _this$props.motionConfig;
var totalAnagle = _this.totalAnagle();
var style = {
offsetAngle: (0, _reactMotion.spring)(clockwiseAnimate ? totalAnagle : -totalAnagle, motionConfig),
opacity: (0, _reactMotion.spring)(0, motionConfig)
};
return style;
}, _this.clearFocus = function () {
var focused = _this.chart.querySelector('.tooth.focused');
focused && focused.classList.remove('focused');
_this.setState({ childFocused: false });
}, _this.isFocused = function () {
return _this.chart.classList.contains('child-focused');
}, _temp), (0, _possibleConstructorReturn3.default)(_this, _ret);
}
(0, _createClass3.default)(GearListChart, [{
key: 'totalAnagle',
value: function totalAnagle() {
var _props = this.props,
endAngle = _props.endAngle,
startAngle = _props.startAngle;
var _NormalizeAngleRange = (0, _math.NormalizeAngleRange)(startAngle, endAngle),
_NormalizeAngleRange2 = (0, _slicedToArray3.default)(_NormalizeAngleRange, 2),
_startAngle = _NormalizeAngleRange2[0],
_endAngle = _NormalizeAngleRange2[1];
return _endAngle - _startAngle;
}
}, {
key: 'shouldComponentUpdate',
value: function shouldComponentUpdate(nextProps, nextState) {
return (0, _shouldUpdate.shouldUpdate)(shoudlUpdateStates, this.state, nextState) || (0, _shouldUpdate.shouldUpdate)(shouldUpdateProps, this.props, nextProps);
}
}, {
key: 'render',
value: function render() {
var _this2 = this;
var _props2 = this.props,
id = _props2.id,
innerRadius = _props2.innerRadius,
outerRadius = _props2.outerRadius,
items = _props2.items,
margin = _props2.margin,
limit = _props2.limit,
startAngle = _props2.startAngle,
endAngle = _props2.endAngle,
clockwise = _props2.clockwise,
animate = _props2.animate,
clockwiseAnimate = _props2.clockwiseAnimate,
motionConfig = _props2.motionConfig,
className = _props2.className,
style = _props2.style,
extra = _props2.extra,
onMouseMove = _props2.onMouseMove,
onMouseEnter = _props2.onMouseEnter,
onMouseLeave = _props2.onMouseLeave,
onMouseOver = _props2.onMouseOver,
onClick = _props2.onClick,
restProps = (0, _objectWithoutProperties3.default)(_props2, ['id', 'innerRadius', 'outerRadius', 'items', 'margin', 'limit', 'startAngle', 'endAngle', 'clockwise', 'animate', 'clockwiseAnimate', 'motionConfig', 'className', 'style', 'extra', 'onMouseMove', 'onMouseEnter', 'onMouseLeave', 'onMouseOver', 'onClick']);
if (!items || !items.length) return null;
var childFocused = this.state.childFocused;
var _NormalizeAngleRange3 = (0, _math.NormalizeAngleRange)(startAngle, endAngle),
_NormalizeAngleRange4 = (0, _slicedToArray3.default)(_NormalizeAngleRange3, 2),
_startAngle = _NormalizeAngleRange4[0],
_endAngle = _NormalizeAngleRange4[1];
var _AnnulusViewport = (0, _math.AnnulusViewport)(startAngle, endAngle, outerRadius, innerRadius, 10),
_AnnulusViewport2 = (0, _slicedToArray3.default)(_AnnulusViewport, 4),
width = _AnnulusViewport2[0],
height = _AnnulusViewport2[1],
cx = _AnnulusViewport2[2],
cy = _AnnulusViewport2[3];
var _perItemAngle = this.totalAnagle() / items.length;
if (_perItemAngle > limit) _perItemAngle = limit;
if (clockwise) {
/* shift half of the margin to centerize teeth */
_startAngle = _endAngle - margin / 2;
} else {
_startAngle = _startAngle + margin / 2;
}
return _react2.default.createElement(
'div',
(0, _extends3.default)({
id: id,
ref: function ref(r) {
return _this2.chart = r;
},
className: (0, _classnames2.default)('gear-list-chart', className, childFocused ? 'child-focused' : ''),
style: (0, _extends3.default)({}, Styles.container, style)
}, restProps),
_react2.default.createElement(
'svg',
{ width: width, height: height },
_react2.default.createElement(
_reactMotion.TransitionMotion,
{
willEnter: this.motionWillEnter,
willLeave: animate ? this.motionWillLeave : undefined,
defaultStyles: items.map(function (item, i) {
return {
key: item.id || String(i),
data: item,
style: {
offsetAngle: _this2.totalAnagle() * (clockwiseAnimate ? -1 : 1),
opacity: 1
}
};
}),
styles: items.map(function (item, i) {
return {
key: item.id || String(i),
data: item,
style: {
offsetAngle: animate ? (0, _reactMotion.spring)(0, motionConfig) : 0,
opacity: 1
}
};
})
},
function (interpolated) {
return _react2.default.createElement(
'g',
{ transform: 'translate(' + cx + ', ' + cy + ')' },
interpolated.map(function (conf, i) {
var item = conf.data;
// before item's leave it stays in interpolated array, have to get correct position
var leaveItemsCount = interpolated.length - items.length;
if (i >= leaveItemsCount) {
i -= leaveItemsCount;
}
var _GearListChart$getToo = GearListChart.getToothParam(i, _perItemAngle, margin, _startAngle, clockwise),
_GearListChart$getToo2 = (0, _slicedToArray3.default)(_GearListChart$getToo, 2),
start = _GearListChart$getToo2[0],
end = _GearListChart$getToo2[1];
return _react2.default.createElement(
'g',
{ key: conf.key || i },
_react2.default.createElement(_Tooth2.default, {
style: { cursor: onClick ? 'pointer' : 'inherit', opacity: conf.style.opacity },
startAngle: start,
endAngle: end,
offsetAngle: +conf.style.offsetAngle,
cx: 0,
cy: 0,
outerRadius: outerRadius,
innerRadius: innerRadius,
index: i,
data: item,
mode: item.mode,
label: item.label,
strips: item.strips,
onMouseMove: onMouseMove && _this2.mouseEventProxy,
onMouseLeave: onMouseLeave && _this2.mouseEventProxy,
onMouseEnter: onMouseEnter && _this2.mouseEventProxy,
onMouseOver: onMouseOver && _this2.mouseEventProxy,
onClick: onClick && _this2.mouseEventProxy,
extra: extra
})
);
})
);
}
)
)
);
}
}], [{
key: 'getToothParam',
value: function getToothParam(index, angle, margin, baseAngle) {
var clockwise = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
var _factor = clockwise ? -1 : 1;
var start = baseAngle + index * angle * _factor;
var end = start + angle * _factor - margin * _factor;
return [start, end].sort(function (a, b) {
return a - b;
});
}
}, {
key: 'getRegistrationName',
value: function getRegistrationName(evt) {
return evt.dispatchConfig.registrationName || evt.dispatchConfig.phasedRegistrationNames.bubbled;
}
/** willEnter for react-motion */
/** willLeave for react-motion */
/** Clear focus status if need to */
}]);
return GearListChart;
}(_react.PureComponent);
exports.default = GearListChart;
GearListChart.defaultProps = {
limit: 90,
startAngle: 0,
endAngle: 0,
margin: 0,
clockwise: true,
clockwiseAnimate: true,
animate: true,
motionConfig: {}
};
GearListChart.propTypes = {
startAngle: _propTypes2.default.number.isRequired,
endAngle: _propTypes2.default.number.isRequired,
innerRadius: _propTypes2.default.number.isRequired,
outerRadius: _propTypes2.default.number.isRequired,
margin: _propTypes2.default.number,
limit: _propTypes2.default.number
};