Skip to content

Commit 14ac678

Browse files
committed
Add chart
1 parent 9f004b2 commit 14ac678

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
3+
interface ChartContentProps {
4+
chart: string;
5+
dataHook: string;
6+
parameters: Record<string, any>;
7+
width?: string;
8+
}
9+
10+
const ChartContent = ({
11+
chart,
12+
dataHook,
13+
parameters,
14+
width = 'w-1/2',
15+
}: ChartContentProps) => {
16+
17+
const
18+
19+
return (
20+
<div className={`flex justify-center pt-2 items-center m-2 ${width ?? ''}`}>
21+
<div
22+
data-testid={dataHook}
23+
data-chart={chart}
24+
data-parameters={JSON.stringify(parameters)}
25+
/>
26+
</div>
27+
);
28+
};
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import React from 'react';
2+
import { processLabel, truncateString } from '../utils';
3+
import { ChartProps } from '../types';
4+
import ReactECharts, { ReactEChartsProps } from './ReactECharts';
5+
import { HistogramData, HistogramDataArray } from '@gen3/core';
6+
import { CallbackDataParams } from 'echarts/types/dist/shared';
7+
import { isArray } from 'lodash';
8+
import { useDeepCompareMemo } from 'use-deep-compare';
9+
10+
export interface BarChartData {
11+
data: number[];
12+
name: string;
13+
type: 'bar';
14+
stack: string;
15+
label: {
16+
show: boolean;
17+
};
18+
}
19+
20+
interface MultiTrackHorizontalBarChartData {
21+
data: HistogramDataArray;
22+
color: string;
23+
label: string;
24+
total: number;
25+
}
26+
27+
export interface MultitrackHorizontalBarChartProps extends Omit<
28+
ChartProps,
29+
'data'
30+
> {
31+
data: MultiTrackHorizontalBarChartData;
32+
valueType?: 'count' | 'percent';
33+
showLegendInChart?: boolean;
34+
labelTruncation?: number;
35+
showXTicks?: boolean;
36+
showYTicks?: boolean;
37+
xLabel?: string;
38+
yLabel?: string;
39+
maxBins?: number;
40+
}
41+
42+
const ExtractDataCount = (
43+
d: HistogramData,
44+
_: number | undefined = undefined,
45+
): number => d.count;
46+
const ExtractDataPercent = (d: HistogramData, total?: number): number =>
47+
total
48+
? Math.round(((d.count / total) * 100.0 + Number.EPSILON) * 100) / 100
49+
: 0;
50+
51+
const processChartData = (
52+
facetData: HistogramDataArray,
53+
valueType = 'count',
54+
total?: number,
55+
maxBins = 100,
56+
): BarChartData[] => {
57+
if (!facetData) {
58+
return [];
59+
}
60+
const data = facetData.filter((d: any) => d.key !== '_missing');
61+
62+
const dataExtractor =
63+
valueType === 'count' ? ExtractDataCount : ExtractDataPercent;
64+
65+
const results = data.slice(0, maxBins).map((d: any) => ({
66+
// TODO: fix type of d
67+
data: [dataExtractor(d, total)] as number[],
68+
name: truncateString(processLabel(d.key), 35),
69+
type: 'bar' as const,
70+
stack: 'value',
71+
label: {
72+
show: true,
73+
moveOverlap: true,
74+
},
75+
}));
76+
return results;
77+
};
78+
79+
const MultiTrackHorizontalBarChart = ({
80+
data,
81+
valueType,
82+
total,
83+
showLegendInChart = true,
84+
}: MultitrackHorizontalBarChartProps) => {
85+
const chartData = processChartData(data, valueType, total);
86+
87+
const chartDefinition =
88+
useDeepCompareMemo((): ReactEChartsProps['option'] => {
89+
return {
90+
tooltip: {
91+
trigger: 'item',
92+
confine: true,
93+
formatter: function (param) {
94+
const p: CallbackDataParams =
95+
isArray(param) && param.length > 0
96+
? param[0]
97+
: (param as CallbackDataParams);
98+
99+
const colorSquare = `<span style="display:inline-block; width:10px; height:10px; background-color:${p.color}; margin-right:5px;"></span>`;
100+
return `${colorSquare}${p.seriesName}: <b>${p.value}</b>`;
101+
},
102+
},
103+
legend: {
104+
orient: 'vertical',
105+
left: '73%',
106+
type: 'scroll',
107+
right: 15,
108+
show: showLegendInChart,
109+
},
110+
grid: {
111+
left: '0%',
112+
right: showLegendInChart ? '30%' : '3%',
113+
bottom: '25%',
114+
containLabel: true,
115+
height: '50%',
116+
},
117+
xAxis: {
118+
type: 'value',
119+
max: 'dataMax',
120+
axisLine: {
121+
lineStyle: {
122+
color: '--mantine-color-base-9',
123+
},
124+
},
125+
},
126+
yAxis: {
127+
type: 'category',
128+
data: [''],
129+
},
130+
series: chartData,
131+
};
132+
}, [chartData, showLegendInChart]);
133+
134+
return (
135+
<div className="w-full h-64">
136+
<ReactECharts
137+
option={chartDefinition}
138+
settings={{
139+
notMerge: true,
140+
lazyUpdate: false,
141+
}}
142+
/>
143+
</div>
144+
);
145+
};
146+
147+
export default MultiTrackHorizontalBarChart;

0 commit comments

Comments
 (0)