Skip to content

Commit 3ba7adf

Browse files
committed
add sliceSeries and setVariable functions
1 parent 5e4cbf2 commit 3ba7adf

File tree

2 files changed

+154
-2
lines changed

2 files changed

+154
-2
lines changed

src/components/ChartUPlot.tsx

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,44 @@ const stringify = (obj: any): string => {
2727
);
2828
};
2929

30+
/**
31+
* Slices a multi-series dataset to only the window where the given axis lies within [min, max].
32+
*
33+
* @param {number[][]} data - Array of N series, each an array of equal length.
34+
* One of these series at index `axis` is the “axis” to window on.
35+
* @param {number} axis - Index of the axis-series in `data`.
36+
* @param {number} min - Inclusive lower bound on axis values.
37+
* @param {number} max - Inclusive upper bound on axis values.
38+
* @returns {number[][]} - A new array of N series, each sliced to the [start..end] window.
39+
*/
40+
function _sliceSeries(
41+
data: number[][],
42+
axis: number,
43+
min: number,
44+
max: number,
45+
): number[][] {
46+
const axisData = data[axis];
47+
let start = -1,
48+
end = -1;
49+
50+
// find the first and last indices where axisData[i] ∈ [min, max]
51+
for (let i = 0; i < axisData.length; i++) {
52+
const v = axisData[i];
53+
if (v >= min && v <= max) {
54+
if (start === -1) start = i;
55+
end = i;
56+
}
57+
}
58+
59+
// if nothing falls in the range, return empty arrays
60+
if (start === -1) {
61+
return data.map(() => []);
62+
}
63+
64+
// slice each series to [start .. end]
65+
return data.map((series) => series.slice(start, end + 1));
66+
}
67+
3068
/**
3169
* Calculate the dimensions for the uPlot chart based on options, style, and device dimensions.
3270
* Adjusts for title and legend margins if they are present.
@@ -53,14 +91,14 @@ function getDimensions(
5391

5492
if (options?.title) {
5593
// Subtract height for title
56-
uplotHeight -= margin.title || MARGIN_TITLE;
94+
uplotHeight -= margin?.title != undefined ? margin.title : MARGIN_TITLE;
5795
}
5896

5997
if (options?.legend?.show) {
6098
// do nothing
6199
} else {
62100
// Subtract height for legend
63-
uplotHeight -= margin.legend || MARGIN_LEGEND;
101+
uplotHeight -= margin?.legend != undefined ? margin.legend : MARGIN_LEGEND;
64102
}
65103

66104
var optionsFinal = { ...options };
@@ -267,6 +305,58 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
267305
}
268306
}, []);
269307

308+
/**
309+
* Slices a multi-series dataset to only the window where the given axis lies within [min, max].
310+
*
311+
* @param {number[][]} data - Array of N series, each an array of equal length.
312+
* One of these series at index `axis` is the “axis” to window on.
313+
* @param {number} axis - Index of the axis-series in `data`.
314+
* @param {number} min - Inclusive lower bound on axis values.
315+
* @param {number} max - Inclusive upper bound on axis values.
316+
* @returns {number[][]} - A new array of N series, each sliced to the [start..end] window.
317+
*/
318+
const sliceSeries = useCallback(
319+
(axis: number, min: number, max: number): void => {
320+
if (isWeb) {
321+
// Slice the data arrays
322+
dataRef.current = _sliceSeries(dataRef.current, axis, min, max);
323+
324+
if (!uplotInstance.current) {
325+
console.error('uPlot instance is not initialized');
326+
return;
327+
}
328+
// Update the uPlot instance with the new data
329+
uplotInstance.current.setData(dataRef.current);
330+
} else {
331+
if (!webref) {
332+
console.error('WebView reference is not set');
333+
return;
334+
}
335+
webref.current.injectJavaScript(`
336+
var axis = ${JSON.stringify(axis)};
337+
var min = ${JSON.stringify(min)};
338+
var max = ${JSON.stringify(max)};
339+
340+
if (!winow._chart) {
341+
console.error('Chart not initialized');
342+
return;
343+
}
344+
345+
if (!window._data || !window._data[axis]) {
346+
console.error('Data not initialized or axis out of bounds');
347+
return;
348+
}
349+
350+
// call sliceSeries function, which we assume is already defined in the webview
351+
window._data = sliceSeries(window._data, axis, min, max);
352+
window._chart.setData(window._data);
353+
true;
354+
`);
355+
}
356+
},
357+
[],
358+
);
359+
270360
// function to call setScale
271361
const setScale = useCallback((axis: string, options: any): void => {
272362
if (isWeb) {
@@ -288,6 +378,33 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
288378
}
289379
}, []);
290380

381+
// if web, sets the variable to window.[name]
382+
// if native, sets the variable to window.[name] via webref.current.injectJavaScript
383+
const setVariable = useCallback((name: string, value: any): void => {
384+
if (isWeb) {
385+
if (!window) {
386+
console.error('Window is not defined');
387+
return;
388+
}
389+
390+
window[name] = value;
391+
} else {
392+
if (!webref) {
393+
console.error('WebView reference is not set');
394+
return;
395+
}
396+
397+
webref.current.injectJavaScript(`
398+
if (window._chart) {
399+
window.${name} = ${JSON.stringify(value)};
400+
} else {
401+
console.error('Chart not initialized');
402+
}
403+
true;
404+
`);
405+
}
406+
}, []);
407+
291408
// function to call setSize
292409
const setSize = useCallback((width: number, height: number): void => {
293410
if (isWeb) {
@@ -334,7 +451,9 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
334451
createChart,
335452
setData,
336453
pushData,
454+
sliceSeries,
337455
setScale,
456+
setVariable,
338457
setSize,
339458
destroy,
340459
}));

src/components/uplot.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,39 @@
3333

3434
return parsed;
3535
}
36+
37+
/**
38+
* Slices a multi-series dataset to only the window where the given axis lies within [min, max].
39+
*
40+
* @param {number[][]} data - Array of N series, each an array of equal length.
41+
* One of these series at index `axis` is the “axis” to window on.
42+
* @param {number} axis - Index of the axis-series in `data`.
43+
* @param {number} min - Inclusive lower bound on axis values.
44+
* @param {number} max - Inclusive upper bound on axis values.
45+
* @returns {number[][]} - A new array of N series, each sliced to the [start..end] window.
46+
*/
47+
function sliceSeries(data, axis, min, max) {
48+
const axisData = data[axis];
49+
let start = -1,
50+
end = -1;
51+
52+
// find the first and last indices where axisData[i] ∈ [min, max]
53+
for (let i = 0; i < axisData.length; i++) {
54+
const v = axisData[i];
55+
if (v >= min && v <= max) {
56+
if (start === -1) start = i;
57+
end = i;
58+
}
59+
}
60+
61+
// if nothing falls in the range, return empty arrays
62+
if (start === -1) {
63+
return data.map(() => []);
64+
}
65+
66+
// slice each series to [start .. end]
67+
return data.map((series) => series.slice(start, end + 1));
68+
}
3669
</script>
3770
'{{UPLOT_CSS}}' '{{UPLOT_JS}}'
3871
<style>

0 commit comments

Comments
 (0)