UNPKG

recharts

Version:
383 lines (309 loc) 13.5 kB
'use strict'; 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; }; 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 _class, _temp2; /** * @fileOverview Radar Bar Chart */ Object.defineProperty(exports, "__esModule", { value: true }); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _d3Scale = require('d3-scale'); var _d3Scale2 = _interopRequireDefault(_d3Scale); var _Surface = require('../container/Surface'); var _Surface2 = _interopRequireDefault(_Surface); var _RadialBar = require('../polar/RadialBar'); var _RadialBar2 = _interopRequireDefault(_RadialBar); var _LodashUtils = require('../util/LodashUtils'); var _LodashUtils2 = _interopRequireDefault(_LodashUtils); var _Legend = require('../component/Legend'); var _Legend2 = _interopRequireDefault(_Legend); var _Tooltip = require('../component/Tooltip'); var _Tooltip2 = _interopRequireDefault(_Tooltip); var _ReactUtils = require('../util/ReactUtils'); var _ReactUtils2 = _interopRequireDefault(_ReactUtils); var _PolarUtils = require('../util/PolarUtils'); 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 RadialBarChart = (_temp2 = _class = function (_Component) { _inherits(RadialBarChart, _Component); function RadialBarChart() { var _Object$getPrototypeO; var _temp, _this, _ret; _classCallCheck(this, RadialBarChart); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(RadialBarChart)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = { activeTooltipLabel: '', activeTooltipPosition: 'left-bottom', activeTooltipCoord: { x: 0, y: 0 }, isTooltipActive: false }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(RadialBarChart, [{ key: 'getComposedData', /** * Compose the data of each group * @param {Array} barPosition The offset and size of each bar * @param {Object} radiusScale The scale function of radius of bars * @param {Object} center The coordinate of center * @param {String} dataKey The unique key of a group * @return {Array} Composed data */ value: function getComposedData(barPosition, radiusScale, center, dataKey) { var data = this.props.data; var pos = barPosition[dataKey]; return data.map(function (entry, index) { var value = entry[dataKey]; var radius = radiusScale(index); return _extends({}, entry, center, { value: value, innerRadius: radius - pos.offset, outerRadius: radius - pos.offset + pos.radius }); }); } /** * Calculate the size of all groups * @param {Array} items All the instance of RadialBar * @return {Object} The size of all groups */ }, { key: 'getRadiusList', value: function getRadiusList(items) { var barSize = this.props.barSize; return items.map(function (child) { return _extends({}, child.props, { barSize: child.props.barSize || barSize }); }); } /** * Calculate the scale function of radius * @param {Number} innerRadius The outer radius * @param {Number} outerRadius The inner radius * @return {Object} A scale function */ }, { key: 'getRadiusScale', value: function getRadiusScale(innerRadius, outerRadius) { var data = this.props.data; var bandCount = Math.max(data.length, 1); var range = [outerRadius, innerRadius]; var scale = _d3Scale2.default.band().domain(_LodashUtils2.default.range(0, bandCount)).range(range); return scale; } /** * Calculate the size of each bar and the gap between two bars * @param {Number} bandRadius The radius of each category * @param {Array} radiusList The radius of all groups * @return {Number} The size of each bar and the gap between two bars */ }, { key: 'getBarPosition', value: function getBarPosition(bandRadius, radiusList) { var _props = this.props; var barGap = _props.barGap; var barCategoryGap = _props.barCategoryGap; var len = radiusList.length; var result = undefined; // whether or not is barSize setted by user if (len && radiusList[0].barSize === +radiusList[0].barSize) { (function () { var sum = radiusList.reduce(function (res, entry) { return res + entry.barSize; }, 0); sum += (len - 1) * barGap; var offset = -sum / 2 >> 0; var prev = { offset: offset - barGap, radius: 0 }; result = radiusList.reduce(function (res, entry) { res[entry.dataKey] = { offset: prev.offset + prev.radius + barGap, radius: entry.barSize }; prev = res[entry.dataKey]; return res; }, {}); })(); } else { (function () { var offset = _LodashUtils2.default.getPercentValue(barCategoryGap, bandRadius); var radius = (bandRadius - 2 * offset - (len - 1) * barGap) / len >> 0; offset = -Math.max((radius * len + (len - 1) * barGap) / 2 >> 0, 0); result = radiusList.reduce(function (res, entry, i) { res[entry.dataKey] = { offset: offset + (radius + barGap) * i, radius: radius }; return res; }, {}); })(); } return result; } }, { key: 'handleMouseEnter', value: function handleMouseEnter(el, e) { var _this2 = this; this.setState({ isTooltipActive: true }, function () { if (_this2.props.onMouseEnter) { _this2.props.onMouseEnter(el, e); } }); } }, { key: 'handleMouseLeave', value: function handleMouseLeave(e) { var _this3 = this; this.setState({ isTooltipActive: false }, function () { if (_this3.props.onMouseEnter) { _this3.props.onMouseLeave(e); } }); } /** * Draw legend * @param {ReactElement} legendItem The instance of Legend * @return {ReactElement} The instance of Legend */ }, { key: 'renderLegend', value: function renderLegend() { var children = this.props.children; var legendItem = _ReactUtils2.default.findChildByType(children, _Legend2.default); if (!legendItem) { return null; } var _props2 = this.props; var data = _props2.data; var width = _props2.width; var height = _props2.height; var legendData = data.map(function (entry) { return { type: 'square', color: entry.fill || '#000', value: entry.name }; }); return _react2.default.cloneElement(legendItem, _extends({}, _Legend2.default.getWithHeight(legendItem, width, height), { payload: legendData })); } }, { key: 'renderTooltip', value: function renderTooltip() { var children = this.props.children; var tooltipItem = _ReactUtils2.default.findChildByType(children, _Tooltip2.default); if (!tooltipItem) { return; } } /** * Draw the main part of bar chart * @param {Array} items All the instance of RadialBar * @param {Object} radiusScale The scale function of radius of bars * @param {Object} center The coordinate of center * @return {ReactComponent} All the instances of RadialBar */ }, { key: 'renderItems', value: function renderItems(items, radiusScale, center) { var _this4 = this; if (!items || !items.length) { return null; } var radiusList = this.getRadiusList(items); var bandRadius = radiusScale.bandwidth(); var barPosition = this.getBarPosition(bandRadius, radiusList); return items.map(function (child, i) { var dataKey = child.props.dataKey; return _react2.default.cloneElement(child, _extends({}, center, { key: 'radial-bar-' + i, onMouseLeave: _this4.handleMouseLeave.bind(_this4), onMouseEnter: _this4.handleMouseEnter.bind(_this4, dataKey), data: _this4.getComposedData(barPosition, radiusScale, center, dataKey) })); }, this); } }, { key: 'render', value: function render() { if (!_ReactUtils2.default.validateWidthHeight(this)) { return null; } var _props3 = this.props; var style = _props3.style; var children = _props3.children; var className = _props3.className; var width = _props3.width; var height = _props3.height; var margin = _props3.margin; var items = _ReactUtils2.default.findAllByType(children, _RadialBar2.default); var cx = _LodashUtils2.default.getPercentValue(this.props.cx, width, width / 2); var cy = _LodashUtils2.default.getPercentValue(this.props.cy, height, height / 2); var maxRadius = (0, _PolarUtils.getMaxRadius)(width, height, cx, cy, margin); var innerRadius = _LodashUtils2.default.getPercentValue(this.props.innerRadius, maxRadius, 0); var outerRadius = _LodashUtils2.default.getPercentValue(this.props.outerRadius, maxRadius, maxRadius * 0.8); var radiusScale = this.getRadiusScale(innerRadius, outerRadius); return _react2.default.createElement( 'div', { className: (0, _classnames2.default)('recharts-wrapper', className), style: _extends({ cursor: 'default' }, style, { position: 'relative' }) }, _react2.default.createElement( _Surface2.default, { width: width, height: height }, this.renderItems(items, radiusScale, { cx: cx, cy: cy }) ), this.renderLegend(), this.renderTooltip(items) ); } }]); return RadialBarChart; }(_react.Component), _class.displayName = 'RadialBarChart', _class.propTypes = { width: _react.PropTypes.number, height: _react.PropTypes.number, margin: _react.PropTypes.shape({ top: _react.PropTypes.number, right: _react.PropTypes.number, bottom: _react.PropTypes.number, left: _react.PropTypes.number }), cy: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), cx: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), data: _react.PropTypes.array, innerRadius: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), outerRadius: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), // The offset radius between two categorys barCategoryGap: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), // The gap radius of two radial bar in one category barGap: _react.PropTypes.number, // The radius of each radial bar barSize: _react.PropTypes.number, title: _react.PropTypes.string, style: _react.PropTypes.object, onMouseEnter: _react.PropTypes.func, onMouseLeave: _react.PropTypes.func, onClick: _react.PropTypes.func, children: _react.PropTypes.oneOfType([_react.PropTypes.arrayOf(_react.PropTypes.node), _react.PropTypes.node]), className: _react.PropTypes.string }, _class.defaultProps = { innerRadius: '30%', outerRadius: '100%', barGap: 2, barCategoryGap: '10%', style: {}, margin: { top: 0, right: 0, bottom: 0, left: 0 } }, _temp2); exports.default = RadialBarChart;