ui: use unique id for window values

This commit is contained in:
nick-delirium 2025-01-06 17:13:20 +01:00
parent db88d039ff
commit 1f3bb2b33c
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0
4 changed files with 70 additions and 56 deletions

View file

@ -5,7 +5,7 @@ import {
customTooltipFormatter
} from './utils';
import { buildBarDatasetsAndSeries } from './barUtils';
import { defaultOptions, echarts } from './init';
import { defaultOptions, echarts, initWindowStorages } from "./init";
import { BarChart } from 'echarts/charts';
echarts.use([BarChart]);
@ -16,6 +16,7 @@ interface BarChartProps extends DataProps {
}
function ORBarChart(props: BarChartProps) {
const chartUuid = React.useRef<string>(Math.random().toString(36).substring(7));
const chartRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
@ -24,23 +25,19 @@ function ORBarChart(props: BarChartProps) {
const categories = buildCategories(props.data);
const { datasets, series } = buildBarDatasetsAndSeries(props, props.horizontal ?? false);
(window as any).__seriesValueMap = {};
(window as any).__seriesColorMap = {};
(window as any).__timestampMap = props.data.chart.map((item) => item.timestamp);
(window as any).__categoryMap = categories;
initWindowStorages(chartUuid.current, categories, props.data.chart);
series.forEach((s: any) => {
(window as any).__seriesColorMap[s.name] = s.itemStyle?.color ?? '#999';
(window as any).__seriesColorMap[chartUuid.current][s.name] = s.itemStyle?.color ?? '#999';
const ds = datasets.find((d) => d.id === s.datasetId);
if (!ds) return;
const yDim = props.horizontal ? s.encode.x : s.encode.y;
const yDimIndex = ds.dimensions.indexOf(yDim);
if (yDimIndex < 0) return;
(window as any).__seriesValueMap[s.name] = {};
(window as any).__seriesValueMap[chartUuid.current][s.name] = {};
ds.source.forEach((row: any[]) => {
const rowIdx = row[0]; // 'idx'
(window as any).__seriesValueMap[s.name][rowIdx] = row[yDimIndex];
(window as any).__seriesValueMap[chartUuid.current][s.name][rowIdx] = row[yDimIndex];
});
});
@ -65,7 +62,7 @@ function ORBarChart(props: BarChartProps) {
},
tooltip: {
...defaultOptions.tooltip,
formatter: customTooltipFormatter,
formatter: customTooltipFormatter(chartUuid.current),
},
xAxis,
yAxis,
@ -75,10 +72,10 @@ function ORBarChart(props: BarChartProps) {
return () => {
chart.dispose();
delete (window as any).__seriesValueMap;
delete (window as any).__seriesColorMap;
delete (window as any).__categoryMap;
delete (window as any).__timestampMap;
delete (window as any).__seriesValueMap[chartUuid.current];
delete (window as any).__seriesColorMap[chartUuid.current];
delete (window as any).__categoryMap[chartUuid.current];
delete (window as any).__timestampMap[chartUuid.current];
};
}, [props.data, props.compData, props.horizontal]);

View file

@ -1,5 +1,5 @@
import React from 'react';
import { echarts, defaultOptions } from './init';
import { echarts, defaultOptions, initWindowStorages } from './init';
import { customTooltipFormatter, buildCategories, buildDatasetsAndSeries } from './utils'
import type { DataProps } from './utils'
import { LineChart } from 'echarts/charts';
@ -15,6 +15,7 @@ interface Props extends DataProps {
}
function ORLineChart(props: Props) {
const chartUuid = React.useRef<string>(Math.random().toString(36).substring(7));
const chartRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
@ -24,22 +25,16 @@ function ORLineChart(props: Props) {
const categories = buildCategories(props.data);
const { datasets, series } = buildDatasetsAndSeries(props);
// Create a quick map of name => dataIndex => value, for partner lookups
// and a map for colors. We'll store them on window in this example for brevity.
(window as any).__seriesValueMap = {};
(window as any).__seriesColorMap = {};
(window as any).__timestampMap = props.data.chart.map(item => item.timestamp);
(window as any).__categoryMap = categories;
initWindowStorages(chartUuid.current, categories, props.data.chart);
series.forEach((s: any) => {
if (props.isArea) {
s.areaStyle = {};
s.stack = 'Total'
// s.emphasis = { focus: 'series' };
s.stack = 'Total';
} else {
s.areaStyle = null;
}
(window as any).__seriesColorMap[s.name] = s.itemStyle?.color ?? '#999';
(window as any).__seriesColorMap[chartUuid.current][s.name] = s.itemStyle?.color ?? '#999';
const datasetId = s.datasetId || 'current';
const ds = datasets.find((d) => d.id === datasetId);
if (!ds) return;
@ -47,10 +42,10 @@ function ORLineChart(props: Props) {
const yDimIndex = ds.dimensions.indexOf(yDim);
if (yDimIndex < 0) return;
(window as any).__seriesValueMap[s.name] = {};
(window as any).__seriesValueMap[chartUuid.current][s.name] = {};
ds.source.forEach((row: any[]) => {
const rowIdx = row[0];
(window as any).__seriesValueMap[s.name][rowIdx] = row[yDimIndex];
(window as any).__seriesValueMap[chartUuid.current][s.name][rowIdx] = row[yDimIndex];
});
});
@ -77,23 +72,23 @@ function ORLineChart(props: Props) {
},
tooltip: {
...defaultOptions.tooltip,
formatter: customTooltipFormatter,
formatter: customTooltipFormatter(chartUuid.current),
},
dataset: datasets,
series,
});
chart.on('click', (event) => {
const index = event.dataIndex;
const timestamp = (window as any).__timestampMap?.[index];
const timestamp = (window as any).__timestampMap?.[chartUuid.current]?.[index];
props.onClick?.({ activePayload: [{ payload: { timestamp }}]})
})
return () => {
chart.dispose();
delete (window as any).__seriesValueMap;
delete (window as any).__seriesColorMap;
delete (window as any).__categoryMap;
delete (window as any).__timestampMap;
delete (window as any).__seriesValueMap[chartUuid.current];
delete (window as any).__seriesColorMap[chartUuid.current];
delete (window as any).__categoryMap[chartUuid.current];
delete (window as any).__timestampMap[chartUuid.current];
};
}, [props.data, props.compData]);

