UNPKG

recharts

Version:
549 lines 24.7 kB
var _Pie; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _extends() { _extends = Object.assign ? Object.assign.bind() : 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; }; return _extends.apply(this, arguments); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /** * @fileOverview Render sectors of a pie */ import React, { PureComponent } from 'react'; import Animate from 'react-smooth'; import get from 'lodash/get'; import isEqual from 'lodash/isEqual'; import isNil from 'lodash/isNil'; import isFunction from 'lodash/isFunction'; import clsx from 'clsx'; import { Layer } from '../container/Layer'; import { Curve } from '../shape/Curve'; import { Text } from '../component/Text'; import { Label } from '../component/Label'; import { LabelList } from '../component/LabelList'; import { Cell } from '../component/Cell'; import { findAllByType, filterProps } from '../util/ReactUtils'; import { Global } from '../util/Global'; import { polarToCartesian, getMaxRadius } from '../util/PolarUtils'; import { isNumber, getPercentValue, mathSign, interpolateNumber, uniqueId } from '../util/DataUtils'; import { getValueByDataKey } from '../util/ChartUtils'; import { warn } from '../util/LogUtils'; import { adaptEventsOfChild } from '../util/types'; import { Shape } from '../util/ActiveShapeUtils'; export var Pie = /*#__PURE__*/function (_PureComponent) { _inherits(Pie, _PureComponent); function Pie(props) { var _this; _classCallCheck(this, Pie); _this = _callSuper(this, Pie, [props]); _defineProperty(_assertThisInitialized(_this), "pieRef", null); _defineProperty(_assertThisInitialized(_this), "sectorRefs", []); _defineProperty(_assertThisInitialized(_this), "id", uniqueId('recharts-pie-')); _defineProperty(_assertThisInitialized(_this), "handleAnimationEnd", function () { var onAnimationEnd = _this.props.onAnimationEnd; _this.setState({ isAnimationFinished: true }); if (isFunction(onAnimationEnd)) { onAnimationEnd(); } }); _defineProperty(_assertThisInitialized(_this), "handleAnimationStart", function () { var onAnimationStart = _this.props.onAnimationStart; _this.setState({ isAnimationFinished: false }); if (isFunction(onAnimationStart)) { onAnimationStart(); } }); _this.state = { isAnimationFinished: !props.isAnimationActive, prevIsAnimationActive: props.isAnimationActive, prevAnimationId: props.animationId, sectorToFocus: 0 }; return _this; } _createClass(Pie, [{ key: "isActiveIndex", value: function isActiveIndex(i) { var activeIndex = this.props.activeIndex; if (Array.isArray(activeIndex)) { return activeIndex.indexOf(i) !== -1; } return i === activeIndex; } }, { key: "hasActiveIndex", value: function hasActiveIndex() { var activeIndex = this.props.activeIndex; return Array.isArray(activeIndex) ? activeIndex.length !== 0 : activeIndex || activeIndex === 0; } }, { key: "renderLabels", value: function renderLabels(sectors) { var isAnimationActive = this.props.isAnimationActive; if (isAnimationActive && !this.state.isAnimationFinished) { return null; } var _this$props = this.props, label = _this$props.label, labelLine = _this$props.labelLine, dataKey = _this$props.dataKey, valueKey = _this$props.valueKey; var pieProps = filterProps(this.props, false); var customLabelProps = filterProps(label, false); var customLabelLineProps = filterProps(labelLine, false); var offsetRadius = label && label.offsetRadius || 20; var labels = sectors.map(function (entry, i) { var midAngle = (entry.startAngle + entry.endAngle) / 2; var endPoint = polarToCartesian(entry.cx, entry.cy, entry.outerRadius + offsetRadius, midAngle); var labelProps = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, pieProps), entry), {}, { stroke: 'none' }, customLabelProps), {}, { index: i, textAnchor: Pie.getTextAnchor(endPoint.x, entry.cx) }, endPoint); var lineProps = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, pieProps), entry), {}, { fill: 'none', stroke: entry.fill }, customLabelLineProps), {}, { index: i, points: [polarToCartesian(entry.cx, entry.cy, entry.outerRadius, midAngle), endPoint], key: 'line' }); var realDataKey = dataKey; // TODO: compatible to lower versions if (isNil(dataKey) && isNil(valueKey)) { realDataKey = 'value'; } else if (isNil(dataKey)) { realDataKey = valueKey; } return /*#__PURE__*/React.createElement(Layer, { key: "label-".concat(entry.startAngle, "-").concat(entry.endAngle) }, labelLine && Pie.renderLabelLineItem(labelLine, lineProps), Pie.renderLabelItem(label, labelProps, getValueByDataKey(entry, realDataKey))); }); return /*#__PURE__*/React.createElement(Layer, { className: "recharts-pie-labels" }, labels); } }, { key: "renderSectorsStatically", value: function renderSectorsStatically(sectors) { var _this2 = this; var _this$props2 = this.props, activeShape = _this$props2.activeShape, blendStroke = _this$props2.blendStroke, inactiveShapeProp = _this$props2.inactiveShape; return sectors.map(function (entry, i) { if ((entry === null || entry === void 0 ? void 0 : entry.startAngle) === 0 && (entry === null || entry === void 0 ? void 0 : entry.endAngle) === 0 && sectors.length !== 1) return null; var isActive = _this2.isActiveIndex(i); var inactiveShape = inactiveShapeProp && _this2.hasActiveIndex() ? inactiveShapeProp : null; var sectorOptions = isActive ? activeShape : inactiveShape; var sectorProps = _objectSpread(_objectSpread({}, entry), {}, { stroke: blendStroke ? entry.fill : entry.stroke, tabIndex: -1 }); return /*#__PURE__*/React.createElement(Layer, _extends({ ref: function ref(_ref) { if (_ref && !_this2.sectorRefs.includes(_ref)) { _this2.sectorRefs.push(_ref); } }, tabIndex: -1, className: "recharts-pie-sector" }, adaptEventsOfChild(_this2.props, entry, i), { // eslint-disable-next-line react/no-array-index-key key: "sector-".concat(entry === null || entry === void 0 ? void 0 : entry.startAngle, "-").concat(entry === null || entry === void 0 ? void 0 : entry.endAngle, "-").concat(entry.midAngle, "-").concat(i) }), /*#__PURE__*/React.createElement(Shape, _extends({ option: sectorOptions, isActive: isActive, shapeType: "sector" }, sectorProps))); }); } }, { key: "renderSectorsWithAnimation", value: function renderSectorsWithAnimation() { var _this3 = this; var _this$props3 = this.props, sectors = _this$props3.sectors, isAnimationActive = _this$props3.isAnimationActive, animationBegin = _this$props3.animationBegin, animationDuration = _this$props3.animationDuration, animationEasing = _this$props3.animationEasing, animationId = _this$props3.animationId; var _this$state = this.state, prevSectors = _this$state.prevSectors, prevIsAnimationActive = _this$state.prevIsAnimationActive; return /*#__PURE__*/React.createElement(Animate, { begin: animationBegin, duration: animationDuration, isActive: isAnimationActive, easing: animationEasing, from: { t: 0 }, to: { t: 1 }, key: "pie-".concat(animationId, "-").concat(prevIsAnimationActive), onAnimationStart: this.handleAnimationStart, onAnimationEnd: this.handleAnimationEnd }, function (_ref2) { var t = _ref2.t; var stepData = []; var first = sectors && sectors[0]; var curAngle = first.startAngle; sectors.forEach(function (entry, index) { var prev = prevSectors && prevSectors[index]; var paddingAngle = index > 0 ? get(entry, 'paddingAngle', 0) : 0; if (prev) { var angleIp = interpolateNumber(prev.endAngle - prev.startAngle, entry.endAngle - entry.startAngle); var latest = _objectSpread(_objectSpread({}, entry), {}, { startAngle: curAngle + paddingAngle, endAngle: curAngle + angleIp(t) + paddingAngle }); stepData.push(latest); curAngle = latest.endAngle; } else { var endAngle = entry.endAngle, startAngle = entry.startAngle; var interpolatorAngle = interpolateNumber(0, endAngle - startAngle); var deltaAngle = interpolatorAngle(t); var _latest = _objectSpread(_objectSpread({}, entry), {}, { startAngle: curAngle + paddingAngle, endAngle: curAngle + deltaAngle + paddingAngle }); stepData.push(_latest); curAngle = _latest.endAngle; } }); return /*#__PURE__*/React.createElement(Layer, null, _this3.renderSectorsStatically(stepData)); }); } }, { key: "attachKeyboardHandlers", value: function attachKeyboardHandlers(pieRef) { var _this4 = this; // eslint-disable-next-line no-param-reassign pieRef.onkeydown = function (e) { if (!e.altKey) { switch (e.key) { case 'ArrowLeft': { var next = ++_this4.state.sectorToFocus % _this4.sectorRefs.length; _this4.sectorRefs[next].focus(); _this4.setState({ sectorToFocus: next }); break; } case 'ArrowRight': { var _next = --_this4.state.sectorToFocus < 0 ? _this4.sectorRefs.length - 1 : _this4.state.sectorToFocus % _this4.sectorRefs.length; _this4.sectorRefs[_next].focus(); _this4.setState({ sectorToFocus: _next }); break; } case 'Escape': { _this4.sectorRefs[_this4.state.sectorToFocus].blur(); _this4.setState({ sectorToFocus: 0 }); break; } default: { // There is nothing to do here } } } }; } }, { key: "renderSectors", value: function renderSectors() { var _this$props4 = this.props, sectors = _this$props4.sectors, isAnimationActive = _this$props4.isAnimationActive; var prevSectors = this.state.prevSectors; if (isAnimationActive && sectors && sectors.length && (!prevSectors || !isEqual(prevSectors, sectors))) { return this.renderSectorsWithAnimation(); } return this.renderSectorsStatically(sectors); } }, { key: "componentDidMount", value: function componentDidMount() { if (this.pieRef) { this.attachKeyboardHandlers(this.pieRef); } } }, { key: "render", value: function render() { var _this5 = this; var _this$props5 = this.props, hide = _this$props5.hide, sectors = _this$props5.sectors, className = _this$props5.className, label = _this$props5.label, cx = _this$props5.cx, cy = _this$props5.cy, innerRadius = _this$props5.innerRadius, outerRadius = _this$props5.outerRadius, isAnimationActive = _this$props5.isAnimationActive; var isAnimationFinished = this.state.isAnimationFinished; if (hide || !sectors || !sectors.length || !isNumber(cx) || !isNumber(cy) || !isNumber(innerRadius) || !isNumber(outerRadius)) { return null; } var layerClass = clsx('recharts-pie', className); return /*#__PURE__*/React.createElement(Layer, { tabIndex: this.props.rootTabIndex, className: layerClass, ref: function ref(_ref3) { _this5.pieRef = _ref3; } }, this.renderSectors(), label && this.renderLabels(sectors), Label.renderCallByParent(this.props, null, false), (!isAnimationActive || isAnimationFinished) && LabelList.renderCallByParent(this.props, sectors, false)); } }], [{ key: "getDerivedStateFromProps", value: function getDerivedStateFromProps(nextProps, prevState) { if (prevState.prevIsAnimationActive !== nextProps.isAnimationActive) { return { prevIsAnimationActive: nextProps.isAnimationActive, prevAnimationId: nextProps.animationId, curSectors: nextProps.sectors, prevSectors: [], isAnimationFinished: true }; } if (nextProps.isAnimationActive && nextProps.animationId !== prevState.prevAnimationId) { return { prevAnimationId: nextProps.animationId, curSectors: nextProps.sectors, prevSectors: prevState.curSectors, isAnimationFinished: true }; } if (nextProps.sectors !== prevState.curSectors) { return { curSectors: nextProps.sectors, isAnimationFinished: true }; } return null; } }, { key: "getTextAnchor", value: function getTextAnchor(x, cx) { if (x > cx) { return 'start'; } if (x < cx) { return 'end'; } return 'middle'; } }, { key: "renderLabelLineItem", value: function renderLabelLineItem(option, props) { if ( /*#__PURE__*/React.isValidElement(option)) { return /*#__PURE__*/React.cloneElement(option, props); } if (isFunction(option)) { return option(props); } return /*#__PURE__*/React.createElement(Curve, _extends({}, props, { type: "linear", className: "recharts-pie-label-line" })); } }, { key: "renderLabelItem", value: function renderLabelItem(option, props, value) { if ( /*#__PURE__*/React.isValidElement(option)) { return /*#__PURE__*/React.cloneElement(option, props); } var label = value; if (isFunction(option)) { label = option(props); if ( /*#__PURE__*/React.isValidElement(label)) { return label; } } return /*#__PURE__*/React.createElement(Text, _extends({}, props, { alignmentBaseline: "middle", className: "recharts-pie-label-text" }), label); } }]); return Pie; }(PureComponent); _Pie = Pie; _defineProperty(Pie, "displayName", 'Pie'); _defineProperty(Pie, "defaultProps", { stroke: '#fff', fill: '#808080', legendType: 'rect', cx: '50%', cy: '50%', startAngle: 0, endAngle: 360, innerRadius: 0, outerRadius: '80%', paddingAngle: 0, labelLine: true, hide: false, minAngle: 0, isAnimationActive: !Global.isSsr, animationBegin: 400, animationDuration: 1500, animationEasing: 'ease', nameKey: 'name', blendStroke: false, rootTabIndex: 0 }); _defineProperty(Pie, "parseDeltaAngle", function (startAngle, endAngle) { var sign = mathSign(endAngle - startAngle); var deltaAngle = Math.min(Math.abs(endAngle - startAngle), 360); return sign * deltaAngle; }); _defineProperty(Pie, "getRealPieData", function (item) { var _item$props = item.props, data = _item$props.data, children = _item$props.children; var presentationProps = filterProps(item.props, false); var cells = findAllByType(children, Cell); if (data && data.length) { return data.map(function (entry, index) { return _objectSpread(_objectSpread(_objectSpread({ payload: entry }, presentationProps), entry), cells && cells[index] && cells[index].props); }); } if (cells && cells.length) { return cells.map(function (cell) { return _objectSpread(_objectSpread({}, presentationProps), cell.props); }); } return []; }); _defineProperty(Pie, "parseCoordinateOfPie", function (item, offset) { var top = offset.top, left = offset.left, width = offset.width, height = offset.height; var maxPieRadius = getMaxRadius(width, height); var cx = left + getPercentValue(item.props.cx, width, width / 2); var cy = top + getPercentValue(item.props.cy, height, height / 2); var innerRadius = getPercentValue(item.props.innerRadius, maxPieRadius, 0); var outerRadius = getPercentValue(item.props.outerRadius, maxPieRadius, maxPieRadius * 0.8); var maxRadius = item.props.maxRadius || Math.sqrt(width * width + height * height) / 2; return { cx: cx, cy: cy, innerRadius: innerRadius, outerRadius: outerRadius, maxRadius: maxRadius }; }); _defineProperty(Pie, "getComposedData", function (_ref4) { var item = _ref4.item, offset = _ref4.offset; var pieData = _Pie.getRealPieData(item); if (!pieData || !pieData.length) { return null; } var _item$props2 = item.props, cornerRadius = _item$props2.cornerRadius, startAngle = _item$props2.startAngle, endAngle = _item$props2.endAngle, paddingAngle = _item$props2.paddingAngle, dataKey = _item$props2.dataKey, nameKey = _item$props2.nameKey, valueKey = _item$props2.valueKey, tooltipType = _item$props2.tooltipType; var minAngle = Math.abs(item.props.minAngle); var coordinate = _Pie.parseCoordinateOfPie(item, offset); var deltaAngle = _Pie.parseDeltaAngle(startAngle, endAngle); var absDeltaAngle = Math.abs(deltaAngle); var realDataKey = dataKey; if (isNil(dataKey) && isNil(valueKey)) { warn(false, "Use \"dataKey\" to specify the value of pie,\n the props \"valueKey\" will be deprecated in 1.1.0"); realDataKey = 'value'; } else if (isNil(dataKey)) { warn(false, "Use \"dataKey\" to specify the value of pie,\n the props \"valueKey\" will be deprecated in 1.1.0"); realDataKey = valueKey; } var notZeroItemCount = pieData.filter(function (entry) { return getValueByDataKey(entry, realDataKey, 0) !== 0; }).length; var totalPadingAngle = (absDeltaAngle >= 360 ? notZeroItemCount : notZeroItemCount - 1) * paddingAngle; var realTotalAngle = absDeltaAngle - notZeroItemCount * minAngle - totalPadingAngle; var sum = pieData.reduce(function (result, entry) { var val = getValueByDataKey(entry, realDataKey, 0); return result + (isNumber(val) ? val : 0); }, 0); var sectors; if (sum > 0) { var prev; sectors = pieData.map(function (entry, i) { var val = getValueByDataKey(entry, realDataKey, 0); var name = getValueByDataKey(entry, nameKey, i); var percent = (isNumber(val) ? val : 0) / sum; var tempStartAngle; if (i) { tempStartAngle = prev.endAngle + mathSign(deltaAngle) * paddingAngle * (val !== 0 ? 1 : 0); } else { tempStartAngle = startAngle; } var tempEndAngle = tempStartAngle + mathSign(deltaAngle) * ((val !== 0 ? minAngle : 0) + percent * realTotalAngle); var midAngle = (tempStartAngle + tempEndAngle) / 2; var middleRadius = (coordinate.innerRadius + coordinate.outerRadius) / 2; var tooltipPayload = [{ name: name, value: val, payload: entry, dataKey: realDataKey, type: tooltipType }]; var tooltipPosition = polarToCartesian(coordinate.cx, coordinate.cy, middleRadius, midAngle); prev = _objectSpread(_objectSpread(_objectSpread({ percent: percent, cornerRadius: cornerRadius, name: name, tooltipPayload: tooltipPayload, midAngle: midAngle, middleRadius: middleRadius, tooltipPosition: tooltipPosition }, entry), coordinate), {}, { value: getValueByDataKey(entry, realDataKey), startAngle: tempStartAngle, endAngle: tempEndAngle, payload: entry, paddingAngle: mathSign(deltaAngle) * paddingAngle }); return prev; }); } return _objectSpread(_objectSpread({}, coordinate), {}, { sectors: sectors, data: pieData }); });