layerchart 0.94.2 → 0.95.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.
@@ -203,6 +203,7 @@ declare class __sveltets_Render<TData> {
203
203
  hide: () => void;
204
204
  mode: "manual" | "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree";
205
205
  }>;
206
+ hideDelay?: number;
206
207
  }> | undefined;
207
208
  /** Exposed via bind: to support `bind:tooltipContext` for external access (ex. `tooltipContext.data) */
208
209
  tooltipContext?: import("svelte/store").Writable<{
@@ -18,6 +18,7 @@
18
18
 
19
19
  import { isScaleBand } from '../utils/scales.js';
20
20
  import { accessor, type Accessor } from '../utils/common.js';
21
+ import { asAny } from '../utils/types.js';
21
22
 
22
23
  const {
23
24
  data: contextData,
@@ -424,14 +425,14 @@
424
425
  onpointerenter={onpointenter &&
425
426
  ((e) => {
426
427
  if (onpointclick) {
427
- (e.target as HTMLElement | SVGElement).style.cursor = 'pointer';
428
+ asAny(e.target).style.cursor = 'pointer';
428
429
  }
429
430
  onpointenter(e, { point, data: highlightData });
430
431
  })}
431
432
  onpointerleave={onpointleave &&
432
433
  ((e) => {
433
434
  if (onpointclick) {
434
- (e.target as HTMLElement | SVGElement).style.cursor = 'default';
435
+ asAny(e.target).style.cursor = 'default';
435
436
  }
436
437
  onpointleave(e, { point, data: highlightData });
437
438
  })}
@@ -166,6 +166,10 @@
166
166
 
167
167
  let highlightSeriesKey: (typeof series)[number]['key'] | null = null;
168
168
 
169
+ function setHighlightSeriesKey(seriesKey: typeof highlightSeriesKey) {
170
+ highlightSeriesKey = seriesKey;
171
+ }
172
+
169
173
  function getAreaProps(s: (typeof series)[number], i: number) {
170
174
  const lineProps = {
171
175
  ...props.line,
@@ -336,6 +340,7 @@
336
340
  getAreaProps,
337
341
  getLabelsProps,
338
342
  getPointsProps,
343
+ setHighlightSeriesKey,
339
344
  }}
340
345
 
341
346
  <slot {...slotProps}>
@@ -486,6 +491,8 @@
486
491
  color={s.color}
487
492
  {format}
488
493
  valueAlign="right"
494
+ onpointerenter={() => (highlightSeriesKey = s.key)}
495
+ onpointerleave={() => (highlightSeriesKey = null)}
489
496
  {...props.tooltip?.item}
490
497
  />
491
498
  {/each}
@@ -196,6 +196,10 @@
196
196
 
197
197
  let highlightSeriesKey: (typeof series)[number]['key'] | null = null;
198
198
 
199
+ function setHighlightSeriesKey(seriesKey: typeof highlightSeriesKey) {
200
+ highlightSeriesKey = seriesKey;
201
+ }
202
+
199
203
  function getBarsProps(s: (typeof series)[number], i: number) {
200
204
  const isFirst = i == 0;
201
205
  const isLast = i == visibleSeries.length - 1;
@@ -343,6 +347,7 @@
343
347
  visibleSeries,
344
348
  getBarsProps,
345
349
  getLabelsProps,
350
+ setHighlightSeriesKey,
346
351
  }}
347
352
  <slot {...slotProps}>
348
353
  <slot name="belowContext" {...slotProps} />
@@ -474,6 +479,8 @@
474
479
  color={s.color ?? cScale?.(c(data))}
475
480
  {format}
476
481
  valueAlign="right"
482
+ onpointerenter={() => (highlightSeriesKey = s.key)}
483
+ onpointerleave={() => (highlightSeriesKey = null)}
477
484
  {...props.tooltip?.item}
478
485
  />
479
486
  {/each}
@@ -132,6 +132,10 @@
132
132
 
133
133
  let highlightSeriesKey: (typeof series)[number]['key'] | null = null;
134
134
 
135
+ function setHighlightSeriesKey(seriesKey: typeof highlightSeriesKey) {
136
+ highlightSeriesKey = seriesKey;
137
+ }
138
+
135
139
  function getSplineProps(s: (typeof series)[number], i: number) {
136
140
  const splineProps: ComponentProps<Spline> = {
137
141
  data: s.data,
@@ -267,6 +271,7 @@
267
271
  getLabelsProps,
268
272
  getPointsProps,
269
273
  getSplineProps,
274
+ setHighlightSeriesKey,
270
275
  }}
271
276
  <slot {...slotProps}>
272
277
  <slot name="belowContext" {...slotProps} />
@@ -406,6 +411,8 @@
406
411
  value={seriesTooltipData ? valueAccessor(seriesTooltipData) : null}
407
412
  color={s.color}
408
413
  {format}
414
+ onpointerenter={() => (highlightSeriesKey = s.key)}
415
+ onpointerleave={() => (highlightSeriesKey = null)}
409
416
  {...props.tooltip?.item}
410
417
  />
411
418
  {/each}
@@ -140,6 +140,10 @@
140
140
 
141
141
  let highlightKey: (typeof series)[number]['key'] | null = null;
142
142
 
143
+ function setHighlightKey(key: typeof highlightKey) {
144
+ highlightKey = key ?? null;
145
+ }
146
+
143
147
  const selectedKeys = selectionStore();
144
148
  $: visibleData = chartData.filter((d) => {
145
149
  const dataKey = keyAccessor(d);
@@ -204,6 +208,7 @@
204
208
  tooltip,
205
209
  series,
206
210
  visibleData,
211
+ setHighlightKey,
207
212
  }}
208
213
  <slot {...slotProps}>
209
214
  <slot name="belowContext" {...slotProps} />
@@ -331,6 +336,8 @@
331
336
  value={valueAccessor(data)}
332
337
  color={cScale?.(c(data))}
333
338
  {format}
339
+ onpointerenter={() => (highlightKey = keyAccessor(data))}
340
+ onpointerleave={() => (highlightKey = null)}
334
341
  {...props.tooltip?.item}
335
342
  />
336
343
  </Tooltip.List>
@@ -139,6 +139,7 @@ declare class __sveltets_Render<TData> {
139
139
  hide: () => void;
140
140
  mode: "manual" | "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree";
141
141
  }>;
142
+ hideDelay?: number;
142
143
  }> | undefined;
