-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathLineChart.tsx
More file actions
125 lines (111 loc) · 4.43 KB
/
Copy pathLineChart.tsx
File metadata and controls
125 lines (111 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { useMemo } from 'react';
import type * as echarts from 'echarts';
import {
buildDatasetOption,
buildSeriesOption,
LINE_SERIES_SYMBOLS,
} from '../Utils/chartOptionBuilder';
import { useEChartOption } from '../Utils/useEChartOption';
import type { PxTable } from '../../../shared-types/pxTable';
import { mapPxTableToChartDataset } from '../Utils/chartDataMapper';
import {
getAdaptiveYAxisMax,
getAdaptiveYAxisMin,
getChartColorsFromCssVariables,
} from '../Utils/chartHelper';
interface LineChartProps {
readonly pxtable: PxTable;
readonly colors?: string[];
}
type TooltipParam = {
axisValueLabel?: string;
seriesIndex: number;
seriesName: string;
data?: Record<string, string | number>;
color?: string;
};
function getTooltipSymbolSvg(symbol: string, color: string): string {
switch (symbol) {
case 'rect':
return `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><rect x="1" y="1" width="8" height="8" fill="${color}" /></svg>`;
case 'triangle':
return `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><polygon points="5,1 9,9 1,9" fill="${color}" /></svg>`;
case 'diamond':
return `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><polygon points="5,1 9,5 5,9 1,5" fill="${color}" /></svg>`;
case 'pin':
return `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><path d="M5 1a2.2 2.2 0 0 0-2.2 2.2c0 1.8 2.2 5.6 2.2 5.6s2.2-3.8 2.2-5.6A2.2 2.2 0 0 0 5 1z" fill="${color}" /></svg>`;
case 'arrow':
return `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><path d="M1 5h5V3l3 2-3 2V5H1z" fill="${color}" /></svg>`;
default:
return `<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><circle cx="5" cy="5" r="4" fill="${color}" /></svg>`;
}
}
export function LineChart({ pxtable, colors }: LineChartProps) {
const dataset = useMemo(() => mapPxTableToChartDataset(pxtable), [pxtable]);
const xAxisName = useMemo(() => {
return pxtable.stub.map((variable) => variable.label).join(' / ');
}, [pxtable]);
const resolvedColors = useMemo(() => {
return colors && colors.length > 0
? colors
: getChartColorsFromCssVariables();
}, [colors]);
const option = useMemo<echarts.EChartsOption>(
() => ({
...buildDatasetOption(dataset),
grid: { top: 0, bottom: 200, left: '0', right: '0', containLabel: false },
xAxis: {
type: 'category' as const,
name: xAxisName,
nameLocation: 'end',
nameGap: 70,
axisLabel: { rotate: 45 },
},
yAxis: {
name: dataset.unit,
scale: true,
min: getAdaptiveYAxisMin,
max: getAdaptiveYAxisMax,
},
legend: {
height: 40 * dataset.series.length, // increase legend height based on number of series to prevent overlap with x-axis labels
},
series: buildSeriesOption(dataset, 'line', resolvedColors),
tooltip: {
trigger: 'axis',
formatter: (params: unknown) => {
const axisParams = (Array.isArray(params) ? params : [params]) as
| TooltipParam[]
| undefined;
if (!axisParams || axisParams.length === 0) {
return '';
}
const title = axisParams[0].axisValueLabel;
const rows = axisParams
.map((param) => {
const seriesMeta = dataset.series[param.seriesIndex];
const row = param.data as Record<string, string | number>;
const value = row?.[seriesMeta.key];
const symbol =
LINE_SERIES_SYMBOLS[
param.seriesIndex % LINE_SERIES_SYMBOLS.length
];
const color = param.color ?? '#666666';
return `<div style="display:flex;align-items:center;gap:6px"><span style="display:inline-flex;align-items:center">${getTooltipSymbolSvg(symbol, color)}</span><span>${param.seriesName}: ${value ?? ''}</span></div>`;
})
.join('');
return `<div><div>${title}</div>${rows}</div>`;
},
},
}),
[dataset, resolvedColors, xAxisName],
);
const { divRef } = useEChartOption(option);
const height = 600 + dataset.series.length * 10; // increase chart height based on number of series to prevent legend overlap
return (
<div>
<div ref={divRef} style={{ width: '100%', height: `${height}px` }}></div>
</div>
);
}
export default LineChart;