UNPKG

recharts

Version:
434 lines (346 loc) 15.9 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, _temp; /** * @fileOverview Radar Chart */ Object.defineProperty(exports, "__esModule", { value: true }); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _d3Scale = require('d3-scale'); var _d3Scale2 = _interopRequireDefault(_d3Scale); var _rechartsScale = require('recharts-scale'); var _Surface = require('../container/Surface'); var _Surface2 = _interopRequireDefault(_Surface); var _Layer = require('../container/Layer'); var _Layer2 = _interopRequireDefault(_Layer); var _Legend = require('../component/Legend'); var _Legend2 = _interopRequireDefault(_Legend); var _Radar = require('../polar/Radar'); var _Radar2 = _interopRequireDefault(_Radar); var _PolarGrid = require('../polar/PolarGrid'); var _PolarGrid2 = _interopRequireDefault(_PolarGrid); var _PolarAngleAxis = require('../polar/PolarAngleAxis'); var _PolarAngleAxis2 = _interopRequireDefault(_PolarAngleAxis); var _PolarRadiusAxis = require('../polar/PolarRadiusAxis'); var _PolarRadiusAxis2 = _interopRequireDefault(_PolarRadiusAxis); var _ReactUtils = require('../util/ReactUtils'); var _ReactUtils2 = _interopRequireDefault(_ReactUtils); var _LodashUtils = require('../util/LodashUtils'); var _LodashUtils2 = _interopRequireDefault(_LodashUtils); 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 RadarChart = (_temp = _class = function (_Component) { _inherits(RadarChart, _Component); function RadarChart() { _classCallCheck(this, RadarChart); return _possibleConstructorReturn(this, Object.getPrototypeOf(RadarChart).apply(this, arguments)); } _createClass(RadarChart, [{ key: 'getRadiusAxisCfg', value: function getRadiusAxisCfg(radiusAxis, innerRadius, outerRadius) { var children = this.props.children; var domain = undefined; var tickCount = undefined; var ticks = undefined; if (radiusAxis && radiusAxis.props.domain) { tickCount = Math.max(radiusAxis.props.tickCount || _PolarRadiusAxis2.default.defaultProps.tickCount, 2); domain = radiusAxis.props.domain; (0, _invariant2.default)(domain.length === 2 && domain[0] === +domain[0] && domain[1] === +domain[1], 'domain in PolarRadiusAxis should be an array which has two numbers'); } else if (radiusAxis && radiusAxis.props.ticks) { ticks = radiusAxis.props.ticks; tickCount = ticks.length; domain = [Math.min.apply(null, ticks), Math.max.apply(null, ticks)]; } else { tickCount = Math.max(radiusAxis && radiusAxis.props.tickCount || _PolarRadiusAxis2.default.defaultProps.tickCount, 2); ticks = this.getTicksByItems(radiusAxis, tickCount); domain = [Math.min.apply(null, ticks), Math.max.apply(null, ticks)]; } return { tickCount: tickCount, ticks: ticks, scale: _d3Scale2.default.linear().domain(domain).range([innerRadius, outerRadius]) }; } }, { key: 'getTicksByItems', value: function getTicksByItems(axisItem, tickCount) { var _props = this.props; var data = _props.data; var children = _props.children; var radarItems = _ReactUtils2.default.findAllByType(children, _Radar2.default); var dataKeys = radarItems.map(function (item) { return item.props.dataKey; }); var max = data.reduce(function (prev, current) { var currentMax = Math.max.apply(null, dataKeys.map(function (v) { return current[v] || 0; })); return Math.max(prev, currentMax); }, 0); var tickValues = (0, _rechartsScale.getNiceTickValues)([0, max], tickCount); return tickValues; } }, { key: 'getGridRadius', value: function getGridRadius(gridCount, innerRadius, outerRadius) { var domain = _LodashUtils2.default.range(0, gridCount); var scale = _d3Scale2.default.point().domain(domain).range([innerRadius, outerRadius]); return domain.map(function (v) { return scale(v); }); } }, { key: 'getAngle', value: function getAngle(index, dataLength, startAngle, clockWise) { var sign = clockWise ? -1 : 1; var angleInterval = 360 / dataLength; return startAngle + index * sign * angleInterval; } }, { key: 'getAngleTicks', value: function getAngleTicks(dataLength, startAngle, clockWise) { var angles = []; for (var i = 0; i < dataLength; i++) { angles.push(this.getAngle(i, dataLength, startAngle, clockWise)); } return angles; } }, { key: 'getRadiusTicks', value: function getRadiusTicks(axisCfg) { var ticks = axisCfg.ticks; var scale = axisCfg.scale; if (ticks && ticks.length) { return ticks.map(function (entry) { return { radius: scale(entry), value: entry }; }); } var tickCount = axisCfg.tickCount; var domain = scale.domain(); return _LodashUtils2.default.range(0, tickCount).map(function (v, i) { var value = domain[0] + i * (domain[1] - domain[0]) / (tickCount - 1); return { value: value, radius: scale(value) }; }); } }, { key: 'getComposedData', value: function getComposedData(item, scale, cx, cy, innerRadius, outerRadius) { var _this2 = this; var dataKey = item.props.dataKey; var _props2 = this.props; var data = _props2.data; var startAngle = _props2.startAngle; var clockWise = _props2.clockWise; var len = data.length; return data.map(function (entry, i) { var value = entry[dataKey] || 0; var angle = _this2.getAngle(i, len, startAngle, clockWise); var radius = scale(value); return _extends({}, (0, _PolarUtils.polarToCartesian)(cx, cy, radius, angle), { value: value, cx: cx, cy: cy, radius: radius, angle: angle, payload: entry }); }); } }, { key: 'renderRadars', value: function renderRadars(items, scale, cx, cy, innerRadius, outerRadius) { var _this3 = this; if (!items || !items.length) { return null; } var baseProps = _ReactUtils2.default.getPresentationAttributes(this.props); return items.map(function (el, index) { return _react2.default.cloneElement(el, _extends({}, baseProps, _ReactUtils2.default.getPresentationAttributes(el), { points: _this3.getComposedData(el, scale, cx, cy, innerRadius, outerRadius), key: 'radar-' + index })); }); } }, { key: 'renderGrid', value: function renderGrid(radiusAxisCfg, cx, cy, innerRadius, outerRadius) { var children = this.props.children; var grid = _ReactUtils2.default.findChildByType(children, _PolarGrid2.default); if (!grid) { return null; } var _props3 = this.props; var startAngle = _props3.startAngle; var clockWise = _props3.clockWise; var data = _props3.data; var len = data.length; var gridCount = radiusAxisCfg.tickCount; return _react2.default.cloneElement(grid, { polarAngles: this.getAngleTicks(len, startAngle, clockWise), polarRadius: this.getGridRadius(gridCount, innerRadius, outerRadius), cx: cx, cy: cy, innerRadius: innerRadius, outerRadius: outerRadius, key: 'layer-grid' }); } }, { key: 'renderAngleAxis', value: function renderAngleAxis(cx, cy, outerRadius, maxRadius) { var _this4 = this; var children = this.props.children; var angleAxis = _ReactUtils2.default.findChildByType(children, _PolarAngleAxis2.default); if (!angleAxis || angleAxis.props.hide) { return null; } var _props4 = this.props; var data = _props4.data; var width = _props4.width; var height = _props4.height; var startAngle = _props4.startAngle; var clockWise = _props4.clockWise; var len = data.length; var grid = _ReactUtils2.default.findChildByType(children, _PolarGrid2.default); var radius = _LodashUtils2.default.getPercentValue(angleAxis.props.radius, maxRadius, outerRadius); var dataKey = angleAxis.props.dataKey; return _react2.default.cloneElement(angleAxis, { ticks: data.map(function (v, i) { return { value: dataKey ? v[dataKey] : i, angle: _this4.getAngle(i, len, startAngle, clockWise) }; }), cx: cx, cy: cy, radius: radius, axisLineType: grid && grid.props && grid.props.gridType || _PolarGrid2.default.defaultProps.gridType, key: 'layer-angle-axis' }); } }, { key: 'renderRadiusAxis', value: function renderRadiusAxis(radiusAxis, radiusAxisCfg, cx, cy) { if (!radiusAxis || radiusAxis.props.hide) { return null; } var startAngle = this.props.startAngle; return _react2.default.cloneElement(radiusAxis, { angle: radiusAxis.props.angle || startAngle, ticks: this.getRadiusTicks(radiusAxisCfg), cx: cx, cy: cy }); } /** * Draw legend * @param {Array} items The instances of item * @return {ReactElement} The instance of Legend */ }, { key: 'renderLegend', value: function renderLegend(items) { var children = this.props.children; var legendItem = _ReactUtils2.default.findChildByType(children, _Legend2.default); if (!legendItem) { return null; } var _props5 = this.props; var width = _props5.width; var height = _props5.height; var legendData = items.map(function (child) { var _child$props = child.props; var dataKey = _child$props.dataKey; var name = _child$props.name; var legendType = _child$props.legendType; return { type: legendType || 'square', color: child.props.stroke || child.props.fill, value: name || dataKey }; }, this); return _react2.default.cloneElement(legendItem, _extends({}, _Legend2.default.getWithHeight(legendItem, width, height), { payload: legendData })); } }, { key: 'render', value: function render() { if (!_ReactUtils2.default.validateWidthHeight(this)) { return null; } var _props6 = this.props; var className = _props6.className; var data = _props6.data; var width = _props6.width; var height = _props6.height; var margin = _props6.margin; var children = _props6.children; var style = _props6.style; 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); if (outerRadius <= 0 || !data || !data.length) { (0, _invariant2.default)(outerRadius > 0, 'outerRadius should be greater than 0.'); (0, _invariant2.default)(data && data.length, 'data(' + data + ') should not be null, undefined, or an empty array.'); return null; } (0, _invariant2.default)(outerRadius > innerRadius, 'outerRadius(' + this.props.outerRadius + ') should be ' + ('greater than innerRadius(' + this.props.innerRadius + '). ')); var items = _ReactUtils2.default.findAllByType(children, _Radar2.default); var radiusAxis = _ReactUtils2.default.findChildByType(children, _PolarRadiusAxis2.default); var radiusAxisCfg = this.getRadiusAxisCfg(radiusAxis, innerRadius, outerRadius); return _react2.default.createElement( 'div', { className: (0, _classnames2.default)('recharts-wrapper', className), style: _extends({ position: 'relative', cursor: 'default' }, style) }, _react2.default.createElement( _Surface2.default, { width: width, height: height }, this.renderGrid(radiusAxisCfg, cx, cy, innerRadius, outerRadius), this.renderRadiusAxis(radiusAxis, radiusAxisCfg, cx, cy), this.renderAngleAxis(cx, cy, outerRadius, maxRadius), this.renderRadars(items, radiusAxisCfg.scale, cx, cy, innerRadius, outerRadius) ), this.renderLegend(items) ); } }]); return RadarChart; }(_react.Component), _class.displayName = 'RadarChart', _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 }), cx: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), cy: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), startAngle: _react.PropTypes.number, innerRadius: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), outerRadius: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]), clockWise: _react.PropTypes.bool, data: _react.PropTypes.array, style: _react.PropTypes.object, children: _react.PropTypes.oneOfType([_react.PropTypes.arrayOf(_react.PropTypes.node), _react.PropTypes.node]), className: _react.PropTypes.string }, _class.defaultProps = { width: 0, height: 0, startAngle: 90, clockWise: true, data: [], margin: { top: 0, right: 0, bottom: 0, left: 0 } }, _temp); exports.default = RadarChart;