layerchart 0.36.5 → 0.37.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.
Files changed (55) hide show
  1. package/dist/components/Arc.svelte +4 -2
  2. package/dist/components/Arc.svelte.d.ts +4 -2
  3. package/dist/components/Area.svelte +2 -2
  4. package/dist/components/Area.svelte.d.ts +2 -2
  5. package/dist/components/Axis.svelte +59 -10
  6. package/dist/components/Axis.svelte.d.ts +6 -3
  7. package/dist/components/Calendar.svelte +2 -2
  8. package/dist/components/Chart.svelte +74 -31
  9. package/dist/components/Chart.svelte.d.ts +33 -6
  10. package/dist/components/Circle.svelte +2 -2
  11. package/dist/components/Circle.svelte.d.ts +2 -2
  12. package/dist/components/ClipPath.svelte +1 -1
  13. package/dist/components/ClipPath.svelte.d.ts +2 -2
  14. package/dist/components/GeoCircle.svelte +1 -1
  15. package/dist/components/GeoCircle.svelte.d.ts +2 -2
  16. package/dist/components/GeoContext.svelte +31 -7
  17. package/dist/components/GeoContext.svelte.d.ts +2 -0
  18. package/dist/components/GeoPath.svelte +12 -10
  19. package/dist/components/GeoPath.svelte.d.ts +5 -4
  20. package/dist/components/GeoPoint.svelte +1 -3
  21. package/dist/components/GeoTile.svelte +1 -3
  22. package/dist/components/Group.svelte +18 -1
  23. package/dist/components/Group.svelte.d.ts +4 -2
  24. package/dist/components/HitCanvas.svelte +86 -0
  25. package/dist/components/HitCanvas.svelte.d.ts +32 -0
  26. package/dist/components/Hull.svelte +4 -4
  27. package/dist/components/Hull.svelte.d.ts +3 -3
  28. package/dist/components/Line.svelte +2 -2
  29. package/dist/components/Line.svelte.d.ts +2 -2
  30. package/dist/components/Link.svelte +4 -4
  31. package/dist/components/Link.svelte.d.ts +4 -4
  32. package/dist/components/Pie.svelte +9 -2
  33. package/dist/components/Rect.svelte +4 -4
  34. package/dist/components/Rect.svelte.d.ts +4 -4
  35. package/dist/components/Spline.svelte +2 -2
  36. package/dist/components/Spline.svelte.d.ts +2 -2
  37. package/dist/components/TooltipContext.svelte +21 -18
  38. package/dist/components/TooltipContext.svelte.d.ts +4 -4
  39. package/dist/components/{Transform.svelte → TransformContext.svelte} +87 -76
  40. package/dist/components/TransformContext.svelte.d.ts +111 -0
  41. package/dist/components/Voronoi.svelte +13 -5
  42. package/dist/components/Voronoi.svelte.d.ts +3 -3
  43. package/dist/components/index.d.ts +1 -1
  44. package/dist/components/index.js +1 -1
  45. package/dist/components/layout/Canvas.svelte +78 -0
  46. package/dist/components/layout/Canvas.svelte.d.ts +37 -0
  47. package/dist/components/layout/Svg.svelte +68 -0
  48. package/dist/components/layout/Svg.svelte.d.ts +32 -0
  49. package/dist/docs/TransformControls.svelte +4 -2
  50. package/dist/docs/TransformControls.svelte.d.ts +1 -2
  51. package/dist/docs/TransformDebug.svelte +21 -0
  52. package/dist/docs/TransformDebug.svelte.d.ts +16 -0
  53. package/dist/utils/event.d.ts +1 -1
  54. package/package.json +1 -1
  55. package/dist/components/Transform.svelte.d.ts +0 -76
@@ -15,6 +15,10 @@ export let initialY = y;
15
15
  * Center within chart
16
16
  */
17
17
  export let center = false;
