layerchart 0.38.1 → 0.38.3

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.
@@ -4,10 +4,11 @@
4
4
  // See: https://github.com/carbon-design-system/sveld/issues/104
5
5
  import { LayerCake,
6
6
  // Canvas as _Canvas,
7
- Html as _Html,
7
+ // Html as _Html,
8
8
  // Svg as _Svg,
9
9
  WebGL as _WebGL, } from 'layercake';
10
10
  import _Canvas from './layout/Canvas.svelte';
11
+ import _Html from './layout/Html.svelte';
11
12
  import _Svg from './layout/Svg.svelte';
12
13
  export const Canvas = _Canvas;
13
14
  export const Html = _Html;
@@ -122,6 +123,7 @@ onMount(() => {
122
123
  {#key isMounted}
123
124
  <TransformContext
124
125
  bind:this={transformContext}
126
+ mode={transform?.mode ?? geo?.applyTransform?.length ? 'manual' : 'none'}
125
127
  initialTranslate={initialTransform?.translate}
126
128
  initialScale={initialTransform?.scale}
127
129
  processTranslate={geo
@@ -1,6 +1,7 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
- import { Html as _Html, WebGL as _WebGL } from 'layercake';
2
+ import { WebGL as _WebGL } from 'layercake';
3
3
  import _Canvas from './layout/Canvas.svelte';
4
+ import _Html from './layout/Html.svelte';
4
5
  import _Svg from './layout/Svg.svelte';
5
6
  export declare const Canvas: typeof _Canvas;
6
7
  export declare const Html: typeof _Html;
@@ -50,24 +51,15 @@ declare const __propDef: {
50
51
  projection: import("d3-geo").GeoProjection | import("d3-geo").GeoIdentityTransform;
51
52
  transform: {
52
53
  scale: number;
53
- setScale: ((new_value: number, opts?: import("svelte/motion").SpringUpdateOpts | undefined) => Promise<void>) | ((value: number, opts?: import("svelte/motion").TweenedOptions<number> | undefined) => Promise<void>) | ((this: void, value: number) => void);
54
+ setScale: (value: number, options?: import("../stores/motionStore").MotionOptions | undefined) => void;
54
55
  translate: {
55
56
  x: number;
56
57
  y: number;
57
58
  };
58
- setTranslate: ((new_value: {
59
+ setTranslate: (point: {
59
60
  x: number;
60
61
  y: number;
61
- }, opts?: import("svelte/motion").SpringUpdateOpts | undefined) => Promise<void>) | ((value: {
62
- x: number;
63
- y: number;
64
- }, opts?: import("svelte/motion").TweenedOptions<{
65
- x: number;
66
- y: number;
67
- }> | undefined) => Promise<void>) | ((this: void, value: {
68
- x: number;
69
- y: number;
70
- }) => void);
62
+ }, options?: import("../stores/motionStore").MotionOptions | undefined) => void;
71
63
  zoomTo: (center: {
72
64
  x: number;
73
65
  y: number;
@@ -80,7 +72,7 @@ declare const __propDef: {
80
72
  tooltip: {
81
73
  y: number;
82
74
  x: number;
83
- data: null; /** Props passed to TransformContext */
75
+ data: null;
84
76
  show: (e: PointerEvent, tooltipData?: any) => void;
85
77
  hide: () => void;
86
78
  };
@@ -32,7 +32,7 @@ function* rgbColorGenerator(step = 500) {
32
32
  }
33
33
  $: colorGenerator = rgbColorGenerator();
34
34
  // Reset color generator whenever updated (width/height) so always reusing same colors (and not exhausting)
35
- const { translate, scale } = transformContext();
35
+ const { translate, scale, dragging } = transformContext();
36
36
  $: {
37
37
  $width;
38
38
  $height;
@@ -89,4 +89,8 @@ function dispatchPointerMove(e) {
89
89
  }
90
90
  }}
91
91
  />
92
- <slot nextColor={() => colorGenerator.next().value} {setColorData}></slot>
92
+
93
+ <!-- Do not render while dragging to improve interaction performance -->
94
+ {#if !$dragging}
95
+ <slot nextColor={() => colorGenerator.next().value} {setColorData}></slot>
96
+ {/if}
@@ -14,7 +14,7 @@ declare const __propDef: {
14
14
  props: {
15
15
  /**
16
16
  * @type {'bisect-x' | 'bisect-y' | 'band' | 'bisect-band' | 'bounds' | 'voronoi' | 'quadtree' | 'manual'}
17
- */ mode?: "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree" | "manual" | undefined;
17
+ */ mode?: "manual" | "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree" | undefined;
18
18
  /**
19
19
  * @type {'closest' | 'left' | 'right'}
20
20
  */ findTooltipData?: "left" | "right" | "closest" | undefined;
@@ -1,10 +1,15 @@
1
1
  <script context="module">import { getContext, setContext } from 'svelte';
2
- import { writable } from 'svelte/store';
2
+ import { writable, derived } from 'svelte/store';
3
3
  export const transformContextKey = Symbol();
4
+ const defaultTranslate = writable({ x: 0, y: 0 });
5
+ const defaultScale = writable(1);
4
6
  const defaultContext = {
5
7
  mode: 'none',
6
- scale: writable(1),
7
- translate: writable({ x: 0, y: 0 }),
8
+ scale: defaultScale,
9
+ setScale: defaultScale.set,
10
+ translate: defaultTranslate,
11
+ setTranslate: defaultTranslate.set,
12
+ moving: writable(false),
8
13
  dragging: writable(false),
9
14
  reset: () => { },
10
15
  zoomIn: () => { },
@@ -21,7 +26,7 @@ function setTransformContext(transform) {
21
26
  </script>
22
27
 
23
28
  <script>import { createEventDispatcher } from 'svelte';
24
- import { motionStore } from '../stores/motionStore.js';
29
+ import { motionStore, motionFinishHandler } from '../stores/motionStore.js';
25
30
  const { width, height } = getContext('LayerCake');
26
31
  export let mode = 'none';
27
32
  export let translateOnScale = false;
@@ -33,7 +38,7 @@ export let processTranslate = (x, y, deltaX, deltaY, scale) => {
33
38
  y: y + deltaY / scale,
34
39
  };
35
40
  };
36
- /** Disable pointer events including move/dragging */
41
+ /** Disable pointer events including move/dragging. Useful for `mode="canvas" but only want zoomTo() interactions */
37
42
  export let disablePointer = false;
38
43
  /** Action to take during wheel scroll */
39
44
  export let scroll = 'none';
@@ -76,19 +81,8 @@ export function zoomTo(center, rect) {
76
81
  $scale = $width < $height ? $width / rect.width : $height / rect.height;
77
82
  }
78
83
  }
79
- setTransformContext({
80
- mode,
81
- scale,
82
- translate,
83
- dragging,
84
- reset,
85
- zoomIn,
86
- zoomOut,
87
- translateCenter,
88
- zoomTo,
89
- });
90
84
  function onPointerDown(e) {
91
- if (disablePointer)
85
+ if (mode === 'none' || disablePointer)
92
86
  return;
93
87
  e.preventDefault();
94
88
  pointerDown = true;
@@ -111,11 +105,12 @@ function onPointerMove(e) {
111
105
  if ($dragging) {
112
106
  e.stopPropagation(); // Stop tooltip from trigging (along with `capture: true`)
113
107
  e.currentTarget.setPointerCapture(e.pointerId);
114
- translate.set(processTranslate(startTranslate.x, startTranslate.y, deltaX, deltaY, $scale), spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
108
+ setTranslate(processTranslate(startTranslate.x, startTranslate.y, deltaX, deltaY, $scale), spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
115
109
  }
116
110
  }
117
111
  function onPointerUp(e) {
118
112
  pointerDown = false;
113
+ $dragging = false;
119
114
  dispatch('dragend');
120
115
  }
121
116
  function onClick(e) {
@@ -125,13 +120,13 @@ function onClick(e) {
125
120
  }
126
121
  }
127
122
  function onDoubleClick(e) {
128
- if (disablePointer)
123
+ if (mode === 'none' || disablePointer)
129
124
  return;
130
125
  const point = localPoint(e);
131
126
  scaleTo(e.shiftKey ? 0.5 : 2, point);
132
127
  }
133
128
  function onWheel(e) {
134
- if (scroll === 'none' || disablePointer)
129
+ if (mode === 'none' || disablePointer || scroll === 'none')
135
130
  return;
136
131
  e.preventDefault();
137
132
  const point = (startPoint = localPoint(e));
@@ -152,7 +147,7 @@ function onWheel(e) {
152
147
  function scaleTo(value, point, options = undefined) {
153
148
  const currentScale = $scale;
154
149
  const newScale = $scale * value;
155
- scale.set(newScale, options);
150
+ setScale(newScale, options);
156
151
  if (translateOnScale) {
157
152
  // Translate towards point (ex. mouse cursor/center) while zooming in/out
158
153
  const invertTransformPoint = {
@@ -163,9 +158,18 @@ function scaleTo(value, point, options = undefined) {
163
158
  x: point.x - invertTransformPoint.x * newScale,
164
159
  y: point.y - invertTransformPoint.y * newScale,
165
160
  };
166
- translate.set(newTranslate, options);
161
+ setTranslate(newTranslate, options);
167
162
  }
168
163
  }
164
+ const translating = motionFinishHandler();
165
+ const scaling = motionFinishHandler();
166
+ const moving = derived([dragging, translating, scaling], ([dragging, translating, scaling]) => dragging || translating || scaling);
167
+ export function setTranslate(point, options) {
168
+ translating.handle(translate.set(point, options));
169
+ }
170
+ export function setScale(value, options) {
171
+ scaling.handle(scale.set(value, options));
172
+ }
169
173
  function localPoint(e) {
170
174
  return {
171
175
  x: e.offsetX,
@@ -178,6 +182,20 @@ $: viewportCenter = {
178
182
  y: center.y - $translate.y,
179
183
  };
180
184
  $: dispatch('transform', { scale: $scale, translate: $translate });
185
+ setTransformContext({
186
+ mode,
187
+ scale,
188
+ setScale,
189
+ translate,
190
+ setTranslate,
191
+ dragging,
192
+ moving,
193
+ reset,
194
+ zoomIn,
195
+ zoomOut,
196
+ translateCenter,
197
+ zoomTo,
198
+ });
181
199
  </script>
182
200
 
183
201
  <div
@@ -202,9 +220,9 @@ $: dispatch('transform', { scale: $scale, translate: $translate });
202
220
  <slot
203
221
  transform={{
204
222
  scale: $scale,
205
- setScale: scale.set,
223
+ setScale,
206
224
  translate: $translate,
207
- setTranslate: translate.set,
225
+ setTranslate,
208
226
  zoomTo,
209
227
  reset,
210
228
  }}
@@ -2,12 +2,18 @@ import { SvelteComponentTyped } from "svelte";
2
2
  import { type Readable, type Writable } from 'svelte/store';
3
3
  export declare const transformContextKey: unique symbol;
4
4
  export type TransformContextValue = {
5
- mode: 'canvas' | 'none';
5
+ mode: 'canvas' | 'manual' | 'none';
6
6
  scale: Writable<number>;
7
+ setScale(value: number, options?: MotionOptions): void;
7
8
  translate: Writable<{
8
9
  x: number;
9
10
  y: number;
10
11
  }>;
12
+ setTranslate(point: {
13
+ x: number;
14
+ y: number;
15
+ }, options?: MotionOptions): void;
16
+ moving: Readable<boolean>;
11
17
  dragging: Readable<boolean>;
12
18
  reset(): void;
13
19
  zoomIn(): void;
@@ -23,10 +29,10 @@ export type TransformContextValue = {
23
29
  };
24
30
  export type TransformContext = TransformContextValue;
25
31
  export declare function transformContext(): TransformContext;
26
- import { motionStore } from '../stores/motionStore.js';
32
+ import { motionStore, type MotionOptions } from '../stores/motionStore.js';
27
33
  declare const __propDef: {
28
34
  props: {
29
- mode?: "none" | "canvas" | undefined;
35
+ mode?: "none" | "canvas" | "manual" | undefined;
30
36
  translateOnScale?: boolean | undefined;
31
37
  spring?: boolean | Parameters<typeof motionStore>[1]['spring'];
32
38
  tweened?: boolean | Parameters<typeof motionStore>[1]['tweened'];
@@ -34,7 +40,7 @@ declare const __propDef: {
34
40
  x: number;
35
41
  y: number;
36
42
  }) | undefined;
37
- /** Disable pointer events including move/dragging */ disablePointer?: boolean | undefined;
43
+ /** Disable pointer events including move/dragging. Useful for `mode="canvas" but only want zoomTo() interactions */ disablePointer?: boolean | undefined;
38
44
  /** Action to take during wheel scroll */ scroll?: "none" | "scale" | "translate" | undefined;
39
45
  /** Distance/threshold to consider drag vs click (disable click propagation) */ clickDistance?: number | undefined;
40
46
  initialTranslate?: {
@@ -64,6 +70,11 @@ declare const __propDef: {
64
70
  width: number;
65
71
  height: number;
66
72
  }) => void) | undefined;
73
+ setTranslate?: ((point: {
74
+ x: number;
75
+ y: number;
76
+ }, options?: MotionOptions) => void) | undefined;
77
+ setScale?: ((value: number, options?: MotionOptions) => void) | undefined;
67
78
  };
68
79
  events: {
69
80
  click: MouseEvent;
@@ -86,24 +97,15 @@ declare const __propDef: {
86
97
  default: {
87
98
  transform: {
88
99
  scale: number;
89
- setScale: ((new_value: number, opts?: import("svelte/motion").SpringUpdateOpts | undefined) => Promise<void>) | ((value: number, opts?: import("svelte/motion").TweenedOptions<number> | undefined) => Promise<void>) | ((this: void, value: number) => void);
100
+ setScale: (value: number, options?: MotionOptions) => void;
90
101
  translate: {
91
102
  x: number;
92
103
  y: number;
93
104
  };
94
- setTranslate: ((new_value: {
95
- x: number;
96
- y: number;
97
- }, opts?: import("svelte/motion").SpringUpdateOpts | undefined) => Promise<void>) | ((value: {
105
+ setTranslate: (point: {
98
106
  x: number;
99
107
  y: number;
100
- }, opts?: import("svelte/motion").TweenedOptions<{
101
- x: number;
102
- y: number;
103
- }> | undefined) => Promise<void>) | ((this: void, value: {
104
- x: number;
105
- y: number;
106
- }) => void);
108
+ }, options?: MotionOptions) => void;
107
109
  zoomTo: (center: {
108
110
  x: number;
109
111
  y: number;
@@ -142,5 +144,10 @@ export default class TransformContext extends SvelteComponentTyped<TransformCont
142
144
  width: number;
143
145
  height: number;
144
146
  } | undefined) => void;
147
+ get setTranslate(): (point: {
148
+ x: number;
149
+ y: number;
150
+ }, options?: MotionOptions | undefined) => void;
151
+ get setScale(): (value: number, options?: MotionOptions | undefined) => void;
145
152
  }
146
153
  export {};
@@ -58,7 +58,7 @@ setContext('canvas', { ctx });
58
58
  'layercake-layout-canvas',
59
59
  'absolute w-full h-full',
60
60
  pointerEvents === false && 'pointer-events-none',
61
- $$restProps.class
61
+ $$props.class
62
62
  )}
63
63
  aria-label={label}
64
64
  aria-labelledby={labelledBy}
@@ -0,0 +1,41 @@
1
+ <script>import { getContext } from 'svelte';
2
+ import { cls } from 'svelte-ux';
3
+ /** The layer's outermost `<div>` tag. Useful for bindings. */
4
+ export let element = undefined;
5
+ /** The layer's z-index. */
6
+ export let zIndex = undefined;
7
+ /** Set this to `false` to set `pointer-events: none;` on the entire layer. */
8
+ export let pointerEvents = undefined;
9
+ /** A string passed to the `aria-role` on the `<div>` tag. This is `undefined` by default but will be set by default to `'figure'` if `label`, `labelledby` or `describedby` is set. That default will be overridden by whatever is passed in. */
10
+ export let role = undefined;
11
+ /** A string passed to the `aria-label` property on the `<div>` tag. */
12
+ export let label = undefined;
13
+ /** A string passed to the `aria-labelledby property` on the `<div>` tag. */
14
+ export let labelledBy = undefined;
15
+ /** A string passed to the `aria-describedby` property on the `<div>` tag. */
16
+ export let describedBy = undefined;
17
+ const { padding } = getContext('LayerCake');
18
+ $: roleVal = role || (label || labelledBy || describedBy ? 'figure' : undefined);
19
+ </script>
20
+
21
+ <div
22
+ bind:this={element}
23
+ class={cls(
24
+ 'layercake-layout-html',
25
+ 'absolute top-0 left-0',
26
+ pointerEvents === false && 'pointer-events-none',
27
+ $$props.class
28
+ )}
29
+ style:z-index={zIndex}
30
+ style:pointer-events={pointerEvents === false ? 'none' : null}
31
+ style:top="{$padding.top}px"
32
+ style:bottom="{$padding.bottom}px"
33
+ style:left="{$padding.left}px"
34
+ style:right="{$padding.right}px"
35
+ role={roleVal}
36
+ aria-label={label}
37
+ aria-labelledby={labelledBy}
38
+ aria-describedby={describedBy}
39
+ >
40
+ <slot {element}></slot>
41
+ </div>
@@ -0,0 +1,27 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ [x: string]: any;
5
+ element?: HTMLDivElement | undefined;
6
+ zIndex?: undefined;
7
+ pointerEvents?: boolean | undefined;
8
+ role?: string | undefined;
9
+ label?: string | undefined;
10
+ labelledBy?: string | undefined;
11
+ describedBy?: string | undefined;
12
+ };
13
+ events: {
14
+ [evt: string]: CustomEvent<any>;
15
+ };
16
+ slots: {
17
+ default: {
18
+ element: HTMLDivElement | undefined;
19
+ };
20
+ };
21
+ };
22
+ export type HtmlProps = typeof __propDef.props;
23
+ export type HtmlEvents = typeof __propDef.events;
24
+ export type HtmlSlots = typeof __propDef.slots;
25
+ export default class Html extends SvelteComponentTyped<HtmlProps, HtmlEvents, HtmlSlots> {
26
+ }
27
+ export {};
@@ -41,7 +41,8 @@ $: if (mode === 'canvas') {
41
41
  class={cls(
42
42
  'layercake-layout-svg',
43
43
  'absolute top-0 left-0 overflow-visible',
44
- pointerEvents === false && 'pointer-events-none'
44
+ pointerEvents === false && 'pointer-events-none',
45
+ $$props.class
45
46
  )}
46
47
  aria-label={label}
47
48
  aria-labelledby={labelledBy}
@@ -1,15 +1,16 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
- /** The layer's `<svg>` tag. Useful for bindings. */ element?: SVGElement | undefined;
5
- /** The layer's `<g>` tag. Useful for bindings. */ innerElement?: SVGGElement | undefined;
6
- /** The layer's z-index. */ zIndex?: undefined;
7
- /** Set this to `false` to set `pointer-events: none;` on the entire layer. */ pointerEvents?: boolean | undefined;
8
- /** A string passed to the `viewBox` property on the `<svg>` tag. */ viewBox?: string | undefined;
9
- /** A string passed to the `aria-label` property on the `<svg>` tag. */ label?: string | undefined;
10
- /** A string passed to the `aria-labelledby property` on the `<svg>` tag. */ labelledBy?: string | undefined;
11
- /** A string passed to the `aria-describedby` property on the `<svg>` tag. */ describedBy?: string | undefined;
12
- /** Shorthand to set the contents of `<title></title>` for accessibility. You can also set arbitrary HTML via the "title" slot but this is a convenient shorthand. If you use the "title" slot, this prop is ignored. */ title?: string | undefined;
4
+ [x: string]: any;
5
+ element?: SVGElement | undefined;
6
+ innerElement?: SVGGElement | undefined;
7
+ zIndex?: undefined;
8
+ pointerEvents?: boolean | undefined;
9
+ viewBox?: string | undefined;
10
+ label?: string | undefined;
11
+ labelledBy?: string | undefined;
12
+ describedBy?: string | undefined;
13
+ title?: string | undefined;
13
14
  };
14
15
  events: {
15
16
  click: MouseEvent;
@@ -25,3 +25,7 @@ export declare function resolveOptions(prop: string, options: PropMotionOptions)
25
25
  spring: any;
26
26
  tweened: any;
27
27
  };
28
+ export declare function motionFinishHandler(): {
29
+ subscribe: (this: void, run: import("svelte/store").Subscriber<boolean>, invalidate?: import("svelte/store").Invalidator<boolean> | undefined) => import("svelte/store").Unsubscriber;
30
+ handle: (promise: Promise<void> | void) => void;
31
+ };
@@ -35,3 +35,26 @@ export function resolveOptions(prop, options) {
35
35
  : false,
36
36
  };
37
37
  }
38
+ export function motionFinishHandler() {
39
+ let latestIndex = 0;
40
+ const moving = writable(false);
41
+ const handle = function (promise) {
42
+ latestIndex += 1;
43
+ if (!promise) {
44
+ // The store returned nothing, which means that the motion store is immediate.
45
+ moving.set(false);
46
+ return;
47
+ }
48
+ let thisIndex = latestIndex;
49
+ moving.set(true);
50
+ promise.then(() => {
51
+ if (thisIndex === latestIndex) {
52
+ moving.set(false);
53
+ }
54
+ });
55
+ };
56
+ return {
57
+ subscribe: moving.subscribe,
58
+ handle,
59
+ };
60
+ }
@@ -5,3 +5,4 @@ export * from './math.js';
5
5
  export * from './pivot.js';
6
6
  export * from './stack.js';
7
7
  export * from './ticks.js';
8
+ export * from './threshold.js';
@@ -5,3 +5,4 @@ export * from './math.js';
5
5
  export * from './pivot.js';
6
6
  export * from './stack.js';
7
7
  export * from './ticks.js';
8
+ export * from './threshold.js';
@@ -5,7 +5,7 @@ import { scaleTime } from 'd3-scale';
5
5
  * https://observablehq.com/@d3/d3-bin-time-thresholds
6
6
  */
7
7
  export function thresholdTime(n) {
8
- // TODO: Unable to satifiy `ThresholdNumberArrayGenerator<Value extends number>` with `Date`
8
+ // TODO: Unable to satisfy `ThresholdNumberArrayGenerator<Value extends number>` with `Date`
9
9
  return (data, min, max) => {
10
10
  return scaleTime().domain([min, max]).ticks(n);
11
11
  };
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.38.1",
7
+ "version": "0.38.3",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.27.5",
10
10
  "@mdi/js": "^7.4.47",
@@ -87,7 +87,7 @@
87
87
  "lodash-es": "^4.17.21",
88
88
  "posthog-js": "^1.136.2",
89
89
  "shapefile": "^0.6.6",
90
- "svelte-ux": "^0.66.0",
90
+ "svelte-ux": "^0.66.4",
91
91
  "topojson-client": "^3.1.0"
92
92
  },
93
93
  "peerDependencies": {