@dschz/solid-uplot 0.1.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.
@@ -0,0 +1,342 @@
1
+ import { getCursorData } from '../chunk/3TJS44N7.js';
2
+ import { getSeriesData } from '../chunk/ZISGD6FJ.js';
3
+ import { createRoot, createEffect, mergeProps, splitProps, Show } from 'solid-js';
4
+ import { render, createComponent, template, use, insert, effect, setAttribute, className, style } from 'solid-js/web';
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
+ var DEFAULT_UNFOCUSED_ALPHA = 0.1;
51
+ var DEFAULT_FOCUSED_ALPHA = 1;
52
+ var DEFAULT_REBUILD_PATHS = false;
53
+ var seriesFocusRedraw = (u, options = {}) => {
54
+ const {
55
+ unfocusedAlpha = DEFAULT_UNFOCUSED_ALPHA,
56
+ focusedAlpha = DEFAULT_FOCUSED_ALPHA,
57
+ rebuildPaths = DEFAULT_REBUILD_PATHS,
58
+ focusTargets
59
+ } = options;
60
+ for (let i = 1; i < u.series.length; i++) {
61
+ const s = u.series[i];
62
+ if (!focusTargets || !focusTargets.length) {
63
+ s.alpha = 1;
64
+ continue;
65
+ }
66
+ const target = focusTargets.find((t) => {
67
+ if ("label" in t) return t.label === s.label;
68
+ if ("zeroIndex" in t) return t.zeroIndex === i - 1;
69
+ if ("index" in t) return t.index === i;
70
+ });
71
+ s.alpha = target ? focusedAlpha : unfocusedAlpha;
72
+ }
73
+ u.redraw(rebuildPaths);
74
+ };
75
+ var focusSeries = (options = {}) => {
76
+ return ({ bus }) => {
77
+ if (!bus) {
78
+ return { hooks: {} };
79
+ }
80
+ const {
81
+ pxThreshold = 5,
82
+ unfocusedAlpha = DEFAULT_UNFOCUSED_ALPHA,
83
+ focusedAlpha = DEFAULT_FOCUSED_ALPHA,
84
+ rebuildPaths = DEFAULT_REBUILD_PATHS
85
+ } = options;
86
+ let dispose;
87
+ let pointerLeave;
88
+ return {
89
+ hooks: {
90
+ ready: (u) => {
91
+ pointerLeave = () => {
92
+ bus.setData("focusSeries", void 0);
93
+ };
94
+ queueMicrotask(() => {
95
+ if (bus.data.focusSeries) {
96
+ seriesFocusRedraw(u, {
97
+ unfocusedAlpha,
98
+ focusedAlpha,
99
+ rebuildPaths,
100
+ focusTargets: bus.data.focusSeries.targets
101
+ });
102
+ }
103
+ });
104
+ u.over.addEventListener("pointerleave", pointerLeave);
105
+ dispose = createRoot((dispose2) => {
106
+ createEffect(() => {
107
+ const cursor2 = bus.data.cursor;
108
+ const focus = bus.data.focusSeries;
109
+ if (cursor2?.sourceId !== u.root.id) {
110
+ seriesFocusRedraw(u, {
111
+ unfocusedAlpha,
112
+ focusedAlpha,
113
+ rebuildPaths,
114
+ focusTargets: focus?.targets
115
+ });
116
+ }
117
+ });
118
+ return dispose2;
119
+ });
120
+ },
121
+ setCursor: (u) => {
122
+ const cursor2 = bus.data.cursor;
123
+ const chartCursor = cursor2?.state[u.root.id];
124
+ if (!cursor2 || !chartCursor || cursor2.sourceId !== u.root.id) return;
125
+ const focusTargets = [];
126
+ for (let i = 1; i < u.series.length; i++) {
127
+ const s = u.series[i];
128
+ const yVals = u.data[i];
129
+ const val = yVals?.[chartCursor.idx];
130
+ if (!s.show || !yVals || val == null) continue;
131
+ const yPos = u.valToPos(val, s.scale);
132
+ const dist = Math.abs(yPos - chartCursor.position.top);
133
+ if (dist <= pxThreshold) {
134
+ if (s.label != null) {
135
+ focusTargets.push({ label: s.label });
136
+ } else {
137
+ focusTargets.push({ index: i });
138
+ }
139
+ }
140
+ }
141
+ seriesFocusRedraw(u, {
142
+ unfocusedAlpha,
143
+ focusedAlpha,
144
+ rebuildPaths,
145
+ focusTargets
146
+ });
147
+ bus.setData("focusSeries", {
148
+ sourceId: u.root.id,
149
+ targets: focusTargets
150
+ });
151
+ },
152
+ destroy: (u) => {
153
+ dispose();
154
+ u.over.removeEventListener("pointerleave", pointerLeave);
155
+ }
156
+ }
157
+ };
158
+ };
159
+ };
160
+ var _tmpl$ = /* @__PURE__ */ template(`<div role=group aria-label="Chart legend">`);
161
+ var legend = (Component, options = {}) => {
162
+ return ({
163
+ bus
164
+ }) => {
165
+ if (!bus) {
166
+ return {
167
+ hooks: {}
168
+ };
169
+ }
170
+ let legendRoot;
171
+ let dispose;
172
+ return {
173
+ hooks: {
174
+ ready: (u) => {
175
+ const seriesData = getSeriesData(u);
176
+ const LegendRoot = () => {
177
+ const _options = mergeProps({
178
+ placement: "top-left",
179
+ pxOffset: 8,
180
+ id: "solid-uplot-legend-root",
181
+ zIndex: 10
182
+ }, options);
183
+ const [legendOptions, containerProps] = splitProps(_options, ["placement", "pxOffset"]);
184
+ const containerStyle = () => {
185
+ const overRect = u.over.getBoundingClientRect();
186
+ const offset = legendOptions.pxOffset;
187
+ return {
188
+ position: "absolute",
189
+ [legendOptions.placement === "top-left" ? "left" : "right"]: `${offset}px`,
190
+ top: `${offset}px`,
191
+ "max-width": `${overRect.width - offset * 2}px`,
192
+ "max-height": `${overRect.height - offset * 2}px`,
193
+ "z-index": containerProps.zIndex,
194
+ "pointer-events": "auto",
195
+ overflow: "auto",
196
+ ...containerProps.style
197
+ };
198
+ };
199
+ return (() => {
200
+ var _el$ = _tmpl$();
201
+ var _ref$ = legendRoot;
202
+ typeof _ref$ === "function" ? use(_ref$, _el$) : legendRoot = _el$;
203
+ insert(_el$, createComponent(Component, {
204
+ u,
205
+ seriesData,
206
+ bus
207
+ }));
208
+ effect((_p$) => {
209
+ var _v$ = containerProps.id, _v$2 = containerProps.class, _v$3 = containerStyle();
210
+ _v$ !== _p$.e && setAttribute(_el$, "id", _p$.e = _v$);
211
+ _v$2 !== _p$.t && className(_el$, _p$.t = _v$2);
212
+ _p$.a = style(_el$, _v$3, _p$.a);
213
+ return _p$;
214
+ }, {
215
+ e: void 0,
216
+ t: void 0,
217
+ a: void 0
218
+ });
219
+ return _el$;
220
+ })();
221
+ };
222
+ dispose = render(() => createComponent(LegendRoot, {}), u.over);
223
+ },
224
+ destroy: () => {
225
+ dispose();
226
+ legendRoot?.remove();
227
+ }
228
+ }
229
+ };
230
+ };
231
+ };
232
+ var _tmpl$2 = /* @__PURE__ */ template(`<div role=tooltip aria-label="Chart tooltip">`);
233
+ var TOOLTIP_OFFSET_X = 8;
234
+ var TOOLTIP_OFFSET_Y = 8;
235
+ var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight) => {
236
+ const baseX = placement.includes("left") ? left - tooltipWidth - TOOLTIP_OFFSET_X : left + TOOLTIP_OFFSET_X;
237
+ const baseY = placement.includes("top") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : top + TOOLTIP_OFFSET_Y;
238
+ const viewportX = baseX - window.scrollX;
239
+ const viewportY = baseY - window.scrollY;
240
+ const overflowsLeft = viewportX < 0;
241
+ const overflowsRight = viewportX + tooltipWidth > window.innerWidth;
242
+ const overflowsTop = viewportY < 0;
243
+ const overflowsBottom = viewportY + tooltipHeight > window.innerHeight;
244
+ let flipX = false;
245
+ let flipY = false;
246
+ if (placement.includes("left") && overflowsLeft) flipX = true;
247
+ if (placement.includes("right") && overflowsRight) flipX = true;
248
+ if (placement.includes("top") && overflowsTop) flipY = true;
249
+ if (placement.includes("bottom") && overflowsBottom) flipY = true;
250
+ const finalX = flipX && placement.includes("left") ? left + TOOLTIP_OFFSET_X : flipX && placement.includes("right") ? left - tooltipWidth - TOOLTIP_OFFSET_X : baseX;
251
+ const finalY = flipY && placement.includes("top") ? top + TOOLTIP_OFFSET_Y : flipY && placement.includes("bottom") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : baseY;
252
+ return {
253
+ left: finalX,
254
+ top: finalY
255
+ };
256
+ };
257
+ var tooltip = (Component, options = {}) => {
258
+ return ({
259
+ bus
260
+ }) => {
261
+ if (!bus) {
262
+ return {
263
+ hooks: {}
264
+ };
265
+ }
266
+ let tooltipRoot;
267
+ let dispose;
268
+ return {
269
+ hooks: {
270
+ ready: (u) => {
271
+ const seriesData = getSeriesData(u);
272
+ const TooltipRoot = () => {
273
+ const _options = mergeProps({
274
+ placement: "top-left",
275
+ id: "solid-uplot-tooltip-root",
276
+ style: {},
277
+ zIndex: 20
278
+ }, options);
279
+ const chartCursorData = () => bus.data.cursor?.state[u.root.id];
280
+ const [tooltipOptions, containerProps] = splitProps(_options, ["placement"]);
281
+ return createComponent(Show, {
282
+ get when() {
283
+ return chartCursorData();
284
+ },
285
+ children: (cursor2) => {
286
+ const position = () => {
287
+ const overRect = u.over.getBoundingClientRect();
288
+ const absoluteLeft = overRect.left + cursor2().position.left + window.scrollX;
289
+ const absoluteTop = overRect.top + cursor2().position.top + window.scrollY;
290
+ const tooltipWidth = tooltipRoot.offsetWidth ?? 0;
291
+ const tooltipHeight = tooltipRoot.offsetHeight ?? 0;
292
+ return getTooltipPosition(tooltipOptions.placement, absoluteLeft, absoluteTop, tooltipWidth, tooltipHeight);
293
+ };
294
+ return (() => {
295
+ var _el$ = _tmpl$2();
296
+ var _ref$ = tooltipRoot;
297
+ typeof _ref$ === "function" ? use(_ref$, _el$) : tooltipRoot = _el$;
298
+ insert(_el$, createComponent(Component, {
299
+ u,
300
+ seriesData,
301
+ get cursor() {
302
+ return cursor2();
303
+ },
304
+ get focusedSeries() {
305
+ return bus.data.focusSeries;
306
+ }
307
+ }));
308
+ effect((_p$) => {
309
+ var _v$ = containerProps.id, _v$2 = containerProps.class, _v$3 = {
310
+ position: "absolute",
311
+ "z-index": containerProps.zIndex,
312
+ left: `${position().left}px`,
313
+ top: `${position().top}px`,
314
+ "pointer-events": "none",
315
+ ...containerProps.style
316
+ };
317
+ _v$ !== _p$.e && setAttribute(_el$, "id", _p$.e = _v$);
318
+ _v$2 !== _p$.t && className(_el$, _p$.t = _v$2);
319
+ _p$.a = style(_el$, _v$3, _p$.a);
320
+ return _p$;
321
+ }, {
322
+ e: void 0,
323
+ t: void 0,
324
+ a: void 0
325
+ });
326
+ return _el$;
327
+ })();
328
+ }
329
+ });
330
+ };
331
+ dispose = render(() => createComponent(TooltipRoot, {}), u.root);
332
+ },
333
+ destroy: () => {
334
+ dispose();
335
+ tooltipRoot?.remove();
336
+ }
337
+ }
338
+ };
339
+ };
340
+ };
341
+
342
+ export { cursor, focusSeries, legend, tooltip };
@@ -0,0 +1,347 @@
1
+ import {
2
+ getSeriesData
3
+ } from "../chunk/A3AZKFSW.jsx";
4
+
5
+ // src/utils/getCursorData.ts
6
+ var getCursorData = (u) => {
7
+ const idx = u.cursor.idx;
8
+ const xValues = u.data[0];
9
+ const isValid = idx != null && xValues && idx < xValues.length;
10
+ return !isValid ? void 0 : {
11
+ plotId: u.root.id,
12
+ idx,
13
+ xValue: xValues[idx],
14
+ visible: Boolean(u.cursor.show),
15
+ position: { left: u.cursor.left || 0, top: u.cursor.top || 0 }
16
+ };
17
+ };
18
+
19
+ // src/plugins/cursor.ts
20
+ var cursor = () => {
21
+ return ({ bus }) => {
22
+ if (!bus) {
23
+ return { hooks: {} };
24
+ }
25
+ bus.setData("cursor", {
26
+ state: {}
27
+ });
28
+ let pointerEnter;
29
+ let pointerLeave;
30
+ return {
31
+ hooks: {
32
+ ready: (u) => {
33
+ pointerEnter = () => {
34
+ bus.setData("cursor", { sourceId: u.root.id });
35
+ };
36
+ pointerLeave = () => {
37
+ bus.setData("cursor", { sourceId: void 0 });
38
+ };
39
+ u.over.addEventListener("pointerenter", pointerEnter);
40
+ u.over.addEventListener("pointerleave", pointerLeave);
41
+ },
42
+ setCursor: (u) => {
43
+ bus.setData("cursor", "state", u.root.id, getCursorData(u));
44
+ },
45
+ setData: (u) => {
46
+ bus.setData("cursor", (prev) => ({
47
+ ...prev ?? {},
48
+ state: {
49
+ ...prev?.state ?? {},
50
+ [u.root.id]: getCursorData(u)
51
+ }
52
+ }));
53
+ },
54
+ destroy: (u) => {
55
+ bus.setData("cursor", "state", u.root.id, void 0);
56
+ u.over.removeEventListener("pointerenter", pointerEnter);
57
+ u.over.removeEventListener("pointerleave", pointerLeave);
58
+ }
59
+ }
60
+ };
61
+ };
62
+ };
63
+
64
+ // src/plugins/focusSeries.ts
65
+ import { createEffect, createRoot } from "solid-js";
66
+ var DEFAULT_UNFOCUSED_ALPHA = 0.1;
67
+ var DEFAULT_FOCUSED_ALPHA = 1;
68
+ var DEFAULT_REBUILD_PATHS = false;
69
+ var seriesFocusRedraw = (u, options = {}) => {
70
+ const {
71
+ unfocusedAlpha = DEFAULT_UNFOCUSED_ALPHA,
72
+ focusedAlpha = DEFAULT_FOCUSED_ALPHA,
73
+ rebuildPaths = DEFAULT_REBUILD_PATHS,
74
+ focusTargets
75
+ } = options;
76
+ for (let i = 1; i < u.series.length; i++) {
77
+ const s = u.series[i];
78
+ if (!focusTargets || !focusTargets.length) {
79
+ s.alpha = 1;
80
+ continue;
81
+ }
82
+ const target = focusTargets.find((t) => {
83
+ if ("label" in t) return t.label === s.label;
84
+ if ("zeroIndex" in t) return t.zeroIndex === i - 1;
85
+ if ("index" in t) return t.index === i;
86
+ });
87
+ s.alpha = target ? focusedAlpha : unfocusedAlpha;
88
+ }
89
+ u.redraw(rebuildPaths);
90
+ };
91
+ var focusSeries = (options = {}) => {
92
+ return ({ bus }) => {
93
+ if (!bus) {
94
+ return { hooks: {} };
95
+ }
96
+ const {
97
+ pxThreshold = 5,
98
+ unfocusedAlpha = DEFAULT_UNFOCUSED_ALPHA,
99
+ focusedAlpha = DEFAULT_FOCUSED_ALPHA,
100
+ rebuildPaths = DEFAULT_REBUILD_PATHS
101
+ } = options;
102
+ let dispose;
103
+ let pointerLeave;
104
+ return {
105
+ hooks: {
106
+ ready: (u) => {
107
+ pointerLeave = () => {
108
+ bus.setData("focusSeries", void 0);
109
+ };
110
+ queueMicrotask(() => {
111
+ if (bus.data.focusSeries) {
112
+ seriesFocusRedraw(u, {
113
+ unfocusedAlpha,
114
+ focusedAlpha,
115
+ rebuildPaths,
116
+ focusTargets: bus.data.focusSeries.targets
117
+ });
118
+ }
119
+ });
120
+ u.over.addEventListener("pointerleave", pointerLeave);
121
+ dispose = createRoot((dispose2) => {
122
+ createEffect(() => {
123
+ const cursor2 = bus.data.cursor;
124
+ const focus = bus.data.focusSeries;
125
+ if (cursor2?.sourceId !== u.root.id) {
126
+ seriesFocusRedraw(u, {
127
+ unfocusedAlpha,
128
+ focusedAlpha,
129
+ rebuildPaths,
130
+ focusTargets: focus?.targets
131
+ });
132
+ }
133
+ });
134
+ return dispose2;
135
+ });
136
+ },
137
+ setCursor: (u) => {
138
+ const cursor2 = bus.data.cursor;
139
+ const chartCursor = cursor2?.state[u.root.id];
140
+ if (!cursor2 || !chartCursor || cursor2.sourceId !== u.root.id) return;
141
+ const focusTargets = [];
142
+ for (let i = 1; i < u.series.length; i++) {
143
+ const s = u.series[i];
144
+ const yVals = u.data[i];
145
+ const val = yVals?.[chartCursor.idx];
146
+ if (!s.show || !yVals || val == null) continue;
147
+ const yPos = u.valToPos(val, s.scale);
148
+ const dist = Math.abs(yPos - chartCursor.position.top);
149
+ if (dist <= pxThreshold) {
150
+ if (s.label != null) {
151
+ focusTargets.push({ label: s.label });
152
+ } else {
153
+ focusTargets.push({ index: i });
154
+ }
155
+ }
156
+ }
157
+ seriesFocusRedraw(u, {
158
+ unfocusedAlpha,
159
+ focusedAlpha,
160
+ rebuildPaths,
161
+ focusTargets
162
+ });
163
+ bus.setData("focusSeries", {
164
+ sourceId: u.root.id,
165
+ targets: focusTargets
166
+ });
167
+ },
168
+ destroy: (u) => {
169
+ dispose();
170
+ u.over.removeEventListener("pointerleave", pointerLeave);
171
+ }
172
+ }
173
+ };
174
+ };
175
+ };
176
+
177
+ // src/plugins/legend.tsx
178
+ import { mergeProps, splitProps } from "solid-js";
179
+ import { render } from "solid-js/web";
180
+ import "uplot";
181
+ var legend = (Component, options = {}) => {
182
+ return ({ bus }) => {
183
+ if (!bus) {
184
+ return { hooks: {} };
185
+ }
186
+ let legendRoot;
187
+ let dispose;
188
+ return {
189
+ hooks: {
190
+ ready: (u) => {
191
+ const seriesData = getSeriesData(u);
192
+ const LegendRoot = () => {
193
+ const _options = mergeProps(
194
+ {
195
+ placement: "top-left",
196
+ pxOffset: 8,
197
+ id: "solid-uplot-legend-root",
198
+ zIndex: 10
199
+ },
200
+ options
201
+ );
202
+ const [legendOptions, containerProps] = splitProps(_options, ["placement", "pxOffset"]);
203
+ const containerStyle = () => {
204
+ const overRect = u.over.getBoundingClientRect();
205
+ const offset = legendOptions.pxOffset;
206
+ return {
207
+ position: "absolute",
208
+ [legendOptions.placement === "top-left" ? "left" : "right"]: `${offset}px`,
209
+ top: `${offset}px`,
210
+ "max-width": `${overRect.width - offset * 2}px`,
211
+ "max-height": `${overRect.height - offset * 2}px`,
212
+ "z-index": containerProps.zIndex,
213
+ "pointer-events": "auto",
214
+ overflow: "auto",
215
+ ...containerProps.style
216
+ };
217
+ };
218
+ return <div
219
+ ref={legendRoot}
220
+ id={containerProps.id}
221
+ class={containerProps.class}
222
+ role="group"
223
+ aria-label="Chart legend"
224
+ style={containerStyle()}
225
+ >
226
+ <Component u={u} seriesData={seriesData} bus={bus} />
227
+ </div>;
228
+ };
229
+ dispose = render(() => <LegendRoot />, u.over);
230
+ },
231
+ destroy: () => {
232
+ dispose();
233
+ legendRoot?.remove();
234
+ }
235
+ }
236
+ };
237
+ };
238
+ };
239
+
240
+ // src/plugins/tooltip.tsx
241
+ import { mergeProps as mergeProps2, Show, splitProps as splitProps2 } from "solid-js";
242
+ import { render as render2 } from "solid-js/web";
243
+ import "uplot";
244
+ var TOOLTIP_OFFSET_X = 8;
245
+ var TOOLTIP_OFFSET_Y = 8;
246
+ var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight) => {
247
+ const baseX = placement.includes("left") ? left - tooltipWidth - TOOLTIP_OFFSET_X : left + TOOLTIP_OFFSET_X;
248
+ const baseY = placement.includes("top") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : top + TOOLTIP_OFFSET_Y;
249
+ const viewportX = baseX - window.scrollX;
250
+ const viewportY = baseY - window.scrollY;
251
+ const overflowsLeft = viewportX < 0;
252
+ const overflowsRight = viewportX + tooltipWidth > window.innerWidth;
253
+ const overflowsTop = viewportY < 0;
254
+ const overflowsBottom = viewportY + tooltipHeight > window.innerHeight;
255
+ let flipX = false;
256
+ let flipY = false;
257
+ if (placement.includes("left") && overflowsLeft) flipX = true;
258
+ if (placement.includes("right") && overflowsRight) flipX = true;
259
+ if (placement.includes("top") && overflowsTop) flipY = true;
260
+ if (placement.includes("bottom") && overflowsBottom) flipY = true;
261
+ const finalX = flipX && placement.includes("left") ? left + TOOLTIP_OFFSET_X : flipX && placement.includes("right") ? left - tooltipWidth - TOOLTIP_OFFSET_X : baseX;
262
+ const finalY = flipY && placement.includes("top") ? top + TOOLTIP_OFFSET_Y : flipY && placement.includes("bottom") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : baseY;
263
+ return {
264
+ left: finalX,
265
+ top: finalY
266
+ };
267
+ };
268
+ var tooltip = (Component, options = {}) => {
269
+ return ({ bus }) => {
270
+ if (!bus) {
271
+ return { hooks: {} };
272
+ }
273
+ let tooltipRoot;
274
+ let dispose;
275
+ return {
276
+ hooks: {
277
+ ready: (u) => {
278
+ const seriesData = getSeriesData(u);
279
+ const TooltipRoot = () => {
280
+ const _options = mergeProps2(
281
+ {
282
+ placement: "top-left",
283
+ id: "solid-uplot-tooltip-root",
284
+ style: {},
285
+ zIndex: 20
286
+ },
287
+ options
288
+ );
289
+ const chartCursorData = () => bus.data.cursor?.state[u.root.id];
290
+ const [tooltipOptions, containerProps] = splitProps2(_options, ["placement"]);
291
+ return <Show when={chartCursorData()}>
292
+ {(cursor2) => {
293
+ const position = () => {
294
+ const overRect = u.over.getBoundingClientRect();
295
+ const absoluteLeft = overRect.left + cursor2().position.left + window.scrollX;
296
+ const absoluteTop = overRect.top + cursor2().position.top + window.scrollY;
297
+ const tooltipWidth = tooltipRoot.offsetWidth ?? 0;
298
+ const tooltipHeight = tooltipRoot.offsetHeight ?? 0;
299
+ return getTooltipPosition(
300
+ tooltipOptions.placement,
301
+ absoluteLeft,
302
+ absoluteTop,
303
+ tooltipWidth,
304
+ tooltipHeight
305
+ );
306
+ };
307
+ return <div
308
+ ref={tooltipRoot}
309
+ id={containerProps.id}
310
+ class={containerProps.class}
311
+ role="tooltip"
312
+ aria-label="Chart tooltip"
313
+ style={{
314
+ position: "absolute",
315
+ "z-index": containerProps.zIndex,
316
+ left: `${position().left}px`,
317
+ top: `${position().top}px`,
318
+ "pointer-events": "none",
319
+ ...containerProps.style
320
+ }}
321
+ >
322
+ <Component
323
+ u={u}
324
+ seriesData={seriesData}
325
+ cursor={cursor2()}
326
+ focusedSeries={bus.data.focusSeries}
327
+ />
328
+ </div>;
329
+ }}
330
+ </Show>;
331
+ };
332
+ dispose = render2(() => <TooltipRoot />, u.root);
333
+ },
334
+ destroy: () => {
335
+ dispose();
336
+ tooltipRoot?.remove();
337
+ }
338
+ }
339
+ };
340
+ };
341
+ };
342
+ export {
343
+ cursor,
344
+ focusSeries,
345
+ legend,
346
+ tooltip
347
+ };