143
144
  tooltipContext?: import("svelte/store").Writable<{
144
145
  x: number;
@@ -113,6 +113,10 @@
113
113
 
114
114
  let highlightSeriesKey: (typeof series)[number]['key'] | null = null;
115
115
 
116
+ function setHighlightSeriesKey(seriesKey: typeof highlightSeriesKey) {
117
+ highlightSeriesKey = seriesKey ?? null;
118
+ }
119
+
116
120
  function getPointsProps(s: (typeof series)[number], i: number) {
117
121
  const pointsProps: ComponentProps<Points> = {
118
122
  data: s.data,
@@ -229,6 +233,7 @@
229
233
  visibleSeries,
230
234
  getLabelsProps,
231
235
  getPointsProps,
236
+ setHighlightSeriesKey,
232
237
  }}
233
238
  {@const activeSeries = tooltip.data
234
239
  ? (series.find((s) => s.key === tooltip.data.seriesKey) ?? series[0])
@@ -349,12 +354,16 @@
349
354
  label={typeof config.x === 'string' ? config.x : 'x'}
350
355
  value={x(data)}
351
356
  {format}
357
+ onpointerenter={() => (highlightSeriesKey = activeSeries?.key ?? null)}
358
+ onpointerleave={() => (highlightSeriesKey = null)}
352
359
  {...props.tooltip?.item}
353
360
  />
354
361
  <Tooltip.Item
355
362
  label={typeof config.y === 'string' ? config.y : 'y'}
356
363
  value={y(data)}
357
364
  {format}
365
+ onpointerenter={() => (highlightSeriesKey = activeSeries?.key ?? null)}
366
+ onpointerleave={() => (highlightSeriesKey = null)}
358
367
  {...props.tooltip?.item}
359
368
  />
360
369
  {#if config.r}
@@ -362,6 +371,8 @@
362
371
  label={typeof config.r === 'string' ? config.r : 'r'}
363
372
  value={r(data)}
364
373
  {format}
374
+ onpointerenter={() => (highlightSeriesKey = activeSeries?.key ?? null)}
375
+ onpointerleave={() => (highlightSeriesKey = null)}
365
376
  {...props.tooltip?.item}
366
377
  />
367
378
  {/if}
@@ -101,7 +101,7 @@
101
101
  /** Similar to d3-selection's raise, re-insert the e.target as the last child of its parent, so to be the top-most element */
102
102
  export let raiseTarget = false;
103
103
 
104
- /** Lock tooltip (keep open, do not update on mouse movement). Allows for kicking on tooltip */
104
+ /** Lock tooltip (keep open, do not update on mouse movement). Allows for clicking on tooltip */
105
105
  export let locked = false;
106
106
 
107
107
  /** quadtree search radius
@@ -124,6 +124,10 @@
124
124
  });
125
125
  setTooltipContext(tooltip);
126
126
 
127
+ /** Delay in ms before hiding tooltip */
128
+ export let hideDelay = 0;
129
+
130
+ let isHoveringTooltip = false;
127
131
  let hideTimeoutId: NodeJS.Timeout;
128
132
 
129
133
  $: bisectX = bisector((d: any) => {
@@ -175,7 +179,9 @@
175
179
 
176
180
  function showTooltip(e: PointerEvent, tooltipData?: any) {
177
181
  // Cancel hiding tooltip if from previous event loop
178
- clearTimeout(hideTimeoutId);
182
+ if (hideTimeoutId) {
183
+ clearTimeout(hideTimeoutId);
184
+ }
179
185
 
180
186
  if (locked) {
181
187
  // Ignore (keep current position / data)
@@ -294,9 +300,12 @@
294
300
  }
295
301
 
296
302
  // Wait an event loop tick in case `showTooltip` is called immediately on another element, to allow tweeneing (ex. moving between bands/bars)
303
+ // Additional hideDelay can be configured to extend this delay further
297
304
  hideTimeoutId = setTimeout(() => {
298
- $tooltip = { ...$tooltip, data: null };
299
- });
305
+ if (!isHoveringTooltip) {
306
+ $tooltip = { ...$tooltip, data: null };
307
+ }
308
+ }, hideDelay);
300
309
  }
301
310
 
302
311
  let quadtree: Quadtree<[number, number]>;
@@ -401,9 +410,19 @@
401
410
  'TooltipContext absolute touch-none',
402
411
  debug && triggerPointerEvents && 'bg-danger/10 outline outline-danger'
403
412
  )}
404
- on:pointerenter={triggerPointerEvents ? showTooltip : undefined}
413
+ on:pointerenter={(e) => {
414
+ isHoveringTooltip = true;
415
+ if (triggerPointerEvents) {
416
+ showTooltip(e);
417
+ }
418
+ }}
405
419
  on:pointermove={triggerPointerEvents ? showTooltip : undefined}
406
- on:pointerleave={triggerPointerEvents ? hideTooltip : undefined}
420
+ on:pointerleave={(e) => {
421
+ isHoveringTooltip = false;
422
+ if (triggerPointerEvents) {
423
+ hideTooltip();
424
+ }
425
+ }}
407
426
  on:click={(e) => {
408
427
  if (triggerPointerEvents) {
409
428
  onclick(e, { data: $tooltip?.data });
@@ -21,7 +21,7 @@ declare const __propDef: {
21
21
  * @type {'closest' | 'left' | 'right'}
22
22
  */ findTooltipData?: "closest" | "left" | "right";
23
23
  /** Similar to d3-selection's raise, re-insert the e.target as the last child of its parent, so to be the top-most element */ raiseTarget?: boolean;
24
- /** Lock tooltip (keep open, do not update on mouse movement). Allows for kicking on tooltip */ locked?: boolean;
24
+ /** Lock tooltip (keep open, do not update on mouse movement). Allows for clicking on tooltip */ locked?: boolean;
25
25
  /** quadtree search radius
26
26
  * @type {number}
27
27
  */ radius?: number;
@@ -37,6 +37,7 @@ declare const __propDef: {
37
37
  hide: () => void;
38
38
  mode: TooltipMode;
39
39
  }>;
40
+ /** Delay in ms before hiding tooltip */ hideDelay?: number;
40
41
  };
41
42
  events: {
42
43
  [evt: string]: CustomEvent<any>;
@@ -22,7 +22,7 @@
22
22
  >
23
23
  {#if color}
24
24
  <div
25
- class={cls('color', 'inline-block size-2 rounded-full bg-[--color]', classes.color)}
25
+ class={cls('color', 'inline-block size-2 rounded-full bg-[var(--color)]', classes.color)}
26
26
  style:--color={color}
27
27
  ></div>
28
28
  {/if}
@@ -9,6 +9,10 @@
9
9
  export let valueAlign: 'left' | 'right' | 'center' = 'left';
10
10
  export let color: string | undefined = undefined;
11
11
 
12
+ export let onclick: ((e: MouseEvent) => void) | undefined = undefined;
13
+ export let onpointerenter: ((e: PointerEvent) => void) | undefined = undefined;
14
+ export let onpointerleave: ((e: PointerEvent) => void) | undefined = undefined;
15
+
12
16
  export let classes: {
13
17
  root?: string;
14
18
  label?: string;
@@ -17,11 +21,17 @@
17
21
  } = {};
18
22
  </script>
19
23
 
20
- <div class={cls('contents', classes.root, $$props.class)} {...$$restProps}>
24
+ <div
25
+ class={cls('contents', classes.root, $$props.class)}
26
+ on:click={onclick}
27
+ on:pointerenter={onpointerenter}
28
+ on:pointerleave={onpointerleave}
29
+ {...$$restProps}
30
+ >
21
31
  <div class={cls('label', 'flex items-center gap-2 whitespace-nowrap', classes.label)}>
22
32
  {#if color}
23
33
  <div
24
- class={cls('color', 'inline-block size-2 rounded-full bg-[--color]', classes.color)}
34
+ class={cls('color', 'inline-block size-2 rounded-full bg-[var(--color)]', classes.color)}
25
35
  style:--color={color}
26
36
  ></div>
27
37
  {/if}
@@ -8,6 +8,9 @@ declare const __propDef: {
8
8
  format?: FormatType | undefined;
9
9
  valueAlign?: "left" | "right" | "center" | undefined;
10
10
  color?: string | undefined | undefined;
11
+ onclick?: ((e: MouseEvent) => void) | undefined | undefined;
12
+ onpointerenter?: ((e: PointerEvent) => void) | undefined | undefined;
13
+ onpointerleave?: ((e: PointerEvent) => void) | undefined | undefined;
11
14
  classes?: {
12
15
  root?: string;
13
16
  label?: string;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "author": "Sean Lynch <techniq35@gmail.com>",
5
5
  "license": "MIT",
6
6
  "repository": "techniq/layerchart",
7
- "version": "0.94.2",
7
+ "version": "0.95.0",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.27.12",
10
10
  "@mdi/js": "^7.4.47",
@@ -50,7 +50,7 @@
50
50
  "rehype-slug": "^6.0.0",
51
51
  "shapefile": "^0.6.6",
52
52
  "solar-calculator": "^0.3.0",
53
- "svelte": "^5.19.9",
53
+ "svelte": "5.19.4",
54
54
  "svelte-check": "^4.1.4",
55
55
  "svelte-json-tree": "^2.2.0",
56
56
  "svelte-ux": "^0.90.0",