18
+ /**
19
+ * Prevent `touchmove` default, which can interfer with `pointermove` when used with `Tooltip`, for example
20
+ */
21
+ export let preventTouchMove = false;
18
22
  export let spring = undefined;
19
23
  export let tweened = undefined;
20
24
  let tweened_x = motionStore(initialX, { spring, tweened });
@@ -29,6 +33,19 @@ $: if (center || x != null || y != null) {
29
33
  }
30
34
  </script>
31
35
 
32
- <g {transform} {...$$restProps} on:click on:mousemove on:mouseleave>
36
+ <g
37
+ {transform}
38
+ {...$$restProps}
39
+ on:click
40
+ on:pointerenter
41
+ on:pointermove
42
+ on:pointerleave
43
+ on:touchmove={(e) => {
44
+ if (preventTouchMove) {
45
+ // Prevent touch to not interfer with pointer
46
+ e.preventDefault();
47
+ }
48
+ }}
49
+ >
33
50
  <slot />
34
51
  </g>
@@ -8,13 +8,15 @@ declare const __propDef: {
8
8
  y?: number | undefined;
9
9
  initialY?: number | undefined;
10
10
  center?: boolean | "x" | "y" | undefined;
11
+ preventTouchMove?: boolean | undefined;
11
12
  spring?: boolean | Parameters<typeof springStore>[1];
12
13
  tweened?: boolean | Parameters<typeof tweenedStore>[1];
13
14
  };
14
15
  events: {
15
16
  click: MouseEvent;
16
- mousemove: MouseEvent;
17
- mouseleave: MouseEvent;
17
+ pointerenter: PointerEvent;
18
+ pointermove: PointerEvent;
19
+ pointerleave: PointerEvent;
18
20
  } & {
19
21
  [evt: string]: CustomEvent<any>;
20
22
  };
