UNPKG

recharts

Version:
168 lines (143 loc) 4.51 kB
/** * @fileOverview Pie Chart */ import React, { Component, PropTypes } from 'react'; import classNames from 'classnames'; import Surface from '../container/Surface'; import Legend from '../component/Legend'; import Tooltip from '../component/Tooltip'; import Pie from '../polar/Pie'; import ReactUtils from '../util/ReactUtils'; import LodashUtils from '../util/LodashUtils'; import { getMaxRadius } from '../util/PolarUtils'; class PieChart extends Component { static displayName = 'PieChart'; static propTypes = { width: PropTypes.number, height: PropTypes.number, margin: PropTypes.shape({ top: PropTypes.number, right: PropTypes.number, bottom: PropTypes.number, left: PropTypes.number, }), title: PropTypes.string, style: PropTypes.object, children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.node), PropTypes.node, ]), className: PropTypes.string, onMouseEnter: PropTypes.func, onMouseLeave: PropTypes.func, onClick: PropTypes.func, }; static defaultProps = { style: {}, margin: { top: 0, right: 0, bottom: 0, left: 0 }, }; state = { activeTooltipLabel: '', activeTooltipPosition: 'left-bottom', activeTooltipCoord: { x: 0, y: 0 }, isTooltipActive: false, }; getComposedData(item) { const { fill, stroke, strokeWidth, strokeDasharray, data } = item.props; return data.map((entry) => { return { fill, stroke, strokeWidth, strokeDasharray, ...entry, }; }); } handleMouseEnter(el, e) { this.setState({ isTooltipActive: true, }, () => { if (this.props.onMouseEnter) { this.props.onMouseEnter(el, e); } }); } handleMouseLeave(e) { this.setState({ isTooltipActive: false, }, () => { if (this.props.onMouseEnter) { this.props.onMouseLeave(e); } }); } /** * Draw legend * @param {Array} items The instances of Pie * @return {ReactElement} The instance of Legend */ renderLegend(items) { const { children } = this.props; const legendItem = ReactUtils.findChildByType(children, Legend); if (!legendItem) {return null;} const { width, height } = this.props; const legendData = items.reduce((result, child) => { const { nameKey } = child.props; const data = this.getComposedData(child); return result.concat(data.map((entry) => { const { name, value, ...rest } = entry; return { value: entry[nameKey], color: entry.fill, ...rest }; })); }, []); return React.cloneElement(legendItem, { ...Legend.getWithHeight(legendItem, width, height), payload: legendData, }); } renderTooltip() { const { children } = this.props; const tooltipItem = ReactUtils.findChildByType(children, Tooltip); if (!tooltipItem) { return; } } /** * Draw the main part of bar chart * @param {Array} items All the instance of Pie * @return {ReactComponent} All the instance of Pie */ renderItems(items) { const { width, height, margin } = this.props; return items.map((child, i) => { const { innerRadius, outerRadius, data } = child.props; const cx = LodashUtils.getPercentValue(child.props.cx, width, width / 2); const cy = LodashUtils.getPercentValue(child.props.cy, height, height / 2); const maxRadius = getMaxRadius(width, height, cx, cy, margin); return React.cloneElement(child, { key: 'recharts-pie-' + i, cx, cy, innerRadius: LodashUtils.getPercentValue(innerRadius, maxRadius, 0), outerRadius: LodashUtils.getPercentValue(outerRadius, maxRadius, maxRadius * 0.8), data: this.getComposedData(child), onMouseEnter: ::this.handleMouseEnter, onMouseLeave: ::this.handleMouseLeave, }); }); } render() { if (!ReactUtils.validateWidthHeight(this)) {return null;} const { style, children, className, width, height } = this.props; const items = ReactUtils.findAllByType(children, Pie); return ( <div className={classNames('recharts-wrapper', className)} style={{ position: 'relative', cursor: 'default', ...style }} > <Surface width={width} height={height}> {this.renderItems(items)} </Surface> {this.renderLegend(items)} {this.renderTooltip(items)} </div> ); } } export default PieChart;