import { Chart, Coord, Geom, Tooltip } from 'bizcharts'; import React, { Component } from 'react'; import { DataView } from '@antv/data-set'; import Debounce from 'lodash.debounce'; import { Divider } from 'antd'; import ReactFitText from 'react-fittext'; import classNames from 'classnames'; import autoHeight from '../autoHeight'; import styles from './index.less'; export interface PieProps { animate?: boolean; color?: string; colors?: string[]; selected?: boolean; height?: number; margin?: [number, number, number, number]; hasLegend?: boolean; padding?: [number, number, number, number]; percent?: number; data?: { x: string | string; y: number; }[]; inner?: number; lineWidth?: number; forceFit?: boolean; style?: React.CSSProperties; className?: string; total?: React.ReactNode | number | (() => React.ReactNode | number); title?: React.ReactNode; tooltip?: boolean; valueFormat?: (value: string) => string | React.ReactNode; subTitle?: React.ReactNode; } interface PieState { legendData: { checked: boolean; x: string; color: string; percent: number; y: string }[]; legendBlock: boolean; } class Pie extends Component { state: PieState = { legendData: [], legendBlock: false, }; // for window resize auto responsive legend resize = Debounce(() => { const { hasLegend } = this.props; const { legendBlock } = this.state; if (!hasLegend || !this.root) { window.removeEventListener('resize', this.resize); return; } if ( this.root && this.root.parentNode && (this.root.parentNode as HTMLElement).clientWidth <= 380 ) { if (!legendBlock) { this.setState({ legendBlock: true, }); } } else if (legendBlock) { this.setState({ legendBlock: false, }); } }, 300); componentDidMount() { window.addEventListener( 'resize', () => { this.requestRef = requestAnimationFrame(() => this.resize()); }, { passive: true }, ); } componentDidUpdate(preProps: PieProps) { const { data } = this.props; if (data !== preProps.data) { // because of charts data create when rendered // so there is a trick for get rendered time this.getLegendData(); } } componentWillUnmount() { if (this.requestRef) { window.cancelAnimationFrame(this.requestRef); } window.removeEventListener('resize', this.resize); if (this.resize) { (this.resize as any).cancel(); } } getG2Instance = (chart: G2.Chart) => { this.chart = chart; requestAnimationFrame(() => { this.getLegendData(); this.resize(); }); }; // for custom lengend view getLegendData = () => { if (!this.chart) return; const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 if (!geom) return; // g2 的类型有问题 const items = (geom as any).get('dataArray') || []; // 获取图形对应的 const legendData = items.map((item: { color: any; _origin: any }[]) => { /* eslint no-underscore-dangle:0 */ const origin = item[0]._origin; origin.color = item[0].color; origin.checked = true; return origin; }); this.setState({ legendData, }); }; handleRoot = (n: HTMLDivElement) => { this.root = n; }; handleLegendClick = (item: { checked: boolean }, i: string | number) => { const newItem = item; newItem.checked = !newItem.checked; const { legendData } = this.state; legendData[i] = newItem; const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x); if (this.chart) { this.chart.filter('x', val => filteredLegendData.indexOf(`${val}`) > -1); } this.setState({ legendData, }); }; root!: HTMLDivElement; chart: G2.Chart | undefined; requestRef: number | undefined; render() { const { valueFormat, subTitle, total, hasLegend = false, className, style, height = 0, forceFit = true, percent, color, inner = 0.75, animate = true, colors, lineWidth = 1, } = this.props; const { legendData, legendBlock } = this.state; const pieClassName = classNames(styles.pie, className, { [styles.hasLegend]: !!hasLegend, [styles.legendBlock]: legendBlock, }); const { data: propsData, selected: propsSelected = true, tooltip: propsTooltip = true, } = this.props; let data = propsData || []; let selected = propsSelected; let tooltip = propsTooltip; const defaultColors = colors; data = data || []; selected = selected || true; tooltip = tooltip || true; let formatColor; const scale = { x: { type: 'cat', range: [0, 1], }, y: { min: 0, }, }; if (percent || percent === 0) { selected = false; tooltip = false; formatColor = (value: string) => { if (value === '占比') { return color || 'rgba(24, 144, 255, 0.85)'; } return '#F0F2F5'; }; data = [ { x: '占比', y: parseFloat(`${percent}`), }, { x: '反比', y: 100 - parseFloat(`${percent}`), }, ]; } const tooltipFormat: [string, (...args: any[]) => { name?: string; value: string }] = [ 'x*percent', (x: string, p: number) => ({ name: x, value: `${(p * 100).toFixed(2)}%`, }), ]; const padding = [12, 0, 12, 0] as [number, number, number, number]; const dv = new DataView(); dv.source(data).transform({ type: 'percent', field: 'y', dimension: 'x', as: 'percent', }); return (
{!!tooltip && } {(subTitle || total) && (
{subTitle &&

{subTitle}

} {/* eslint-disable-next-line */} {total && (
{typeof total === 'function' ? total() : total}
)}
)}
{hasLegend && ( )}
); } } export default autoHeight()(Pie);