@dschz/solid-uplot 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index/index.d.ts +3 -1
- package/dist/index/index.js +1 -4
- package/dist/plugins/index.d.ts +29 -5
- package/dist/plugins/index.js +18 -13
- package/package.json +29 -31
- package/dist/chunk/X3NAOFDO.jsx +0 -42
- package/dist/index/index.jsx +0 -160
- package/dist/plugins/index.jsx +0 -334
package/dist/index/index.d.ts
CHANGED
|
@@ -30,11 +30,13 @@ type SolidUplotPlugin<T extends VoidStruct = VoidStruct> = uPlot$1.Plugin | Uplo
|
|
|
30
30
|
*
|
|
31
31
|
* @template T - The type of the plugin bus data structure
|
|
32
32
|
*/
|
|
33
|
-
type SolidUplotOptions<T extends VoidStruct = VoidStruct> = Omit<uPlot$1.Options, "plugins" | "width" | "height"> & {
|
|
33
|
+
type SolidUplotOptions<T extends VoidStruct = VoidStruct> = Omit<uPlot$1.Options, "plugins" | "width" | "height" | "data"> & {
|
|
34
34
|
/** Chart width in pixels */
|
|
35
35
|
readonly width?: number;
|
|
36
36
|
/** Chart height in pixels */
|
|
37
37
|
readonly height?: number;
|
|
38
|
+
/** Chart data - accepts AlignedData or number[][] */
|
|
39
|
+
readonly data?: uPlot$1.AlignedData | number[][];
|
|
38
40
|
/** Plugin communication bus for coordinating between plugins */
|
|
39
41
|
readonly pluginBus?: SolidUplotPluginBus<T>;
|
|
40
42
|
/** Array of plugins to apply to the chart */
|
package/dist/index/index.js
CHANGED
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { U as UplotPluginFactory, S as SolidUplotPluginBus } from '../createPluginBus-DdrjQANs.js';
|
|
2
2
|
import { C as CursorData, S as SeriesDatum } from '../getSeriesData-04wGQord.js';
|
|
3
3
|
import { Component, JSX } from 'solid-js';
|
|
4
|
-
import uPlot from 'uplot';
|
|
4
|
+
import uPlot$1 from 'uplot';
|
|
5
5
|
import 'solid-js/store';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -156,7 +156,7 @@ type FocusSeriesPluginMessageBus = {
|
|
|
156
156
|
/**
|
|
157
157
|
* Configuration options for the focus series plugin.
|
|
158
158
|
*/
|
|
159
|
-
type FocusSeriesPluginOptions = {
|
|
159
|
+
type FocusSeriesPluginOptions<T extends CursorPluginMessageBus & FocusSeriesPluginMessageBus> = {
|
|
160
160
|
/**
|
|
161
161
|
* The vertical distance in pixels required to focus a series.
|
|
162
162
|
* If the cursor's Y position is within this threshold of a Y value, that series is considered focused.
|
|
@@ -183,6 +183,24 @@ type FocusSeriesPluginOptions = {
|
|
|
183
183
|
* @default false
|
|
184
184
|
*/
|
|
185
185
|
readonly rebuildPaths?: boolean;
|
|
186
|
+
/**
|
|
187
|
+
*
|
|
188
|
+
* For charts that are configured with this plugin, this callback is used to determine if the chart
|
|
189
|
+
* should redraw when the plugin bus updates. It is an additional condition to the base condition `cursor?.sourceId !== u.root.id`
|
|
190
|
+
* which is always applied first to prevent the source chart from redrawing twice.
|
|
191
|
+
*
|
|
192
|
+
* This can be used to add filtering logic, such as only reacting to specific source charts.
|
|
193
|
+
*
|
|
194
|
+
* @default undefined (always redraw for non-source charts)
|
|
195
|
+
*/
|
|
196
|
+
readonly shouldRedrawOnBusUpdate?: (params: {
|
|
197
|
+
/** The current chart instance (the one evaluating whether to redraw) */
|
|
198
|
+
readonly u: uPlot;
|
|
199
|
+
/** Current cursor state from the bus (may be from another chart) */
|
|
200
|
+
readonly cursor: T["cursor"];
|
|
201
|
+
/** Current focus series state from the bus */
|
|
202
|
+
readonly focusSeries: T["focusSeries"];
|
|
203
|
+
}) => boolean;
|
|
186
204
|
};
|
|
187
205
|
/**
|
|
188
206
|
* Creates a focus series plugin that visually highlights series based on cursor proximity.
|
|
@@ -219,7 +237,7 @@ type FocusSeriesPluginOptions = {
|
|
|
219
237
|
* @param options - Configuration options for focus behavior
|
|
220
238
|
* @returns A plugin factory function that creates the focus series plugin instance
|
|
221
239
|
*/
|
|
222
|
-
declare const focusSeries: (options?: FocusSeriesPluginOptions) => UplotPluginFactory<CursorPluginMessageBus & FocusSeriesPluginMessageBus>;
|
|
240
|
+
declare const focusSeries: (options?: FocusSeriesPluginOptions<CursorPluginMessageBus & FocusSeriesPluginMessageBus>) => UplotPluginFactory<CursorPluginMessageBus & FocusSeriesPluginMessageBus>;
|
|
223
241
|
|
|
224
242
|
/**
|
|
225
243
|
* Simple legend placement options - only top corners to avoid axis conflicts
|
|
@@ -233,7 +251,7 @@ type LegendPlacement = "top-left" | "top-right";
|
|
|
233
251
|
* data flow where series data changes immediately trigger legend updates with fresh data information.
|
|
234
252
|
*/
|
|
235
253
|
type LegendProps = {
|
|
236
|
-
readonly u: uPlot;
|
|
254
|
+
readonly u: uPlot$1;
|
|
237
255
|
readonly seriesData: SeriesDatum[];
|
|
238
256
|
readonly bus: SolidUplotPluginBus<CursorPluginMessageBus & FocusSeriesPluginMessageBus>;
|
|
239
257
|
};
|
|
@@ -306,7 +324,7 @@ type TooltipCursorPlacement = "top-left" | "top-right" | "bottom-left" | "bottom
|
|
|
306
324
|
*/
|
|
307
325
|
type TooltipProps = {
|
|
308
326
|
/** The uPlot instance for accessing chart configuration and data */
|
|
309
|
-
readonly u: uPlot;
|
|
327
|
+
readonly u: uPlot$1;
|
|
310
328
|
/**
|
|
311
329
|
* Current cursor data including position and data index, automatically updated
|
|
312
330
|
* by the cursor plugin and passed via the plugin bus system
|
|
@@ -360,6 +378,12 @@ type TooltipConfigOptions = {
|
|
|
360
378
|
* @default "top-left"
|
|
361
379
|
*/
|
|
362
380
|
readonly placement?: TooltipCursorPlacement;
|
|
381
|
+
/**
|
|
382
|
+
* Use fixed positioning for the tooltip. Set to true when the chart is in a
|
|
383
|
+
* fixed positioning context (like a dialog or modal) to prevent tooltip clipping.
|
|
384
|
+
* @default false
|
|
385
|
+
*/
|
|
386
|
+
readonly fixed?: boolean;
|
|
363
387
|
};
|
|
364
388
|
/**
|
|
365
389
|
* Combined options for the tooltip plugin including container props and behavior config.
|
package/dist/plugins/index.js
CHANGED
|
@@ -58,7 +58,7 @@ var seriesFocusRedraw = (u, options = {}) => {
|
|
|
58
58
|
} = options;
|
|
59
59
|
for (let i = 1; i < u.series.length; i++) {
|
|
60
60
|
const s = u.series[i];
|
|
61
|
-
if (!focusTargets
|
|
61
|
+
if (!focusTargets?.length) {
|
|
62
62
|
s.alpha = 1;
|
|
63
63
|
continue;
|
|
64
64
|
}
|
|
@@ -104,13 +104,15 @@ var focusSeries = (options = {}) => {
|
|
|
104
104
|
dispose = createRoot((dispose2) => {
|
|
105
105
|
createEffect(() => {
|
|
106
106
|
const cursor2 = bus.data.cursor;
|
|
107
|
-
const
|
|
108
|
-
|
|
107
|
+
const focusSeries2 = bus.data.focusSeries;
|
|
108
|
+
const isNotSourceChart = cursor2?.sourceId !== u.root.id;
|
|
109
|
+
const userRedrawCondition = options.shouldRedrawOnBusUpdate?.({ u, cursor: cursor2, focusSeries: focusSeries2 }) ?? true;
|
|
110
|
+
if (isNotSourceChart && userRedrawCondition) {
|
|
109
111
|
seriesFocusRedraw(u, {
|
|
110
112
|
unfocusedAlpha,
|
|
111
113
|
focusedAlpha,
|
|
112
114
|
rebuildPaths,
|
|
113
|
-
focusTargets:
|
|
115
|
+
focusTargets: focusSeries2?.targets
|
|
114
116
|
});
|
|
115
117
|
}
|
|
116
118
|
});
|
|
@@ -231,11 +233,11 @@ var legend = (Component, options = {}) => {
|
|
|
231
233
|
var _tmpl$2 = /* @__PURE__ */ template(`<div role=tooltip aria-label="Chart tooltip">`);
|
|
232
234
|
var TOOLTIP_OFFSET_X = 8;
|
|
233
235
|
var TOOLTIP_OFFSET_Y = 8;
|
|
234
|
-
var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight) => {
|
|
236
|
+
var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight, isFixed = false) => {
|
|
235
237
|
const baseX = placement.includes("left") ? left - tooltipWidth - TOOLTIP_OFFSET_X : left + TOOLTIP_OFFSET_X;
|
|
236
238
|
const baseY = placement.includes("top") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : top + TOOLTIP_OFFSET_Y;
|
|
237
|
-
const viewportX = baseX - window.scrollX;
|
|
238
|
-
const viewportY = baseY - window.scrollY;
|
|
239
|
+
const viewportX = isFixed ? baseX : baseX - window.scrollX;
|
|
240
|
+
const viewportY = isFixed ? baseY : baseY - window.scrollY;
|
|
239
241
|
const overflowsLeft = viewportX < 0;
|
|
240
242
|
const overflowsRight = viewportX + tooltipWidth > window.innerWidth;
|
|
241
243
|
const overflowsTop = viewportY < 0;
|
|
@@ -271,12 +273,13 @@ var tooltip = (Component, options = {}) => {
|
|
|
271
273
|
const TooltipRoot = () => {
|
|
272
274
|
const _options = mergeProps({
|
|
273
275
|
placement: "top-left",
|
|
276
|
+
fixed: false,
|
|
274
277
|
id: "solid-uplot-tooltip-root",
|
|
275
278
|
style: {},
|
|
276
279
|
zIndex: 20
|
|
277
280
|
}, options);
|
|
278
281
|
const chartCursorData = () => bus.data.cursor?.state[u.root.id];
|
|
279
|
-
const [tooltipOptions, containerProps] = splitProps(_options, ["placement"]);
|
|
282
|
+
const [tooltipOptions, containerProps] = splitProps(_options, ["placement", "fixed"]);
|
|
280
283
|
return createComponent(Show, {
|
|
281
284
|
get when() {
|
|
282
285
|
return chartCursorData();
|
|
@@ -284,11 +287,13 @@ var tooltip = (Component, options = {}) => {
|
|
|
284
287
|
children: (cursor2) => {
|
|
285
288
|
const position = () => {
|
|
286
289
|
const overRect = u.over.getBoundingClientRect();
|
|
287
|
-
const absoluteLeft = overRect.left + cursor2().position.left + window.scrollX;
|
|
288
|
-
const absoluteTop = overRect.top + cursor2().position.top + window.scrollY;
|
|
289
290
|
const tooltipWidth = tooltipRoot.offsetWidth ?? 0;
|
|
290
291
|
const tooltipHeight = tooltipRoot.offsetHeight ?? 0;
|
|
291
|
-
|
|
292
|
+
const cursorLeft = overRect.left + cursor2().position.left;
|
|
293
|
+
const cursorTop = overRect.top + cursor2().position.top;
|
|
294
|
+
const absoluteLeft = tooltipOptions.fixed ? cursorLeft : cursorLeft + window.scrollX;
|
|
295
|
+
const absoluteTop = tooltipOptions.fixed ? cursorTop : cursorTop + window.scrollY;
|
|
296
|
+
return getTooltipPosition(tooltipOptions.placement, absoluteLeft, absoluteTop, tooltipWidth, tooltipHeight, tooltipOptions.fixed);
|
|
292
297
|
};
|
|
293
298
|
return (() => {
|
|
294
299
|
var _el$ = _tmpl$2();
|
|
@@ -306,11 +311,11 @@ var tooltip = (Component, options = {}) => {
|
|
|
306
311
|
}));
|
|
307
312
|
effect((_p$) => {
|
|
308
313
|
var _v$ = containerProps.id, _v$2 = containerProps.class, _v$3 = {
|
|
309
|
-
position: "absolute",
|
|
314
|
+
position: tooltipOptions.fixed ? "fixed" : "absolute",
|
|
310
315
|
"z-index": containerProps.zIndex,
|
|
316
|
+
"pointer-events": "none",
|
|
311
317
|
left: `${position().left}px`,
|
|
312
318
|
top: `${position().top}px`,
|
|
313
|
-
"pointer-events": "none",
|
|
314
319
|
...containerProps.style
|
|
315
320
|
};
|
|
316
321
|
_v$ !== _p$.e && setAttribute(_el$, "id", _p$.e = _v$);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dschz/solid-uplot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "SolidJS wrapper for uPlot — ultra-fast, tiny time-series & charting library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Daniel Sanchez <dsanc89@pm.me>",
|
|
@@ -59,14 +59,12 @@
|
|
|
59
59
|
"browser": {},
|
|
60
60
|
"exports": {
|
|
61
61
|
".": {
|
|
62
|
-
"solid": "./dist/index/index.jsx",
|
|
63
62
|
"import": {
|
|
64
63
|
"types": "./dist/index/index.d.ts",
|
|
65
64
|
"default": "./dist/index/index.js"
|
|
66
65
|
}
|
|
67
66
|
},
|
|
68
67
|
"./plugins": {
|
|
69
|
-
"solid": "./dist/plugins/index.jsx",
|
|
70
68
|
"import": {
|
|
71
69
|
"types": "./dist/plugins/index.d.ts",
|
|
72
70
|
"default": "./dist/plugins/index.js"
|
|
@@ -107,46 +105,46 @@
|
|
|
107
105
|
"typecheck": "tsc --noEmit"
|
|
108
106
|
},
|
|
109
107
|
"devDependencies": {
|
|
110
|
-
"@changesets/cli": "^2.29.
|
|
111
|
-
"@dschz/solid-auto-sizer": "^0.1.
|
|
112
|
-
"@solidjs/router": "^0.15.
|
|
108
|
+
"@changesets/cli": "^2.29.7",
|
|
109
|
+
"@dschz/solid-auto-sizer": "^0.1.3",
|
|
110
|
+
"@solidjs/router": "^0.15.4",
|
|
113
111
|
"@solidjs/testing-library": "^0.8.10",
|
|
114
|
-
"@tailwindcss/vite": "^4.1.
|
|
115
|
-
"@testing-library/jest-dom": "^6.
|
|
112
|
+
"@tailwindcss/vite": "^4.1.17",
|
|
113
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
116
114
|
"@testing-library/user-event": "^14.6.1",
|
|
117
|
-
"@types/bun": "^1.
|
|
118
|
-
"@types/prismjs": "^1.26.
|
|
119
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
120
|
-
"@typescript-eslint/parser": "^8.
|
|
121
|
-
"@vitest/coverage-istanbul": "^
|
|
115
|
+
"@types/bun": "^1.3.3",
|
|
116
|
+
"@types/prismjs": "^1.26.5",
|
|
117
|
+
"@typescript-eslint/eslint-plugin": "^8.47.0",
|
|
118
|
+
"@typescript-eslint/parser": "^8.47.0",
|
|
119
|
+
"@vitest/coverage-istanbul": "^4.0.13",
|
|
122
120
|
"@wessberg/pointer-events": "^1.0.9",
|
|
123
|
-
"canvas": "^3.
|
|
124
|
-
"eslint": "^9.
|
|
121
|
+
"canvas": "^3.2.0",
|
|
122
|
+
"eslint": "^9.39.1",
|
|
125
123
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
126
124
|
"eslint-plugin-solid": "^0.14.5",
|
|
127
|
-
"globals": "^16.
|
|
128
|
-
"jiti": "^2.
|
|
129
|
-
"jsdom": "^
|
|
130
|
-
"path2d": "^0.
|
|
131
|
-
"prettier": "^3.
|
|
132
|
-
"prismjs": "^1.
|
|
133
|
-
"solid-js": "^1.9.
|
|
134
|
-
"solid-prism-editor": "^2.
|
|
135
|
-
"tailwindcss": "^4.1.
|
|
136
|
-
"tsup": "^8.
|
|
125
|
+
"globals": "^16.5.0",
|
|
126
|
+
"jiti": "^2.6.1",
|
|
127
|
+
"jsdom": "^27.2.0",
|
|
128
|
+
"path2d": "^0.3.1",
|
|
129
|
+
"prettier": "^3.6.2",
|
|
130
|
+
"prismjs": "^1.30.0",
|
|
131
|
+
"solid-js": "^1.9.10",
|
|
132
|
+
"solid-prism-editor": "^2.1.0",
|
|
133
|
+
"tailwindcss": "^4.1.17",
|
|
134
|
+
"tsup": "^8.5.1",
|
|
137
135
|
"tsup-preset-solid": "^2.2.0",
|
|
138
|
-
"typescript": "^5.
|
|
139
|
-
"typescript-eslint": "^8.
|
|
136
|
+
"typescript": "^5.9.3",
|
|
137
|
+
"typescript-eslint": "^8.47.0",
|
|
140
138
|
"uplot": "^1.6.32",
|
|
141
|
-
"vite": "^
|
|
142
|
-
"vite-plugin-solid": "^2.11.
|
|
143
|
-
"vitest": "^
|
|
139
|
+
"vite": "^7.2.4",
|
|
140
|
+
"vite-plugin-solid": "^2.11.10",
|
|
141
|
+
"vitest": "^4.0.13"
|
|
144
142
|
},
|
|
145
143
|
"peerDependencies": {
|
|
146
144
|
"solid-js": ">=1.6.0",
|
|
147
145
|
"uplot": ">=1.6.32"
|
|
148
146
|
},
|
|
149
147
|
"dependencies": {
|
|
150
|
-
"@solid-primitives/refs": "^1.1.
|
|
148
|
+
"@solid-primitives/refs": "^1.1.2"
|
|
151
149
|
}
|
|
152
150
|
}
|
package/dist/chunk/X3NAOFDO.jsx
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// src/utils/getCursorData.ts
|
|
2
|
-
var getCursorData = (u) => {
|
|
3
|
-
const idx = u.cursor.idx;
|
|
4
|
-
const xValues = u.data[0];
|
|
5
|
-
const isValid = idx != null && xValues && idx < xValues.length;
|
|
6
|
-
return !isValid ? void 0 : {
|
|
7
|
-
plotId: u.root.id,
|
|
8
|
-
idx,
|
|
9
|
-
xValue: xValues[idx],
|
|
10
|
-
visible: Boolean(u.cursor.show),
|
|
11
|
-
position: { left: u.cursor.left || 0, top: u.cursor.top || 0 }
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// src/utils/getSeriesData.ts
|
|
16
|
-
var getSeriesData = (u, options = {}) => {
|
|
17
|
-
const series = [];
|
|
18
|
-
for (let i = 1; i < u.series.length; i++) {
|
|
19
|
-
const s = u.series[i];
|
|
20
|
-
const stroke = typeof s.stroke === "function" ? s.stroke(u, i) : s.stroke;
|
|
21
|
-
const fill = typeof s.fill === "function" ? s.fill(u, i) : s.fill;
|
|
22
|
-
const label = options.labelTransform?.(s.label) || s.label?.toString() || `Series ${i}`;
|
|
23
|
-
series.push({
|
|
24
|
-
idx: i - 1,
|
|
25
|
-
seriesIdx: i,
|
|
26
|
-
label,
|
|
27
|
-
stroke: stroke ?? "#000",
|
|
28
|
-
fill: fill ?? "transparent",
|
|
29
|
-
width: s.width,
|
|
30
|
-
dash: s.dash,
|
|
31
|
-
scale: s.scale,
|
|
32
|
-
visible: Boolean(s.show)
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
return series;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export {
|
|
39
|
-
getCursorData,
|
|
40
|
-
getSeriesData
|
|
41
|
-
};
|
|
42
|
-
// istanbul ignore next -- @preserve
|
package/dist/index/index.jsx
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getCursorData,
|
|
3
|
-
getSeriesData
|
|
4
|
-
} from "../chunk/X3NAOFDO.jsx";
|
|
5
|
-
|
|
6
|
-
// src/createPluginBus.tsx
|
|
7
|
-
import { createStore } from "solid-js/store";
|
|
8
|
-
var createPluginBus = (initialData = {}) => {
|
|
9
|
-
const [data, setData] = createStore(initialData);
|
|
10
|
-
return { data, setData };
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// src/SolidUplot.tsx
|
|
14
|
-
import "uplot/dist/uPlot.min.css";
|
|
15
|
-
import { mergeRefs } from "@solid-primitives/refs";
|
|
16
|
-
import {
|
|
17
|
-
createEffect,
|
|
18
|
-
createMemo,
|
|
19
|
-
createUniqueId,
|
|
20
|
-
mergeProps,
|
|
21
|
-
onCleanup,
|
|
22
|
-
splitProps,
|
|
23
|
-
untrack
|
|
24
|
-
} from "solid-js";
|
|
25
|
-
import uPlot2 from "uplot";
|
|
26
|
-
|
|
27
|
-
// src/utils/getNewCalendarDayIndices.ts
|
|
28
|
-
import "uplot";
|
|
29
|
-
|
|
30
|
-
// src/eventPlugins.ts
|
|
31
|
-
var createCursorMovePlugin = (onCursorMove) => {
|
|
32
|
-
return {
|
|
33
|
-
hooks: {
|
|
34
|
-
setCursor: (u) => {
|
|
35
|
-
const cursor = getCursorData(u);
|
|
36
|
-
if (!cursor) return;
|
|
37
|
-
onCursorMove?.({ u, cursor, seriesData: getSeriesData(u) });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// src/SolidUplot.tsx
|
|
44
|
-
var SolidUplot = (props) => {
|
|
45
|
-
let container;
|
|
46
|
-
const _props = mergeProps(
|
|
47
|
-
{
|
|
48
|
-
id: createUniqueId(),
|
|
49
|
-
childrenPlacement: "top",
|
|
50
|
-
width: 600,
|
|
51
|
-
height: 300,
|
|
52
|
-
autoResize: false,
|
|
53
|
-
data: [],
|
|
54
|
-
resetScales: true,
|
|
55
|
-
plugins: [],
|
|
56
|
-
legend: {
|
|
57
|
-
show: false
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
props
|
|
61
|
-
);
|
|
62
|
-
const [local, options] = splitProps(_props, [
|
|
63
|
-
"children",
|
|
64
|
-
"childrenPlacement",
|
|
65
|
-
"class",
|
|
66
|
-
"autoResize",
|
|
67
|
-
"onCreate",
|
|
68
|
-
"onCursorMove",
|
|
69
|
-
"style",
|
|
70
|
-
"ref"
|
|
71
|
-
]);
|
|
72
|
-
const [updateableOptions, newChartOptions] = splitProps(options, [
|
|
73
|
-
"data",
|
|
74
|
-
"width",
|
|
75
|
-
"height",
|
|
76
|
-
"resetScales"
|
|
77
|
-
]);
|
|
78
|
-
const [system, chartOptions] = splitProps(newChartOptions, ["pluginBus", "plugins"]);
|
|
79
|
-
const size = () => ({ width: updateableOptions.width, height: updateableOptions.height });
|
|
80
|
-
const chartPlugins = createMemo(() => {
|
|
81
|
-
const plugins = system.plugins.map(
|
|
82
|
-
(plugin) => typeof plugin === "function" ? plugin({ bus: system.pluginBus }) : plugin
|
|
83
|
-
);
|
|
84
|
-
if (local.onCursorMove) {
|
|
85
|
-
plugins.push(createCursorMovePlugin(local.onCursorMove));
|
|
86
|
-
}
|
|
87
|
-
return plugins;
|
|
88
|
-
});
|
|
89
|
-
createEffect(() => {
|
|
90
|
-
const getInitialSize = () => {
|
|
91
|
-
if (local.autoResize) {
|
|
92
|
-
const rect = container.getBoundingClientRect();
|
|
93
|
-
return {
|
|
94
|
-
width: rect.width > 0 ? Math.floor(rect.width) : 600,
|
|
95
|
-
height: rect.height > 0 ? Math.floor(rect.height) : 300
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return untrack(size);
|
|
99
|
-
};
|
|
100
|
-
const initialSize = getInitialSize();
|
|
101
|
-
const initialData = untrack(() => updateableOptions.data);
|
|
102
|
-
const chart = new uPlot2(
|
|
103
|
-
{
|
|
104
|
-
...chartOptions,
|
|
105
|
-
...initialSize,
|
|
106
|
-
plugins: chartPlugins()
|
|
107
|
-
},
|
|
108
|
-
initialData,
|
|
109
|
-
container
|
|
110
|
-
);
|
|
111
|
-
local.onCreate?.(chart, { seriesData: getSeriesData(chart) });
|
|
112
|
-
createEffect(() => {
|
|
113
|
-
if (local.autoResize) return;
|
|
114
|
-
chart.setSize(size());
|
|
115
|
-
});
|
|
116
|
-
createEffect(() => {
|
|
117
|
-
if (!local.autoResize) return;
|
|
118
|
-
const resizeObserver = new ResizeObserver((entries) => {
|
|
119
|
-
for (const entry of entries) {
|
|
120
|
-
const { width, height } = entry.contentRect;
|
|
121
|
-
chart.setSize({ width: Math.floor(width), height: Math.floor(height) });
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
resizeObserver.observe(container);
|
|
125
|
-
onCleanup(() => {
|
|
126
|
-
resizeObserver.disconnect();
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
createEffect(() => {
|
|
130
|
-
chart.setData(updateableOptions.data, updateableOptions.resetScales);
|
|
131
|
-
});
|
|
132
|
-
onCleanup(() => {
|
|
133
|
-
chart.destroy();
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
const classes = () => local.class ? `solid-uplot ${local.class}` : "solid-uplot";
|
|
137
|
-
return <div
|
|
138
|
-
id="solid-uplot-root"
|
|
139
|
-
ref={mergeRefs(local.ref, (el) => container = el)}
|
|
140
|
-
class={classes()}
|
|
141
|
-
style={{
|
|
142
|
-
display: "flex",
|
|
143
|
-
"flex-direction": local.childrenPlacement === "top" ? "column" : "column-reverse",
|
|
144
|
-
// When autoResize is enabled, fill the parent container
|
|
145
|
-
...local.autoResize && {
|
|
146
|
-
width: "100%",
|
|
147
|
-
height: "100%",
|
|
148
|
-
"min-width": "0",
|
|
149
|
-
"min-height": "0"
|
|
150
|
-
},
|
|
151
|
-
...local.style
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
{local.children}
|
|
155
|
-
</div>;
|
|
156
|
-
};
|
|
157
|
-
export {
|
|
158
|
-
SolidUplot,
|
|
159
|
-
createPluginBus
|
|
160
|
-
};
|
package/dist/plugins/index.jsx
DELETED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getCursorData,
|
|
3
|
-
getSeriesData
|
|
4
|
-
} from "../chunk/X3NAOFDO.jsx";
|
|
5
|
-
|
|
6
|
-
// src/plugins/cursor.ts
|
|
7
|
-
var cursor = () => {
|
|
8
|
-
return ({ bus }) => {
|
|
9
|
-
if (!bus) {
|
|
10
|
-
return { hooks: {} };
|
|
11
|
-
}
|
|
12
|
-
bus.setData("cursor", {
|
|
13
|
-
state: {}
|
|
14
|
-
});
|
|
15
|
-
let pointerEnter;
|
|
16
|
-
let pointerLeave;
|
|
17
|
-
return {
|
|
18
|
-
hooks: {
|
|
19
|
-
ready: (u) => {
|
|
20
|
-
pointerEnter = () => {
|
|
21
|
-
bus.setData("cursor", { sourceId: u.root.id });
|
|
22
|
-
};
|
|
23
|
-
pointerLeave = () => {
|
|
24
|
-
bus.setData("cursor", { sourceId: void 0 });
|
|
25
|
-
};
|
|
26
|
-
u.over.addEventListener("pointerenter", pointerEnter);
|
|
27
|
-
u.over.addEventListener("pointerleave", pointerLeave);
|
|
28
|
-
},
|
|
29
|
-
setCursor: (u) => {
|
|
30
|
-
bus.setData("cursor", "state", u.root.id, getCursorData(u));
|
|
31
|
-
},
|
|
32
|
-
setData: (u) => {
|
|
33
|
-
bus.setData("cursor", (prev) => ({
|
|
34
|
-
...prev ?? {},
|
|
35
|
-
state: {
|
|
36
|
-
...prev?.state ?? {},
|
|
37
|
-
[u.root.id]: getCursorData(u)
|
|
38
|
-
}
|
|
39
|
-
}));
|
|
40
|
-
},
|
|
41
|
-
destroy: (u) => {
|
|
42
|
-
bus.setData("cursor", "state", u.root.id, void 0);
|
|
43
|
-
u.over.removeEventListener("pointerenter", pointerEnter);
|
|
44
|
-
u.over.removeEventListener("pointerleave", pointerLeave);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// src/plugins/focusSeries.ts
|
|
52
|
-
import { createEffect, createRoot } from "solid-js";
|
|
53
|
-
var DEFAULT_UNFOCUSED_ALPHA = 0.1;
|
|
54
|
-
var DEFAULT_FOCUSED_ALPHA = 1;
|
|
55
|
-
var DEFAULT_REBUILD_PATHS = false;
|
|
56
|
-
var seriesFocusRedraw = (u, options = {}) => {
|
|
57
|
-
const {
|
|
58
|
-
unfocusedAlpha = DEFAULT_UNFOCUSED_ALPHA,
|
|
59
|
-
focusedAlpha = DEFAULT_FOCUSED_ALPHA,
|
|
60
|
-
rebuildPaths = DEFAULT_REBUILD_PATHS,
|
|
61
|
-
focusTargets
|
|
62
|
-
} = options;
|
|
63
|
-
for (let i = 1; i < u.series.length; i++) {
|
|
64
|
-
const s = u.series[i];
|
|
65
|
-
if (!focusTargets || !focusTargets.length) {
|
|
66
|
-
s.alpha = 1;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const target = focusTargets.find((t) => {
|
|
70
|
-
if ("label" in t) return t.label === s.label;
|
|
71
|
-
if ("zeroIndex" in t) return t.zeroIndex === i - 1;
|
|
72
|
-
if ("index" in t) return t.index === i;
|
|
73
|
-
});
|
|
74
|
-
s.alpha = target ? focusedAlpha : unfocusedAlpha;
|
|
75
|
-
}
|
|
76
|
-
u.redraw(rebuildPaths);
|
|
77
|
-
};
|
|
78
|
-
var focusSeries = (options = {}) => {
|
|
79
|
-
return ({ bus }) => {
|
|
80
|
-
if (!bus) {
|
|
81
|
-
return { hooks: {} };
|
|
82
|
-
}
|
|
83
|
-
const {
|
|
84
|
-
pxThreshold = 5,
|
|
85
|
-
unfocusedAlpha = DEFAULT_UNFOCUSED_ALPHA,
|
|
86
|
-
focusedAlpha = DEFAULT_FOCUSED_ALPHA,
|
|
87
|
-
rebuildPaths = DEFAULT_REBUILD_PATHS
|
|
88
|
-
} = options;
|
|
89
|
-
let dispose;
|
|
90
|
-
let pointerLeave;
|
|
91
|
-
return {
|
|
92
|
-
hooks: {
|
|
93
|
-
ready: (u) => {
|
|
94
|
-
pointerLeave = () => {
|
|
95
|
-
bus.setData("focusSeries", void 0);
|
|
96
|
-
};
|
|
97
|
-
queueMicrotask(() => {
|
|
98
|
-
if (bus.data.focusSeries) {
|
|
99
|
-
seriesFocusRedraw(u, {
|
|
100
|
-
unfocusedAlpha,
|
|
101
|
-
focusedAlpha,
|
|
102
|
-
rebuildPaths,
|
|
103
|
-
focusTargets: bus.data.focusSeries.targets
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
u.over.addEventListener("pointerleave", pointerLeave);
|
|
108
|
-
dispose = createRoot((dispose2) => {
|
|
109
|
-
createEffect(() => {
|
|
110
|
-
const cursor2 = bus.data.cursor;
|
|
111
|
-
const focus = bus.data.focusSeries;
|
|
112
|
-
if (cursor2?.sourceId !== u.root.id) {
|
|
113
|
-
seriesFocusRedraw(u, {
|
|
114
|
-
unfocusedAlpha,
|
|
115
|
-
focusedAlpha,
|
|
116
|
-
rebuildPaths,
|
|
117
|
-
focusTargets: focus?.targets
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
return dispose2;
|
|
122
|
-
});
|
|
123
|
-
},
|
|
124
|
-
setCursor: (u) => {
|
|
125
|
-
const cursor2 = bus.data.cursor;
|
|
126
|
-
const chartCursor = cursor2?.state[u.root.id];
|
|
127
|
-
if (!cursor2 || !chartCursor || cursor2.sourceId !== u.root.id) return;
|
|
128
|
-
const focusTargets = [];
|
|
129
|
-
for (let i = 1; i < u.series.length; i++) {
|
|
130
|
-
const s = u.series[i];
|
|
131
|
-
const yVals = u.data[i];
|
|
132
|
-
const val = yVals?.[chartCursor.idx];
|
|
133
|
-
if (!s.show || !yVals || val == null) continue;
|
|
134
|
-
const yPos = u.valToPos(val, s.scale);
|
|
135
|
-
const dist = Math.abs(yPos - chartCursor.position.top);
|
|
136
|
-
if (dist <= pxThreshold) {
|
|
137
|
-
if (s.label != null) {
|
|
138
|
-
focusTargets.push({ label: s.label });
|
|
139
|
-
} else {
|
|
140
|
-
focusTargets.push({ index: i });
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
seriesFocusRedraw(u, {
|
|
145
|
-
unfocusedAlpha,
|
|
146
|
-
focusedAlpha,
|
|
147
|
-
rebuildPaths,
|
|
148
|
-
focusTargets
|
|
149
|
-
});
|
|
150
|
-
bus.setData("focusSeries", {
|
|
151
|
-
sourceId: u.root.id,
|
|
152
|
-
targets: focusTargets
|
|
153
|
-
});
|
|
154
|
-
},
|
|
155
|
-
destroy: (u) => {
|
|
156
|
-
dispose();
|
|
157
|
-
u.over.removeEventListener("pointerleave", pointerLeave);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
};
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// src/plugins/legend.tsx
|
|
165
|
-
import { mergeProps, splitProps } from "solid-js";
|
|
166
|
-
import { render } from "solid-js/web";
|
|
167
|
-
import "uplot";
|
|
168
|
-
var legend = (Component, options = {}) => {
|
|
169
|
-
return ({ bus }) => {
|
|
170
|
-
if (!bus) {
|
|
171
|
-
return { hooks: {} };
|
|
172
|
-
}
|
|
173
|
-
let legendRoot;
|
|
174
|
-
let dispose;
|
|
175
|
-
return {
|
|
176
|
-
hooks: {
|
|
177
|
-
ready: (u) => {
|
|
178
|
-
const seriesData = getSeriesData(u);
|
|
179
|
-
const LegendRoot = () => {
|
|
180
|
-
const _options = mergeProps(
|
|
181
|
-
{
|
|
182
|
-
placement: "top-left",
|
|
183
|
-
pxOffset: 8,
|
|
184
|
-
id: "solid-uplot-legend-root",
|
|
185
|
-
zIndex: 10
|
|
186
|
-
},
|
|
187
|
-
options
|
|
188
|
-
);
|
|
189
|
-
const [legendOptions, containerProps] = splitProps(_options, ["placement", "pxOffset"]);
|
|
190
|
-
const containerStyle = () => {
|
|
191
|
-
const overRect = u.over.getBoundingClientRect();
|
|
192
|
-
const offset = legendOptions.pxOffset;
|
|
193
|
-
return {
|
|
194
|
-
position: "absolute",
|
|
195
|
-
[legendOptions.placement === "top-left" ? "left" : "right"]: `${offset}px`,
|
|
196
|
-
top: `${offset}px`,
|
|
197
|
-
"max-width": `${overRect.width - offset * 2}px`,
|
|
198
|
-
"max-height": `${overRect.height - offset * 2}px`,
|
|
199
|
-
"z-index": containerProps.zIndex,
|
|
200
|
-
"pointer-events": "auto",
|
|
201
|
-
overflow: "auto",
|
|
202
|
-
...containerProps.style
|
|
203
|
-
};
|
|
204
|
-
};
|
|
205
|
-
return <div
|
|
206
|
-
ref={legendRoot}
|
|
207
|
-
id={containerProps.id}
|
|
208
|
-
class={containerProps.class}
|
|
209
|
-
role="group"
|
|
210
|
-
aria-label="Chart legend"
|
|
211
|
-
style={containerStyle()}
|
|
212
|
-
>
|
|
213
|
-
<Component u={u} seriesData={seriesData} bus={bus} />
|
|
214
|
-
</div>;
|
|
215
|
-
};
|
|
216
|
-
dispose = render(() => <LegendRoot />, u.over);
|
|
217
|
-
},
|
|
218
|
-
destroy: () => {
|
|
219
|
-
dispose();
|
|
220
|
-
legendRoot?.remove();
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// src/plugins/tooltip.tsx
|
|
228
|
-
import { mergeProps as mergeProps2, Show, splitProps as splitProps2 } from "solid-js";
|
|
229
|
-
import { render as render2 } from "solid-js/web";
|
|
230
|
-
import "uplot";
|
|
231
|
-
var TOOLTIP_OFFSET_X = 8;
|
|
232
|
-
var TOOLTIP_OFFSET_Y = 8;
|
|
233
|
-
var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight) => {
|
|
234
|
-
const baseX = placement.includes("left") ? left - tooltipWidth - TOOLTIP_OFFSET_X : left + TOOLTIP_OFFSET_X;
|
|
235
|
-
const baseY = placement.includes("top") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : top + TOOLTIP_OFFSET_Y;
|
|
236
|
-
const viewportX = baseX - window.scrollX;
|
|
237
|
-
const viewportY = baseY - window.scrollY;
|
|
238
|
-
const overflowsLeft = viewportX < 0;
|
|
239
|
-
const overflowsRight = viewportX + tooltipWidth > window.innerWidth;
|
|
240
|
-
const overflowsTop = viewportY < 0;
|
|
241
|
-
const overflowsBottom = viewportY + tooltipHeight > window.innerHeight;
|
|
242
|
-
let flipX = false;
|
|
243
|
-
let flipY = false;
|
|
244
|
-
if (placement.includes("left") && overflowsLeft) flipX = true;
|
|
245
|
-
if (placement.includes("right") && overflowsRight) flipX = true;
|
|
246
|
-
if (placement.includes("top") && overflowsTop) flipY = true;
|
|
247
|
-
if (placement.includes("bottom") && overflowsBottom) flipY = true;
|
|
248
|
-
const finalX = flipX && placement.includes("left") ? left + TOOLTIP_OFFSET_X : flipX && placement.includes("right") ? left - tooltipWidth - TOOLTIP_OFFSET_X : baseX;
|
|
249
|
-
const finalY = flipY && placement.includes("top") ? top + TOOLTIP_OFFSET_Y : flipY && placement.includes("bottom") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : baseY;
|
|
250
|
-
return {
|
|
251
|
-
left: finalX,
|
|
252
|
-
top: finalY
|
|
253
|
-
};
|
|
254
|
-
};
|
|
255
|
-
var tooltip = (Component, options = {}) => {
|
|
256
|
-
return ({ bus }) => {
|
|
257
|
-
if (!bus) {
|
|
258
|
-
return { hooks: {} };
|
|
259
|
-
}
|
|
260
|
-
let tooltipRoot;
|
|
261
|
-
let dispose;
|
|
262
|
-
return {
|
|
263
|
-
hooks: {
|
|
264
|
-
ready: (u) => {
|
|
265
|
-
const seriesData = getSeriesData(u);
|
|
266
|
-
const TooltipRoot = () => {
|
|
267
|
-
const _options = mergeProps2(
|
|
268
|
-
{
|
|
269
|
-
placement: "top-left",
|
|
270
|
-
id: "solid-uplot-tooltip-root",
|
|
271
|
-
style: {},
|
|
272
|
-
zIndex: 20
|
|
273
|
-
},
|
|
274
|
-
options
|
|
275
|
-
);
|
|
276
|
-
const chartCursorData = () => bus.data.cursor?.state[u.root.id];
|
|
277
|
-
const [tooltipOptions, containerProps] = splitProps2(_options, ["placement"]);
|
|
278
|
-
return <Show when={chartCursorData()}>
|
|
279
|
-
{(cursor2) => {
|
|
280
|
-
const position = () => {
|
|
281
|
-
const overRect = u.over.getBoundingClientRect();
|
|
282
|
-
const absoluteLeft = overRect.left + cursor2().position.left + window.scrollX;
|
|
283
|
-
const absoluteTop = overRect.top + cursor2().position.top + window.scrollY;
|
|
284
|
-
const tooltipWidth = tooltipRoot.offsetWidth ?? 0;
|
|
285
|
-
const tooltipHeight = tooltipRoot.offsetHeight ?? 0;
|
|
286
|
-
return getTooltipPosition(
|
|
287
|
-
tooltipOptions.placement,
|
|
288
|
-
absoluteLeft,
|
|
289
|
-
absoluteTop,
|
|
290
|
-
tooltipWidth,
|
|
291
|
-
tooltipHeight
|
|
292
|
-
);
|
|
293
|
-
};
|
|
294
|
-
return <div
|
|
295
|
-
ref={tooltipRoot}
|
|
296
|
-
id={containerProps.id}
|
|
297
|
-
class={containerProps.class}
|
|
298
|
-
role="tooltip"
|
|
299
|
-
aria-label="Chart tooltip"
|
|
300
|
-
style={{
|
|
301
|
-
position: "absolute",
|
|
302
|
-
"z-index": containerProps.zIndex,
|
|
303
|
-
left: `${position().left}px`,
|
|
304
|
-
top: `${position().top}px`,
|
|
305
|
-
"pointer-events": "none",
|
|
306
|
-
...containerProps.style
|
|
307
|
-
}}
|
|
308
|
-
>
|
|
309
|
-
<Component
|
|
310
|
-
u={u}
|
|
311
|
-
seriesData={seriesData}
|
|
312
|
-
cursor={cursor2()}
|
|
313
|
-
focusedSeries={bus.data.focusSeries}
|
|
314
|
-
/>
|
|
315
|
-
</div>;
|
|
316
|
-
}}
|
|
317
|
-
</Show>;
|
|
318
|
-
};
|
|
319
|
-
dispose = render2(() => <TooltipRoot />, u.root);
|
|
320
|
-
},
|
|
321
|
-
destroy: () => {
|
|
322
|
-
dispose();
|
|
323
|
-
tooltipRoot?.remove();
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
};
|
|
328
|
-
};
|
|
329
|
-
export {
|
|
330
|
-
cursor,
|
|
331
|
-
focusSeries,
|
|
332
|
-
legend,
|
|
333
|
-
tooltip
|
|
334
|
-
};
|