'x'
This commit is contained in:
156
app/lib/charts/ReportChart.tsx
Normal file
156
app/lib/charts/ReportChart.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import * as echarts from "echarts";
|
||||
import type { BarChartDataItem, PieChartDataItem } from "./types";
|
||||
|
||||
export interface BarChartProps {
|
||||
data: BarChartDataItem[];
|
||||
title?: string;
|
||||
dark?: boolean;
|
||||
color?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function BarChart({
|
||||
data,
|
||||
title,
|
||||
dark = false,
|
||||
color = "#ff4d4f",
|
||||
className = "",
|
||||
}: BarChartProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current || data.length === 0) return;
|
||||
|
||||
const chart = echarts.init(ref.current);
|
||||
const textColor = dark ? "#e2e8f0" : "#334155";
|
||||
|
||||
chart.setOption({
|
||||
title: title ? { text: title, left: "center", textStyle: { color: textColor } } : undefined,
|
||||
tooltip: { trigger: "axis" },
|
||||
grid: { left: "3%", right: "4%", bottom: "3%", top: title ? 40 : 20, containLabel: true },
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: data.map((d) => d.name),
|
||||
axisLabel: { color: textColor },
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLabel: { color: textColor },
|
||||
splitLine: { lineStyle: { color: dark ? "#334155" : "#e2e8f0" } },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "bar",
|
||||
data: data.map((d) => d.value),
|
||||
itemStyle: { color },
|
||||
barMaxWidth: 36,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return () => chart.dispose();
|
||||
}, [data, title, dark, color]);
|
||||
|
||||
return <div ref={ref} className={className} style={{ height: 280, width: "100%" }} />;
|
||||
}
|
||||
|
||||
export interface PieChartProps {
|
||||
data: PieChartDataItem[];
|
||||
title?: string;
|
||||
dark?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const PIE_COLORS = ["#ff4d4f", "#f97316", "#eab308", "#22c55e", "#0ea5e9", "#8b5cf6"];
|
||||
|
||||
export function PieChart({
|
||||
data,
|
||||
title,
|
||||
dark = false,
|
||||
className = "",
|
||||
}: PieChartProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current || data.length === 0) return;
|
||||
|
||||
const chart = echarts.init(ref.current);
|
||||
const textColor = dark ? "#e2e8f0" : "#334155";
|
||||
|
||||
chart.setOption({
|
||||
title: title ? { text: title, left: "center", textStyle: { color: textColor } } : undefined,
|
||||
tooltip: { trigger: "item", formatter: "{b}: {c} ({d}%)" },
|
||||
legend: { bottom: 0, textStyle: { color: textColor } },
|
||||
series: [
|
||||
{
|
||||
type: "pie",
|
||||
radius: ["40%", "70%"],
|
||||
center: ["50%", title ? "45%" : "50%"],
|
||||
data: data.map((d, i) => ({
|
||||
name: d.name,
|
||||
value: d.value,
|
||||
itemStyle: { color: PIE_COLORS[i % PIE_COLORS.length] },
|
||||
})),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return () => chart.dispose();
|
||||
}, [data, title, dark]);
|
||||
|
||||
return <div ref={ref} className={className} style={{ height: 280, width: "100%" }} />;
|
||||
}
|
||||
|
||||
export interface LineChartProps {
|
||||
data: { xAxis: string[]; series: { name: string; data: number[] }[] };
|
||||
title?: string;
|
||||
dark?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function LineChart({
|
||||
data,
|
||||
title,
|
||||
dark = false,
|
||||
className = "",
|
||||
}: LineChartProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current || !data.xAxis?.length) return;
|
||||
|
||||
const chart = echarts.init(ref.current);
|
||||
const textColor = dark ? "#e2e8f0" : "#334155";
|
||||
|
||||
chart.setOption({
|
||||
title: title ? { text: title, left: "center", textStyle: { color: textColor } } : undefined,
|
||||
tooltip: { trigger: "axis" },
|
||||
legend: { bottom: 0, textStyle: { color: textColor } },
|
||||
grid: { left: "3%", right: "4%", bottom: 60, top: title ? 40 : 20, containLabel: true },
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: data.xAxis,
|
||||
axisLabel: { color: textColor },
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLabel: { color: textColor },
|
||||
splitLine: { lineStyle: { color: dark ? "#334155" : "#e2e8f0" } },
|
||||
},
|
||||
series: data.series.map((s, i) => ({
|
||||
type: "line",
|
||||
name: s.name,
|
||||
data: s.data,
|
||||
smooth: true,
|
||||
itemStyle: { color: PIE_COLORS[i % PIE_COLORS.length] },
|
||||
})),
|
||||
});
|
||||
|
||||
return () => chart.dispose();
|
||||
}, [data, title, dark]);
|
||||
|
||||
return <div ref={ref} className={className} style={{ height: 280, width: "100%" }} />;
|
||||
}
|
||||
Reference in New Issue
Block a user