@@ -0,0 +1,86 @@
1
+ <script>import { beforeUpdate, createEventDispatcher, getContext, onMount, setContext } from 'svelte';
2
+ import { writable } from 'svelte/store';
3
+ import { scaleCanvas } from 'layercake';
4
+ import { cls } from 'svelte-ux';
5
+ import Canvas from './layout/Canvas.svelte';
6
+ const { width, height } = getContext('LayerCake');
7
+ export let context = undefined;
8
+ /** Show canvas for debugging */
9
+ export let debug = false;
10
+ const dispatch = createEventDispatcher();
11
+ const cntxt = {
12
+ ctx: writable({}),
13
+ };
14
+ onMount(() => {
15
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext#willreadfrequently
16
+ scaleCanvas(context, $width, $height);
17
+ });
18
+ $: cntxt.ctx.set(context);
19
+ setContext('canvas', cntxt);
20
+ function* rgbColorGenerator(step = 500) {
21
+ let nextColor = 1;
22
+ while (nextColor < 16777216) {
23
+ const rgb = [
24
+ nextColor & 0xff, // red
25
+ (nextColor & 0xff00) >> 8, // green
26
+ (nextColor & 0xff0000) >> 16, // blue
27
+ ];
28
+ nextColor += step;
29
+ yield `rgb(${rgb.join(',')})`;
30
+ }
31
+ }
32
+ $: colorGenerator = rgbColorGenerator();
33
+ // Reset color generator whenever updated (width/height) so always reusing same colors (and not exhausting)
34
+ beforeUpdate(() => {
35
+ colorGenerator = rgbColorGenerator();
36
+ });
37
+ const dataByColor = new Map();
38
+ function setColorData(color, data) {
39
+ dataByColor.set(color, data);
40
+ }
41
+ let activePointer = false;
42
+ function getPointerData(e) {
43
+ const { offsetX, offsetY } = e;
44
+ const dpr = window.devicePixelRatio ?? 1;
45
+ const imageData = context.getImageData(offsetX * dpr, offsetY * dpr, 1, 1);
46
+ const [r, g, b, a] = imageData.data;
47
+ const colorKey = `rgb(${r},${g},${b})`;
48
+ const data = dataByColor.get(colorKey);
49
+ return data;
50
+ }
51
+ function dispatchPointerMove(e) {
52
+ const data = getPointerData(e);
53
+ if (data) {
54
+ activePointer = true;
55
+ }
56
+ // Still dispatch with `undefined data` to hide tooltip, etc
57
+ dispatch('pointermove', { event: e, data });
58
+ }
59
+ </script>
60
+
61
+ <Canvas
62
+ bind:context
63
+ willReadFrequently
64
+ class={cls(
65
+ 'HitCanvas absolute w-full h-full border border-danger',
66
+ // '[image-rendering:pixelated]', // https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering
67
+ !debug && 'opacity-0'
68
+ )}
69
+ on:pointerenter={dispatchPointerMove}
70
+ on:pointermove={dispatchPointerMove}
71
+ on:pointerleave={() => (activePointer = false)}
72
+ on:pointerleave
73
+ on:touchmove={(e) => {
74
+ // Prevent touch to not interfer with pointer if over data
75
+ if (activePointer) {
76
+ e.preventDefault();
77
+ }
78
+ }}
79
+ on:click={(e) => {
80
+ const data = getPointerData(e);
81
+ if (data) {
82
+ dispatch('click', { event: e, data });
83
+ }
84
+ }}
85
+ />
86
+ <slot nextColor={() => colorGenerator.next().value} {setColorData}></slot>
@@ -0,0 +1,32 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ context?: CanvasRenderingContext2D | undefined;
5
+ /** Show canvas for debugging */ debug?: boolean | undefined;
6
+ };
7
+ events: {
8
+ pointerleave: PointerEvent;
9
+ pointermove: CustomEvent<{
10
+ event: PointerEvent;
11
+ data: any;
12
+ }>;
13
+ click: CustomEvent<{
14
+ event: MouseEvent;
15
+ data: any;
16
+ }>;
17
+ } & {
18
+ [evt: string]: CustomEvent<any>;
19
+ };
20
+ slots: {
21
+ default: {
22
+ nextColor: () => string | void;
23
+ setColorData: (color: string, data: any) => void;
24
+ };
25
+ };
26
+ };
27
+ export type HitCanvasProps = typeof __propDef.props;
28
+ export type HitCanvasEvents = typeof __propDef.events;
29
+ export type HitCanvasSlots = typeof __propDef.slots;
30
+ export default class HitCanvas extends SvelteComponentTyped<HitCanvasProps, HitCanvasEvents, HitCanvasSlots> {
31
+ }
32
+ export {};
@@ -32,8 +32,8 @@ $: points = (data ?? $flatData).map((d) => {
32
32
  geojson={polygon}
33
33
  {curve}
34
34
  class={cls('fill-transparent', classes.path)}
35
- on:mousemove={(e) => dispatch('mousemove', { event: e, points, polygon })}
36
- on:mouseleave
35
+ on:pointermove={(e) => dispatch('pointermove', { event: e, points, polygon })}
36
+ on:pointerleave
37
37
  on:click={(e) => dispatch('click', { points, polygon })}
38
38
  />
39
39
  {:else}
@@ -45,8 +45,8 @@ $: points = (data ?? $flatData).map((d) => {
45
45
  y={(d) => d[1]}
46
46
  {curve}
47
47
  class={cls('fill-transparent', classes.path)}
48
- on:mousemove={(e) => dispatch('mousemove', { event: e, points, polygon })}
49
- on:mouseleave
48
+ on:pointermove={(e) => dispatch('pointermove', { event: e, points, polygon })}
49
+ on:pointerleave
50
50
  on:click={(e) => dispatch('click', { points, polygon })}
51
51
  />
52
52
  {/if}
@@ -13,13 +13,13 @@ declare const __propDef: {
13
13
  } | undefined;
14
14
  };
15
15
  events: {
16
- mouseleave: MouseEvent;
16
+ pointerleave: PointerEvent;
17
17
  click: CustomEvent<{
18
18
  points: [number, number][];
19
19
  polygon: Delaunay.Polygon;
20
20
  }>;
21
- mousemove: CustomEvent<{
22
- event: MouseEvent;
21
+ pointermove: CustomEvent<{
22
+ event: PointerEvent;
23
23
  points: [number, number][];
24
24
  polygon: Delaunay.Polygon;
25
25
  }>;
@@ -31,6 +31,6 @@ $: tick().then(() => {
31
31
  class={cls($$props.stroke === undefined && 'stroke-surface-content')}
32
32
  {...$$restProps}
33
33
  on:click
34
- on:mousemove
35
- on:mouseleave
34
+ on:pointermove
35
+ on:pointerleave
36
36
  />
@@ -16,8 +16,8 @@ declare const __propDef: {
16
16
  };
17
17
  events: {
18
18
  click: MouseEvent;
19
- mousemove: MouseEvent;
20
- mouseleave: MouseEvent;
19
+ pointermove: PointerEvent;
20
+ pointerleave: PointerEvent;
21
21
  } & {
22
22
  [evt: string]: CustomEvent<any>;
23
23
  };
@@ -31,9 +31,9 @@ $: {
31
31
  d={$tweened_d}
32
32
  fill="none"
33
33
  on:click
34
- on:mouseover
35
- on:mousemove
36
- on:mouseout
37
- on:mouseleave
34
+ on:pointerover
35
+ on:pointermove
36
+ on:pointerout
37
+ on:pointerleave
38
38
  {...$$restProps}
39
39
  />
@@ -15,10 +15,10 @@ declare const __propDef: {
15
15
  };
16
16
  events: {
17
17
  click: MouseEvent;
18
- mouseover: MouseEvent;
19
- mousemove: MouseEvent;
20
- mouseout: MouseEvent;
21
- mouseleave: MouseEvent;
18
+ pointerover: PointerEvent;
19
+ pointermove: PointerEvent;
20
+ pointerout: PointerEvent;
21
+ pointerleave: PointerEvent;
22
22
  } & {
23
23
  [evt: string]: CustomEvent<any>;
24
24
  };
@@ -87,8 +87,15 @@ $: coords = {
87
87
  {cornerRadius}
88
88
  {offset}
89
89
  fill={$config.r ? $rGet(arc.data) : null}
90
- on:mousemove={(e) => tooltip?.show(e, arc.data)}
91
- on:mouseleave={(e) => tooltip?.hide()}
90
+ on:pointerenter={(e) => tooltip?.show(e, arc.data)}
91
+ on:pointermove={(e) => tooltip?.show(e, arc.data)}
92
+ on:pointerleave={(e) => tooltip?.hide()}
93
+ on:touchmove={(e) => {
94
+ if (tooltip) {
95
+ // Prevent touch to not interfer with pointer when using tooltip
96
+ e.preventDefault();
97
+ }
98
+ }}
92
99
  />
93
100
  {/each}
94
101
  </slot>
@@ -32,8 +32,8 @@ $: tick().then(() => {
32
32
  class={cls($$props.fill == null && 'fill-surface-content')}
33
33
  {...$$restProps}
34
34
  on:click
35
- on:mouseover
36
- on:mousemove
37
- on:mouseout
38
- on:mouseleave
35
+ on:pointerover
36
+ on:pointermove
37
+ on:pointerout
38
+ on:pointerleave
39
39
  />
@@ -20,10 +20,10 @@ declare const __propDef: {
20
20
  };
21
21
  events: {
22
22
  click: MouseEvent;
23
- mouseover: MouseEvent;
24
- mousemove: MouseEvent;
25
- mouseout: MouseEvent;
26
- mouseleave: MouseEvent;
23
+ pointerover: PointerEvent;
24
+ pointermove: PointerEvent;
25
+ pointerout: PointerEvent;
26
+ pointerleave: PointerEvent;
27
27
  } & {
28
28
  [evt: string]: CustomEvent<any>;
29
29
  };
@@ -109,8 +109,8 @@ $: {
109
109
  class={cls('path-line fill-none', !$$props.stroke && 'stroke-surface-content', $$props.class)}
110
110
  in:drawTransition|global={typeof draw === 'object' ? draw : undefined}
111
111
  on:click
112
- on:mousemove
113
- on:mouseleave
112
+ on:pointermove
113
+ on:pointerleave
114
114
  bind:this={pathEl}
115
115
  />
116
116
 
@@ -17,8 +17,8 @@ declare const __propDef: {
17
17
  };
18
18
  events: {
19
19
  click: MouseEvent;
20
- mousemove: MouseEvent;
21
- mouseleave: MouseEvent;
20
+ pointermove: PointerEvent;
21
+ pointerleave: PointerEvent;
22
22
  } & {
23
23
  [evt: string]: CustomEvent<any>;
24
24
  };
@@ -45,7 +45,7 @@ export let mode = 'manual';
45
45
  * @type {'closest' | 'left' | 'right'}
46
46
  */
47
47
  export let findTooltipData = 'closest';
48
- /** Similar to d3-selection's raise, re-insert the event.target as the last child of its parent, so to be the top-most element */
48
+ /** 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 */
49
49
  export let raiseTarget = false;
50
50
  /** quadtree search radius
51
51
  * @type {number}
@@ -105,11 +105,11 @@ function findData(previousValue, currentValue, valueAtPoint, accessor) {
105
105
  return currentValue;
106
106
  }
107
107
  }
108
- function showTooltip(event, tooltipData) {
108
+ function showTooltip(e, tooltipData) {
109
109
  // Cancel hiding tooltip if from previous event loop
110
110
  clearTimeout(hideTimeoutId);
111
- const referenceNode = event.target.closest('.layercake-container');
112
- const point = localPoint(referenceNode, event);
111
+ const referenceNode = e.target.closest('.layercake-container');
112
+ const point = localPoint(referenceNode, e);
113
113
  const localX = point?.x ?? 0;
114
114
  const localY = point?.y ?? 0;
115
115
  // If tooltipData not provided already (voronoi, etc), attempt to find it
@@ -121,7 +121,7 @@ function showTooltip(event, tooltipData) {
121
121
  break;
122
122
  }
123
123
  case 'bisect-band': {
124
- // `x` and `y` values at mouse/touch coordinate
124
+ // `x` and `y` values at pointer coordinate
125
125
  const xValueAtPoint = scaleInvert($xScale, localX);
126
126
  const yValueAtPoint = scaleInvert($yScale, localY);
127
127
  if (isScaleBand($xScale)) {
@@ -146,7 +146,7 @@ function showTooltip(event, tooltipData) {
146
146
  break;
147
147
  }
148
148
  case 'bisect-x': {
149
- // `x` value at mouse/touch coordinate
149
+ // `x` value at pointer coordinate
150
150
  const xValueAtPoint = scaleInvert($xScale, localX - $padding.left);
151
151
  const index = bisectX($flatData, xValueAtPoint, 1);
152
152
  const previousValue = $flatData[index - 1];
@@ -155,7 +155,7 @@ function showTooltip(event, tooltipData) {
155
155
  break;
156
156
  }
157
157
  case 'bisect-y': {
158
- // `y` value at mouse/touch coordinate
158
+ // `y` value at pointer coordinate
159
159
  const yValueAtPoint = scaleInvert($yScale, localY - $padding.top);
160
160
  const index = bisectY($flatData, yValueAtPoint, 1);
161
161
  const previousValue = $flatData[index - 1];
@@ -167,7 +167,7 @@ function showTooltip(event, tooltipData) {
167
167
  }
168
168
  if (tooltipData) {
169
169
  if (raiseTarget) {
170
- raise(event.target);
170
+ raise(e.target);
171
171
  }
172
172
  $tooltip = {
173
173
  ...$tooltip,
@@ -264,7 +264,6 @@ $: if (mode === 'bounds' || mode === 'band') {
264
264
  }
265
265
  })
266
266
  .sort(sortFunc('x'));
267
- // console.log({ rects });
268
267
  }
269
268
  </script>
270
269
 
@@ -275,11 +274,13 @@ $: if (mode === 'bounds' || mode === 'band') {
275
274
  <div
276
275
  style:width="{$width}px"
277
276
  style:height="{$height}px"
278
- class={cls('tooltip-trigger absolute', debug && 'bg-danger/10 outline outline-danger')}
279
- on:touchstart={showTooltip}
280
- on:touchmove={showTooltip}
281
- on:mousemove={showTooltip}
282
- on:mouseleave={hideTooltip}
277
+ class={cls(
278
+ 'tooltip-trigger absolute touch-none',
279
+ debug && 'bg-danger/10 outline outline-danger'
280
+ )}
281
+ on:pointerenter={showTooltip}
282
+ on:pointermove={showTooltip}
283
+ on:pointerleave={hideTooltip}
283
284
  on:click={(e) => {
284
285
  onClick({ data: $tooltip?.data });
285
286
  }}
@@ -288,8 +289,9 @@ $: if (mode === 'bounds' || mode === 'band') {
288
289
  {:else if mode === 'voronoi'}
289
290
  <Svg>
290
291
  <Voronoi
291
- on:mousemove={(e) => showTooltip(e.detail.event, e.detail.data)}
292
- on:mouseleave={hideTooltip}
292
+ on:pointerenter={(e) => showTooltip(e.detail.event, e.detail.data)}
293
+ on:pointermove={(e) => showTooltip(e.detail.event, e.detail.data)}
294
+ on:pointerleave={hideTooltip}
293
295
  on:click={(e) => {
294
296
  onClick({ data: e.detail.data });
295
297
  }}
@@ -306,8 +308,9 @@ $: if (mode === 'bounds' || mode === 'band') {
306
308
  width={rect.width}
307
309
  height={rect.height}
308
310
  class={cls(debug ? 'fill-danger/10 stroke-danger' : 'fill-transparent')}
309
- on:mousemove={(e) => showTooltip(e, rect.data)}
310
- on:mouseleave={hideTooltip}
311
+ on:pointerenter={(e) => showTooltip(e, rect.data)}
312
+ on:pointermove={(e) => showTooltip(e, rect.data)}
313
+ on:pointerleave={hideTooltip}
311
314
  on:click={(e) => {
312
315
  onClick({ data: rect.data });
313
316
  }}
@@ -5,8 +5,8 @@ export type TooltipContextValue = {
5
5
  x: number;
6
6
  y: number;
7
7
  data: any;
8
- show(event: MouseEvent | TouchEvent, tooltipData?: any): any;
9
- hide(event?: MouseEvent | TouchEvent): any;
8
+ show(e: PointerEvent, tooltipData?: any): void;
9
+ hide(e?: PointerEvent): void;
10
10
  };
11
11
  export type TooltipContext = Readable<TooltipContextValue>;
12
12
  export declare function tooltipContext(): TooltipContext;
@@ -18,7 +18,7 @@ declare const __propDef: {
18
18
  /**
19
19
  * @type {'closest' | 'left' | 'right'}
20
20
  */ findTooltipData?: "left" | "right" | "closest" | undefined;
21
- /** Similar to d3-selection's raise, re-insert the event.target as the last child of its parent, so to be the top-most element */ raiseTarget?: boolean | undefined;
21
+ /** 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 | undefined;
22
22
  /** quadtree search radius
23
23
  * @type {number}
24
24
  */ radius?: number | undefined;
@@ -36,7 +36,7 @@ declare const __propDef: {
36
36
  y: number;
37
37
  x: number;
38
38
  data: null;
39
- show: (event: MouseEvent | TouchEvent, tooltipData?: any) => void;
39
+ show: (e: PointerEvent, tooltipData?: any) => void;
40
40
  hide: () => void;
41
41
  };
42
42
  };