View file

@ -66,4 +66,24 @@ const defaultOptions = {
},
}
export function initWindowStorages(chartUuid: string, categories: string[] = [], chartArr: any[] = []) {
(window as any).__seriesValueMap = (window as any).__seriesValueMap ?? {};
(window as any).__seriesColorMap = (window as any).__seriesColorMap ?? {};
(window as any).__timestampMap = (window as any).__timestampMap ?? {};
(window as any).__categoryMap = (window as any).__categoryMap ?? {};
if (!(window as any).__seriesColorMap[chartUuid]) {
(window as any).__seriesColorMap[chartUuid] = {};
}
if (!(window as any).__seriesValueMap[chartUuid]) {
(window as any).__seriesValueMap[chartUuid] = {};
}
if (!(window as any).__categoryMap[chartUuid]) {
(window as any).__categoryMap[chartUuid] = categories;
}
if (!(window as any).__timestampMap[chartUuid]) {
(window as any).__timestampMap[chartUuid] = chartArr.map((item) => item.timestamp);
}
}
export { echarts, defaultOptions };

View file

@ -42,28 +42,29 @@ export function assignColorsByBaseName(series: any[]) {
/**
* Show the hovered current or previous line + the matching partner (if it exists).
*/
export function customTooltipFormatter(params: any): string {
// With trigger='item', params is a single object describing the hovered point
// { seriesName, dataIndex, data, marker, color, encode, ... }
if (!params) return '';
const { seriesName, dataIndex } = params;
export function customTooltipFormatter(uuid: string) {
return (params: any): string => {
// With trigger='item', params is a single object describing the hovered point
// { seriesName, dataIndex, data, marker, color, encode, ... }
if (!params) return '';
const { seriesName, dataIndex } = params;
// 'value' of the hovered point
const yKey = params.encode.y[0]; // "Series 1"
const value = params.data?.[yKey];
// 'value' of the hovered point
const yKey = params.encode.y[0]; // "Series 1"
const value = params.data?.[yKey];
const isPrevious = /^Previous\s+/.test(seriesName);
const baseName = seriesName.replace(/^Previous\s+/, '');
const partnerName = isPrevious ? baseName : `Previous ${baseName}`;
const isPrevious = /^Previous\s+/.test(seriesName);
const baseName = seriesName.replace(/^Previous\s+/, '');
const partnerName = isPrevious ? baseName : `Previous ${baseName}`;
// Get partners value from some global map
const partnerVal = (window as any).__seriesValueMap?.[partnerName]?.[dataIndex];
const timestamp = (window as any).__timestampMap?.[dataIndex];
const categoryLabel = (window as any).__categoryMap
? (window as any).__categoryMap[dataIndex]
: dataIndex;
// Get partners value from some global map
const partnerVal = (window as any).__seriesValueMap?.[uuid]?.[partnerName]?.[dataIndex];
const timestamp = (window as any).__timestampMap?.[uuid]?.[dataIndex];
const categoryLabel = (window as any).__categoryMap[uuid]
? (window as any).__categoryMap[uuid][dataIndex]
: dataIndex;
let tooltipContent = `
let tooltipContent = `
<div class="flex flex-col gap-1 bg-white shadow border rounded p-2 z-50">
<div class="flex gap-2 items-center">
<div style="
@ -86,9 +87,9 @@ export function customTooltipFormatter(params: any): string {
</div>
`;
if (partnerVal !== undefined) {
const partnerColor = (window as any).__seriesColorMap?.[partnerName] || '#999';
tooltipContent += `
if (partnerVal !== undefined) {
const partnerColor = (window as any).__seriesColorMap?.[uuid]?.[partnerName] || '#999';
tooltipContent += `
<div class="flex gap-2 items-center mt-2">
<div style="
border-radius: 99px;
@ -108,10 +109,11 @@ export function customTooltipFormatter(params: any): string {
</div>
</div>
`;
}
}
tooltipContent += '</div>';
return tooltipContent;
tooltipContent += '</div>';
return tooltipContent;
}
}
/**