UNPKG

react-vis

Version:

Data visualization library based on React and d3.

376 lines (306 loc) 14.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 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 _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // Copyright (c) 2016 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _deepEqual = require('deep-equal'); var _deepEqual2 = _interopRequireDefault(_deepEqual); var _d3Shape = require('d3-shape'); var d3Shape = _interopRequireWildcard(_d3Shape); var _animation = require('../animation'); var _animation2 = _interopRequireDefault(_animation); var _scalesUtils = require('../utils/scales-utils'); var _chartUtils = require('../utils/chart-utils'); var _animationUtils = require('../utils/animation-utils'); var _theme = require('../theme'); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 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 _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 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 ATTRIBUTES = ['angle', 'radius', 'innerRadius', 'color', 'opacity', 'fill', 'stroke']; var ANIMATED_PROPS = ['angleDomain', 'angleRange', 'angle', 'radiusDomain', 'radiusRange', 'radius', 'innerRadiusDomain', 'innerRadiusRange', 'innerRadius', 'colorDomain', 'colorRange', 'color', 'opacityDomain', 'opacityRange', 'opacity', 'fillDomain', 'fillRange', 'fill', 'strokeDomain', 'strokeRange', 'stroke', 'data']; var DEFAULT_MARGINS = { left: 10, right: 10, top: 10, bottom: 10 }; /** * Walk through the data and assign color property to the data points if it * doesn't exist. * @param {Array} data Array of data. * @returns {Array} New array of data points. */ function assignColorsToData(data) { return data.map(function (d, color) { return _extends({ color: color }, d); }); } var RadialChart = function (_React$Component) { _inherits(RadialChart, _React$Component); _createClass(RadialChart, null, [{ key: 'propTypes', get: function get() { return { width: _react2.default.PropTypes.number.isRequired, height: _react2.default.PropTypes.number.isRequired, margin: _chartUtils.MarginPropType, animation: _animationUtils.AnimationPropType, onSectionMouseOver: _react2.default.PropTypes.func, onSectionMouseOut: _react2.default.PropTypes.func, onSectionClick: _react2.default.PropTypes.func }; } }]); function RadialChart(props) { _classCallCheck(this, RadialChart); var _this = _possibleConstructorReturn(this, (RadialChart.__proto__ || Object.getPrototypeOf(RadialChart)).call(this, props)); var data = assignColorsToData(props.data); var scaleProps = _this._getAllScaleProps(props, data); var arc = _this._getArcFromProps(scaleProps); _this.state = { scaleProps: scaleProps, data: data, arc: arc }; _this._sectionMouseOut = _this._sectionMouseOut.bind(_this); _this._sectionMouseOver = _this._sectionMouseOver.bind(_this); _this._sectionClick = _this._sectionClick.bind(_this); return _this; } _createClass(RadialChart, [{ key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var nextData = assignColorsToData(nextProps.data); var scaleProps = this.state.scaleProps; var nextscaleProps = this._getAllScaleProps(nextProps, nextData); if (!(0, _deepEqual2.default)(nextscaleProps, scaleProps)) { this.setState({ scaleProps: nextscaleProps, data: nextData, arc: this._getArcFromProps(scaleProps) }); } } /** * Triggers a callback on a section if the callback is set. * @param {function} handler Callback function. * @param {Object} d Data point of the arc. * @param {Object} event Event. * @private */ }, { key: '_triggerSectionHandler', value: function _triggerSectionHandler(handler, d, event) { if (handler) { var arc = this.state.arc; var _arc$centroid = arc.centroid(d); var _arc$centroid2 = _slicedToArray(_arc$centroid, 2); var x = _arc$centroid2[0]; var y = _arc$centroid2[1]; handler(d.data, { event: event, x: x, y: y }); } } /** * `mouseover` handler for the section. * @param {Object} d Data point. * @param {Object} event Event. * @private */ }, { key: '_sectionMouseOver', value: function _sectionMouseOver(d, event) { var onSectionMouseOver = this.props.onSectionMouseOver; this._triggerSectionHandler(onSectionMouseOver, d, event); } /** * `mouseout` handler for the section. * @param {Object} d Data point. * @param {Object} event Event. * @private */ }, { key: '_sectionMouseOut', value: function _sectionMouseOut(d, event) { var onSectionMouseOut = this.props.onSectionMouseOut; this._triggerSectionHandler(onSectionMouseOut, d, event); } /** * `click` handler for the section. * @param {Object} d Data point. * @param {Object} event Event. * @private */ }, { key: '_sectionClick', value: function _sectionClick(d, event) { var onSectionClick = this.props.onSectionClick; this._triggerSectionHandler(onSectionClick, d, event); } /** * Get the list of scale-related settings that should be applied by default. * @param {Object} props Object of props. * @returns {Object} Defaults. * @private */ }, { key: '_getDefaultScaleProps', value: function _getDefaultScaleProps(props) { var _getInnerDimensions = (0, _chartUtils.getInnerDimensions)(props, DEFAULT_MARGINS); var innerWidth = _getInnerDimensions.innerWidth; var innerHeight = _getInnerDimensions.innerHeight; var radius = Math.min(innerWidth / 2, innerHeight / 2); return { radiusRange: [0, radius], _radiusValue: radius, opacityRange: _theme.OPACITY_RANGE, _opacityValue: 1, colorRange: _theme.DISCRETE_COLOR_RANGE, colorType: 'category' }; } /** * Get the map of scales from the props. * @param {Object} props Props. * @param {Array} data Array of all data. * @returns {Object} Map of scales. * @private */ }, { key: '_getAllScaleProps', value: function _getAllScaleProps(props, data) { var defaultScaleProps = this._getDefaultScaleProps(props); var userScaleProps = (0, _scalesUtils.extractScalePropsFromProps)(props, ATTRIBUTES); var missingScaleProps = (0, _scalesUtils.getMissingScaleProps)(_extends({}, defaultScaleProps, userScaleProps), data, ATTRIBUTES); return _extends({}, defaultScaleProps, userScaleProps, missingScaleProps, { _allData: [], _adjustBy: [], _adjustWhat: [] }); } /** * Get attribute functor. * @param {string} attr Attribute name. * @returns {*} Functor. * @protected */ }, { key: '_getAttributeFunctor', value: function _getAttributeFunctor(attr) { return (0, _scalesUtils.getAttributeFunctor)(this.state.scaleProps, attr); } /** * Extract the arc function from the props. * @param {Object} scaleProps Scale props. * @returns {function} Arc function, null if radius is missing. * @private */ }, { key: '_getArcFromProps', value: function _getArcFromProps(scaleProps) { var radiusFunctor = (0, _scalesUtils.getAttributeFunctor)(scaleProps, 'radius'); var innerRadiusFunctor = (0, _scalesUtils.getAttributeFunctor)(scaleProps, 'innerRadius'); if (!radiusFunctor) { return null; } return d3Shape.arc().outerRadius(radiusFunctor).innerRadius(innerRadiusFunctor); } }, { key: 'render', value: function render() { var _this2 = this; var _props = this.props; var width = _props.width; var height = _props.height; var animation = _props.animation; if (animation) { return _react2.default.createElement( _animation2.default, _extends({}, this.props, { animatedProps: ANIMATED_PROPS }), _react2.default.createElement(RadialChart, _extends({}, this.props, { animation: null })) ); } var _state = this.state; var data = _state.data; var arc = _state.arc; if (!data || !arc) { return null; } var _getInnerDimensions2 = (0, _chartUtils.getInnerDimensions)(this.props, DEFAULT_MARGINS); var innerWidth = _getInnerDimensions2.innerWidth; var innerHeight = _getInnerDimensions2.innerHeight; var opacityFunctor = this._getAttributeFunctor('opacity'); var fillFunctor = this._getAttributeFunctor('fill') || this._getAttributeFunctor('color'); var strokeFunctor = this._getAttributeFunctor('stroke') || this._getAttributeFunctor('color'); var pie = d3Shape.pie().sort(null).value(function (d) { return d.angle; }); var pieData = pie(data); return _react2.default.createElement( 'div', { style: { width: width + 'px', height: height + 'px' }, className: 'rv-radial-chart' }, _react2.default.createElement( 'svg', { width: width, height: height, className: 'rv-radial-chart__svg' }, _react2.default.createElement( 'g', { className: 'rv-radial-chart__series--pie', transform: 'translate(' + innerWidth / 2 + ',' + innerHeight / 2 + ')', ref: 'container' }, data.map(function (d, i) { return _react2.default.createElement('path', { d: arc(pieData[i]), style: { opacity: opacityFunctor && opacityFunctor(d), stroke: strokeFunctor && strokeFunctor(d), fill: fillFunctor && fillFunctor(d) }, onMouseOver: function onMouseOver(e) { return _this2._sectionMouseOver(pieData[i], e); }, onMouseOut: function onMouseOut(e) { return _this2._sectionMouseOut(pieData[i], e); }, onClick: function onClick(e) { return _this2._sectionClick(pieData[i], e); }, key: i }); }) ) ) ); } }]); return RadialChart; }(_react2.default.Component); RadialChart.displayName = 'RadialChart'; exports.default = RadialChart;