Skip to content

Commit 7d36d02

Browse files
committed
more robust function handling
1 parent 84de668 commit 7d36d02

File tree

2 files changed

+67
-19
lines changed

2 files changed

+67
-19
lines changed

src/components/ChartUPlot.tsx

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,49 @@ if (isWeb) {
2222
const MARGIN_TITLE = 27; // Height of the title
2323
const MARGIN_LEGEND = 50; // Height of the legend
2424

25+
// Utility functions to be injected into the WebView
26+
// these are also present in the uplot.html file, but
27+
// they are also here since in some cases the <script>
28+
// tag in the HTML file is sometimes not executed in time
29+
const UTIL_FUNCTIONS = `
30+
function parseOptions(options) {
31+
var parsed = JSON.parse(options, (k, v) => {
32+
if (typeof v === 'string' && v.startsWith('__UPLOT_FUNC__')) {
33+
var name = v.replace(/^__UPLOT_FUNC__/, '');
34+
return window[name];
35+
}
36+
return v;
37+
});
38+
39+
return parsed;
40+
}
41+
42+
function sliceSeries(data, axis, min, max) {
43+
const axisData = data[axis];
44+
let start = -1;
45+
let end = -1;
46+
for (let i = 0; i < axisData.length; i++) {
47+
const v = axisData[i];
48+
if (v >= min && v <= max) {
49+
if (start === -1) start = i;
50+
end = i;
51+
}
52+
}
53+
54+
if (start === -1) {
55+
return data.map(() => []);
56+
}
57+
58+
return data.map((series) => series.slice(start, end + 1));
59+
}
60+
`;
61+
2562
const stringify = (obj: any): string => {
2663
return JSON.stringify(obj, (_key, val) =>
27-
typeof val === 'function' ? `function(${val.name || 'anonymous'})` : val,
64+
// encode functions as an explicit marker that parseOptions can detect reliably
65+
typeof val === 'function'
66+
? `__UPLOT_FUNC__${val.name || 'anonymous'}`
67+
: val,
2868
);
2969
};
3070

@@ -393,7 +433,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
393433
if (window._chart) {
394434
window._chart.setSize(${JSON.stringify(dimensionsRef.current.containerWidth)}, ${JSON.stringify(dimensionsRef.current.containerHeight)});
395435
} else {
396-
console.error('Chart not initialized');
436+
console.error('useEffect - dim | Chart not initialized');
397437
}
398438
true;
399439
`);
@@ -484,7 +524,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
484524
if (window._chart) {
485525
window._chart.setData(window._data);
486526
} else {
487-
console.error('Chart not initialized');
527+
console.error('setData | Chart not initialized');
488528
}
489529
true;
490530
`);
@@ -524,7 +564,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
524564
if (window._chart) {
525565
window._chart.setData(window._data);
526566
} else {
527-
console.error('Chart not initialized');
567+
console.error('pushData | Chart not initialized');
528568
}
529569
})();
530570
true;
@@ -566,7 +606,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
566606
if (window._chart) {
567607
window._chart.setData(window._data);
568608
} else {
569-
console.error('Chart not initialized or data not available');
609+
console.error('sliceSeries | Chart not initialized or data not available');
570610
}
571611
true;
572612
`);
@@ -589,7 +629,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
589629
if (window._chart) {
590630
window._chart.setScale(${JSON.stringify(axis)}, ${JSON.stringify(options)});true;
591631
} else {
592-
console.error('Chart not initialized');
632+
console.error('setScale | Chart not initialized');
593633
}
594634
true;
595635
`);
@@ -635,7 +675,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
635675
if (!window._chart) {
636676
window._chart.setSize(${JSON.stringify(width)}, ${JSON.stringify(height)});true;
637677
} else {
638-
console.error('Chart not initialized');
678+
console.error('setSize | Chart not initialized');
639679
}
640680
true;
641681
`);
@@ -679,6 +719,22 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
679719
[],
680720
);
681721

722+
// add UTIL_FUNCTIONS to the injectedJavaScript
723+
const injectedJavaScriptWithFunctions = useMemo(() => {
724+
return `
725+
${UTIL_FUNCTIONS}
726+
727+
${injectedJavaScript}
728+
729+
true;
730+
`;
731+
}, [injectedJavaScript]);
732+
733+
console.log(
734+
'injectedJavaScriptWithFunctions',
735+
injectedJavaScriptWithFunctions,
736+
);
737+
682738
useImperativeHandle(ref, () => ({
683739
createChart,
684740
updateOptions,
@@ -712,7 +768,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
712768
ref={setWebRef}
713769
onLayout={handleLayout}
714770
javaScriptEnabled={true}
715-
injectedJavaScript={`${injectedJavaScript}; true;`}
771+
injectedJavaScript={injectedJavaScriptWithFunctions}
716772
onMessage={handleMessage}
717773
/>
718774
);

src/components/uplot.html

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,9 @@
1616

1717
function parseOptions(options) {
1818
var parsed = JSON.parse(options, (k, v) => {
19-
if (
20-
typeof v === 'string' &&
21-
(v.trim().startsWith('function') || v.includes('=>'))
22-
) {
23-
const fnMatch = v.match(/^function\(\s*([^)]+)\s*\)$/);
24-
if (fnMatch) {
25-
return window[fnMatch[1]];
26-
} else {
27-
console.error('Invalid function format');
28-
return () => {};
29-
}
19+
if (typeof v === 'string' && v.startsWith('__UPLOT_FUNC__')) {
20+
var name = v.replace(/^__UPLOT_FUNC__/, '');
21+
return window[name];
3022
}
3123
return v;
3224
});

0 commit comments

Comments
 (0)