From 1a4b752a018dd0f23a50165a7ccbda7ca856cea9 Mon Sep 17 00:00:00 2001 From: zty Date: Tue, 7 Jul 2026 21:28:38 -0400 Subject: [PATCH] feat(source): ContribPie material contribution pie chart component --- .../iapip-web/src/pages/source/ContribPie.tsx | 59 +++++++++++++++++++ .../iapip-web/src/pages/source/source.css | 10 ++++ 2 files changed, 69 insertions(+) create mode 100644 空气质量预测/源码/用户端/iapip-web/src/pages/source/ContribPie.tsx diff --git a/空气质量预测/源码/用户端/iapip-web/src/pages/source/ContribPie.tsx b/空气质量预测/源码/用户端/iapip-web/src/pages/source/ContribPie.tsx new file mode 100644 index 0000000..ca7e1df --- /dev/null +++ b/空气质量预测/源码/用户端/iapip-web/src/pages/source/ContribPie.tsx @@ -0,0 +1,59 @@ +export interface PieItem { + name: string + rate: number + isSrc: boolean +} + +interface Props { + items: PieItem[] + colors?: string[] +} + +const DEFAULT_COLORS = ['#C0392B', '#E67E22', '#E0A100', '#159A86', '#2E7FC1', '#6FB1E0', '#9AA7B4'] + +const R = 74 +const CX = 90 +const CY = 90 + +function arc(cx: number, cy: number, r: number, a0: number, a1: number) { + const p = (a: number) => [cx + r * Math.cos((a - 90) * Math.PI / 180), cy + r * Math.sin((a - 90) * Math.PI / 180)] + const [x0, y0] = p(a0) + const [x1, y1] = p(a1) + const large = a1 - a0 > 180 ? 1 : 0 + return `M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} Z` +} + +export default function ContribPie({ items, colors = DEFAULT_COLORS }: Props) { + const total = items.reduce((s, it) => s + it.rate, 0) + if (!items.length || total <= 0) { + return
该污染物无材料释放
+ } + const color = (i: number) => colors[Math.min(i, colors.length - 1)] + let acc = 0 + const slices = items.map((it, i) => { + const a0 = acc / total * 360 + acc += it.rate + const a1 = acc / total * 360 + return { d: arc(CX, CY, R, a0, a1), c: color(i), pct: it.rate / total * 100 } + }) + return ( +
+ + {slices.map((s, i) => ( + + {items[i].name}:{(items[i].rate * 100).toFixed(1)}% + + ))} + +
+ {items.map((it, i) => ( +
+ + {it.name}{it.isSrc && (污染源)} + {(it.rate * 100).toFixed(1)}% +
+ ))} +
+
+ ) +} diff --git a/空气质量预测/源码/用户端/iapip-web/src/pages/source/source.css b/空气质量预测/源码/用户端/iapip-web/src/pages/source/source.css index 980bf5b..939d8ad 100644 --- a/空气质量预测/源码/用户端/iapip-web/src/pages/source/source.css +++ b/空气质量预测/源码/用户端/iapip-web/src/pages/source/source.css @@ -255,3 +255,13 @@ .rbc-lg{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted,#8a8f98);} .rbc-lg i{width:11px;height:11px;border-radius:3px;display:inline-block;} .rbc-lg-dash{width:14px;height:0;border-top:1px dashed #C0392B;border-radius:0;} + +/* 材料贡献饼图 */ +.pie-wrap{display:flex;gap:22px;align-items:center;flex-wrap:wrap;padding:6px 2px 2px;} +.pie-svg{flex-shrink:0;} +.pie-legend{display:flex;flex-direction:column;gap:8px;min-width:200px;flex:1;} +.pie-lg{display:flex;align-items:center;gap:9px;font-size:13px;} +.pie-lg i{width:12px;height:12px;border-radius:3px;flex-shrink:0;} +.pie-lg-nm{flex:1;color:var(--ink,#1f2328);} +.pie-src{color:#C0392B;font-weight:700;} +.pie-lg-v{font-weight:700;color:var(--ink,#1f2328);}