Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | import { useEffect, useRef } from "react";
import { DataPoint, ChartMetadata } from "src/types/data";
// We'll use the project's built-in event system
const useLineChartMetadataExpose = (
dataSet,
xAxisDataType,
yScale,
disabledItems,
lineData,
filter,
onChartDataProcessed,
renderCompleteRef,
prevChartDataRef
) => {
// Keep track of the chart ID
// Track if we've dispatched our first event
const firstEventDispatchedRef = useRef(false);
useEffect(() => {
// Log whether render is complete for debugging
if (renderCompleteRef.current) {
// Extract all dates from all series
const allDates = dataSet.flatMap(set =>
set.series.map(point => (xAxisDataType === "number" ? point.date : String(point.date)))
);
// Create unique dates array
const uniqueDates = [...new Set(allDates)];
// Sort and filter series based on values at the filter date if filter exists
let visibleSeries = dataSet.map(d => d.label);
if (filter?.date) {
visibleSeries = visibleSeries.sort((a, b) => {
const aData = dataSet.find(d => d.label === a);
const bData = dataSet.find(d => d.label === b);
const aValue =
aData?.series.find(d => String(d.date) === String(filter.date))?.value || 0;
const bValue =
bData?.series.find(d => String(d.date) === String(filter.date))?.value || 0;
return filter.sortingDir === "desc" ? bValue - aValue : aValue - bValue;
});
// Apply limit if specified
if (filter.limit) {
visibleSeries = visibleSeries.slice(0, filter.limit);
}
}
const currentMetadata: ChartMetadata = {
xAxisDomain: uniqueDates.map(String),
yAxisDomain: yScale.domain() as [number, number],
visibleItems: visibleSeries.filter(
label =>
!disabledItems.includes(label) &&
dataSet.find(d => d.label === label)?.series.length > 0
),
renderedData: lineData.reduce(
(acc, item) => {
// Only include data for visible series
if (item.points.length > 0 && visibleSeries.includes(item.label)) {
acc[item.label] = item.points;
}
return acc;
},
{} as { [key: string]: DataPoint[] }
),
chartType: "line-chart",
};
// Check if data has actually changed
const hasChanged =
!prevChartDataRef.current ||
JSON.stringify(prevChartDataRef.current.xAxisDomain) !==
JSON.stringify(currentMetadata.xAxisDomain) ||
JSON.stringify(prevChartDataRef.current.yAxisDomain) !==
JSON.stringify(currentMetadata.yAxisDomain) ||
JSON.stringify(prevChartDataRef.current.visibleItems) !==
JSON.stringify(currentMetadata.visibleItems) ||
JSON.stringify(Object.keys(prevChartDataRef.current.renderedData).sort()) !==
JSON.stringify(Object.keys(currentMetadata.renderedData).sort());
// Always update the ref with latest metadata
prevChartDataRef.current = currentMetadata;
// Only emit event/call callback if data has changed
// Also always emit on first render when data is available
if (hasChanged || !firstEventDispatchedRef.current) {
firstEventDispatchedRef.current = true;
// Call the callback if it exists (for backward compatibility)
if (onChartDataProcessed) {
onChartDataProcessed(currentMetadata);
}
}
}
}, [
dataSet,
xAxisDataType,
yScale,
disabledItems,
lineData,
filter,
onChartDataProcessed,
prevChartDataRef,
]);
};
export default useLineChartMetadataExpose;
|