You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

192 lines
3.8 KiB

import { CSSProperties } from 'react';
import * as echarts from 'echarts';
import { PieSeriesOption } from 'echarts';
import { useRef, useEffect } from 'react';
import { isEmpty, sumBy, head, merge, gt, gte, lte, ceil } from 'lodash';
import { CHARTS_COLORS, LOADING_COLOR } from './type';
import { useSize } from 'ahooks';
// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
type ECOption = echarts.ComposeOption<PieSeriesOption>;
export interface PieProps {
color?: Array<string>;
series: Array<any>;
loading?: boolean;
smooth?: boolean;
style?: CSSProperties;
options?: ECOption;
onDownCallBack?: any;
loadingType?: any;
}
function getOptions(width: number) {
if (gt(width, 1920)) {
return {
legend: {
textStyle: {
width: 140,
fontSize: 14,
overflow: 'truncate',
},
},
radius: ['60%', '80%'],
center: ['40%', '50%'],
title: {
left: '40%',
},
};
} else if (gte(width, 1680)) {
return {
legend: {
textStyle: {
width: 120,
fontSize: 12,
overflow: 'truncate',
},
},
radius: ['60%', '80%'],
center: ['35%', '50%'],
title: {
left: '35%',
},
};
} else if (gte(width, 1440)) {
return {
legend: {
textStyle: {
width: 100,
fontSize: 10,
overflow: 'truncate',
},
},
radius: ['50%', '70%'],
center: ['35%', '50%'],
title: {
left: '35%',
},
};
} else if (lte(width, 1440)) {
return {
legend: {
textStyle: {
width: 80,
fontSize: 8,
overflow: 'truncate',
},
},
radius: ['40%', '60%'],
center: ['30%', '50%'],
title: {
left: '30%',
},
};
} else {
return {
legend: {
textStyle: {
width: 100,
fontSize: 10,
overflow: 'truncate',
},
},
radius: ['50%', '70%'],
center: ['35%', '50%'],
title: {
left: '35%',
},
};
}
}
export function ChartsPie(props: PieProps) {
const {
color = CHARTS_COLORS,
series,
loading,
style,
options,
onDownCallBack,
loadingType = { color: LOADING_COLOR },
} = props;
const contentEle = useRef<any>();
const chartRef = useRef<any>();
const size = useSize(document.querySelector('body'));
// @ts-ignore
const sizeOptions = getOptions(size?.width);
// @ts-ignore
const legendShow = options?.legend?.show;
const defaultOptions: ECOption = merge(
{
color: color,
tooltip: {
trigger: 'item',
formatter: '{b}<br />数量: {c}<br />占比: {d}%',
},
label: {
formatter(params: { [key: string]: any }): any {
return `${params?.name}: ${params?.percent ?? 0}%`;
},
},
legend: {
show: false,
itemWidth: 10,
itemHeight: 10,
},
title: {
text: ceil(sumBy(head(series)?.data, 'value'), 2) || 0,
top: '47%',
textAlign: 'center',
left: '50%',
textStyle: {
color: '#333',
fontSize: 22,
fontWeight: '400',
},
},
},
options,
legendShow ? sizeOptions : {},
);
const responsive = useSize(contentEle.current);
useEffect(() => {
chartRef.current?.resize();
}, [JSON.stringify(responsive)]);
useEffect(() => {
if (!chartRef.current) {
chartRef.current = echarts.init(contentEle.current);
}
if (loading) {
chartRef.current.showLoading(Object.assign({ text: '' }, loadingType));
return;
} else {
chartRef.current.hideLoading();
}
if (!isEmpty(series)) {
chartRef.current.setOption({
...defaultOptions,
series: series.map((item) => ({
radius: sizeOptions.radius,
center: legendShow ? sizeOptions.center : ['50%', '50%'],
...item,
type: 'pie',
})),
});
if (onDownCallBack) {
chartRef.current.on('click', function (params: any) {
onDownCallBack(chartRef.current, params, options);
});
}
}
}, [series, loading]);
return (
<div ref={contentEle} style={{ width: '100%', height: '100%', ...style }} />
);
}