| New file |
| | |
| | | export type ChartRow<T> = { item: T; value: number; even: boolean }; |
| | | |
| | | /** 图表取值:0 不画;碳减排可为负,展示时取绝对值。 */ |
| | | export function chartValue(raw: number, carbon = false) { |
| | | const n = Number(raw); |
| | | if (!Number.isFinite(n) || n === 0) return 0; |
| | | return carbon ? Math.abs(n) : n; |
| | | } |
| | | |
| | | /** |
| | | * 分类图数据: |
| | | * - 部分有值:只保留当前指标 > 0 的类 |
| | | * - 全部为 0:evenSplit 时均分扇区(value=1 仅用于几何,even 标记给 tooltip 显示 0) |
| | | */ |
| | | export function chartSeries<T>( |
| | | items: T[] | undefined, |
| | | pick: (item: T) => number, |
| | | opts?: { carbon?: boolean; evenSplit?: boolean } |
| | | ): ChartRow<T>[] { |
| | | const list = items || []; |
| | | const rows = list.map(item => ({ |
| | | item, |
| | | raw: chartValue(pick(item), opts?.carbon) |
| | | })); |
| | | const positive = rows.filter(e => e.raw > 0); |
| | | if (positive.length) { |
| | | return positive.map(e => ({ item: e.item, value: e.raw, even: false })); |
| | | } |
| | | if (opts?.evenSplit === false) { |
| | | return rows.map(e => ({ item: e.item, value: 0, even: false })); |
| | | } |
| | | return rows.map(e => ({ item: e.item, value: 1, even: true })); |
| | | } |
| | | |
| | | export function pieTooltipFormatter(unit = '') { |
| | | return (p: any) => { |
| | | const val = p.data?.even ? 0 : p.value; |
| | | const u = unit ? ` ${unit}` : ''; |
| | | const pct = p.percent != null ? ` (${p.percent}%)` : ''; |
| | | return `${p.name}<br/>${val}${u}${pct}`; |
| | | }; |
| | | } |
| | | |
| | | export function toPieData<T>( |
| | | rows: ChartRow<T>[], |
| | | name: (item: T) => string, |
| | | color: (item: T) => string | undefined |
| | | ) { |
| | | return rows.map(row => ({ |
| | | name: name(row.item), |
| | | value: row.value, |
| | | even: row.even, |
| | | itemStyle: { color: color(row.item) } |
| | | })); |
| | | } |