|
|
import { Card } from "antd";
|
|
|
import * as echarts from "echarts/core";
|
|
|
import { GridComponent, GridComponentOption } from "echarts/components";
|
|
|
import { BarChart, BarSeriesOption } from "echarts/charts";
|
|
|
import {
|
|
|
GridComponent,
|
|
|
TooltipComponent,
|
|
|
LegendComponent,
|
|
|
TitleComponent,
|
|
|
} from "echarts/components";
|
|
|
import {
|
|
|
BarChart,
|
|
|
PieChart,
|
|
|
LineChart,
|
|
|
BarSeriesOption,
|
|
|
PieSeriesOption,
|
|
|
LineSeriesOption,
|
|
|
} from "echarts/charts";
|
|
|
import { CanvasRenderer } from "echarts/renderers";
|
|
|
import { useRef, useState } from "react";
|
|
|
const tabList = [
|
|
|
{
|
|
|
key: "bar",
|
|
|
label: "柱状图",
|
|
|
},
|
|
|
{
|
|
|
key: "pie",
|
|
|
label: "饼图",
|
|
|
},
|
|
|
{
|
|
|
key: "line",
|
|
|
label: "折线图",
|
|
|
},
|
|
|
];
|
|
|
import { useRef, useEffect, useState } from "react";
|
|
|
import { ChartComponentProps, ChartData } from "./getChartData";
|
|
|
|
|
|
// 注册必要的组件
|
|
|
echarts.use([
|
|
|
GridComponent,
|
|
|
TooltipComponent,
|
|
|
LegendComponent,
|
|
|
TitleComponent,
|
|
|
BarChart,
|
|
|
PieChart,
|
|
|
LineChart,
|
|
|
CanvasRenderer,
|
|
|
]);
|
|
|
|
|
|
echarts.use([GridComponent, BarChart, CanvasRenderer]);
|
|
|
type EChartsOption = echarts.ComposeOption<
|
|
|
GridComponentOption | BarSeriesOption
|
|
|
BarSeriesOption | PieSeriesOption | LineSeriesOption
|
|
|
>;
|
|
|
|
|
|
var option: EChartsOption;
|
|
|
const tabList = [
|
|
|
{ key: "bar", label: "柱状图" },
|
|
|
{ key: "pie", label: "饼图" },
|
|
|
{ key: "line", label: "折线图" },
|
|
|
];
|
|
|
|
|
|
option = {
|
|
|
xAxis: {
|
|
|
type: "category",
|
|
|
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
|
|
},
|
|
|
yAxis: {
|
|
|
type: "value",
|
|
|
// 图表配置生成器
|
|
|
const getOption = (type: string, data: ChartData): EChartsOption => {
|
|
|
const commonOption = {
|
|
|
title: { text: `${tabList.find((t) => t.key === type)?.label}` },
|
|
|
tooltip: { trigger: "item" },
|
|
|
};
|
|
|
|
|
|
// 提取数值数组
|
|
|
const values = data.values.map((item) => item.value);
|
|
|
|
|
|
switch (type) {
|
|
|
case "bar":
|
|
|
return {
|
|
|
...commonOption,
|
|
|
xAxis: { type: "category", data: data.categories },
|
|
|
yAxis: { type: "value" },
|
|
|
series: [{ data: values, type: "bar" }],
|
|
|
};
|
|
|
case "pie":
|
|
|
return {
|
|
|
...commonOption,
|
|
|
series: [
|
|
|
{
|
|
|
type: "pie",
|
|
|
data: data.categories.map((name, i) => ({
|
|
|
name,
|
|
|
value: values[i],
|
|
|
})),
|
|
|
radius: "50%",
|
|
|
},
|
|
|
],
|
|
|
};
|
|
|
case "line":
|
|
|
return {
|
|
|
...commonOption,
|
|
|
xAxis: { type: "category", data: data.categories },
|
|
|
yAxis: { type: "value" },
|
|
|
series: [
|
|
|
{
|
|
|
data: [120, 200, 150, 80, 70, 110, 130],
|
|
|
type: "bar",
|
|
|
data: values,
|
|
|
type: "line",
|
|
|
smooth: true,
|
|
|
areaStyle: {},
|
|
|
},
|
|
|
],
|
|
|
};
|
|
|
default:
|
|
|
return {};
|
|
|
}
|
|
|
};
|
|
|
export function ChartComponent() {
|
|
|
const [activeTabKey, setActiveTabKey] = useState<string>("bar");
|
|
|
const line = useRef<HTMLCanvasElement>(null);
|
|
|
const bar = useRef<HTMLCanvasElement>(null);
|
|
|
const pie = useRef<HTMLCanvasElement>(null);
|
|
|
const contentListNoTitle: Record<string, React.ReactNode> = {
|
|
|
bar: <canvas ref={bar}></canvas>,
|
|
|
pie: <canvas ref={pie}></canvas>,
|
|
|
line: <canvas ref={line}></canvas>,
|
|
|
|
|
|
export function ChartComponent({
|
|
|
data = { categories: [], values: [] },
|
|
|
}: ChartComponentProps) {
|
|
|
const [activeTabKey, setActiveTabKey] = useState("bar");
|
|
|
const chartRef = useRef<HTMLDivElement>(null);
|
|
|
const chartInstance = useRef<echarts.ECharts | null>(null);
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (!chartRef.current) return;
|
|
|
|
|
|
// 数据校验
|
|
|
if (
|
|
|
!data?.categories?.length ||
|
|
|
!data?.values?.length ||
|
|
|
data.values.some((item) => typeof item.value !== "number")
|
|
|
) {
|
|
|
console.warn("Invalid chart data");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 销毁旧实例
|
|
|
if (chartInstance.current) {
|
|
|
chartInstance.current.dispose();
|
|
|
}
|
|
|
|
|
|
// 初始化新图表
|
|
|
chartInstance.current = echarts.init(chartRef.current);
|
|
|
chartInstance.current.setOption(getOption(activeTabKey, data));
|
|
|
|
|
|
// 窗口resize监听
|
|
|
const resizeHandler = () => chartInstance.current?.resize();
|
|
|
window.addEventListener("resize", resizeHandler);
|
|
|
|
|
|
// 清理函数
|
|
|
return () => {
|
|
|
window.removeEventListener("resize", resizeHandler);
|
|
|
chartInstance.current?.dispose();
|
|
|
};
|
|
|
// var myChart = echarts.init(bar);
|
|
|
}, [activeTabKey, data]);
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
<Card
|
|
|
style={{ width: "100%" }}
|
|
|
style={{ width: "100%", minHeight: 400 }}
|
|
|
tabList={tabList}
|
|
|
activeTabKey={activeTabKey}
|
|
|
onTabChange={setActiveTabKey}
|
|
|
tabProps={{ size: "middle" }}
|
|
|
>
|
|
|
{contentListNoTitle[activeTabKey]}
|
|
|
<div
|
|
|
ref={chartRef}
|
|
|
style={{
|
|
|
width: "100%",
|
|
|
height: 400,
|
|
|
minHeight: 400,
|
|
|
}}
|
|
|
/>
|
|
|
</Card>
|
|
|
</>
|
|
|
);
|
|
|
} |
...
|
...
|
|