layerchart 0.97.0 → 0.98.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.
@@ -42,13 +42,12 @@
42
42
 
43
43
  <script lang="ts">
44
44
  import { extent, min, max } from 'd3-array';
45
- import { clamp } from '@layerstack/utils';
45
+ import { clamp, localPoint } from '@layerstack/utils';
46
46
  import { cls } from '@layerstack/tailwind';
47
47
  import { Logger } from '@layerstack/utils';
48
48
 
49
49
  import { chartContext } from './ChartContext.svelte';
50
50
 
51
- import { localPoint } from '../utils/event.js';
52
51
  import type { DomainType } from '../utils/scales.js';
53
52
  import { add } from '../utils/math.js';
54
53
  import type { HTMLAttributes } from 'svelte/elements';
@@ -143,7 +142,7 @@
143
142
  logger.debug('drag start');
144
143
  e.stopPropagation();
145
144
 
146
- const startPoint = localPoint(rootEl, e);
145
+ const startPoint = localPoint(e, rootEl);
147
146
 
148
147
  if (
149
148
  startPoint &&
@@ -165,7 +164,7 @@
165
164
  onbrushstart({ xDomain, yDomain });
166
165
 
167
166
  const onPointerMove = (e: PointerEvent) => {
168
- const currentPoint = localPoint(rootEl, e);
167
+ const currentPoint = localPoint(e, rootEl);
169
168
  fn(start, {
170
169
  x: $xScale.invert?.(currentPoint?.x ?? 0),
171
170
  y: $yScale.invert?.(currentPoint?.y ?? 0),
@@ -175,7 +174,7 @@
175
174
  };
176
175
 
177
176
  const onPointerUp = (e: PointerEvent) => {
178
- const currentPoint = localPoint(rootEl, e);
177
+ const currentPoint = localPoint(e, rootEl);
179
178
  const xPointDelta = Math.abs((startPoint?.x ?? 0) - (currentPoint?.x ?? 0));
180
179
  const yPointDelta = Math.abs((startPoint?.y ?? 0) - (currentPoint?.y ?? 0));
181
180
 
@@ -423,7 +423,7 @@
423
423
  initialTranslate={initialTransform?.translate}
424
424
  initialScale={initialTransform?.scale}
425
425
  processTranslate={geo
426
- ? (x, y, deltaX, deltaY, scale) => {
426
+ ? (x, y, deltaX, deltaY) => {
427
427
  if (geo.applyTransform?.includes('rotate')) {
428
428
  // When applying transform to rotate, invert `y` values and reduce sensitivity based on projection scale
429
429
  // see: https://observablehq.com/@benoldenburg/simple-globe and https://observablehq.com/@michael-keith/draggable-globe-in-d3
@@ -434,12 +434,9 @@
434
434
  x: x + deltaX * (sensitivity / projectionScale),
435
435
  y: y + deltaY * (sensitivity / projectionScale) * -1,
436
436
  };
437
- } else if (geo.applyTransform?.includes('translate')) {
438
- // When applying to `translate`, use pointer values as is (with no `scale` adjustment)
439
- return { x: x + deltaX, y: y + deltaY };
440
437
  } else {
441
438
  // Apply default TransformContext.processTransform (passing `undefined` below appears to not work when checking for `geo?.applyTransform` exists)
442
- return { x: x + deltaX / scale, y: y + deltaY / scale };
439
+ return { x: x + deltaX, y: y + deltaY };
443
440
  }
444
441
  }
445
442
  : undefined}
@@ -223,10 +223,9 @@ declare class __sveltets_Render<TData> {
223
223
  /** Props passed to TransformContext */
224
224
  transform?: Partial<{
225
225
  mode?: "none" | "canvas" | "manual";
226
- translateOnScale?: boolean;
227
226
  spring?: boolean | Parameters<typeof import("../stores/motionStore").motionStore>[1]["spring"];
228
227
  tweened?: boolean | Parameters<typeof import("../stores/motionStore").motionStore>[1]["tweened"];
229
- processTranslate?: (x: number, y: number, deltaX: number, deltaY: number, scale: number) => {
228
+ processTranslate?: (x: number, y: number, deltaX: number, deltaY: number) => {
230
229
  x: number;
231
230
  y: number;
232
231
  };
@@ -302,7 +301,9 @@ declare class __sveltets_Render<TData> {
302
301
  }) => void;
303
302
  onbrushstart?: (detail: {
304
303
  xDomain?: DomainType;
305
- yDomain?: DomainType;
304
+ yDomain
305
+ /** Exposed via bind: to support `bind:brushContext` for external access (ex. `brushContext.xDomain) */
306
+ ?: DomainType;
306
307
  }) => void;
307
308
  onbrushend?: (detail: {
308
309
  xDomain?: DomainType;
@@ -1,12 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { onDestroy, tick } from 'svelte';
3
3
  import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
4
+ import { cls } from '@layerstack/tailwind';
4
5
 
5
6
  import { getRenderContext } from './Chart.svelte';
6
7
  import { chartContext } from './ChartContext.svelte';
7
8
  import { motionStore } from '../stores/motionStore.js';
8
9
  import { getCanvasContext } from './layout/Canvas.svelte';
9
-
10
10
  const { width, height } = chartContext();
11
11
 
12
12
  /**
@@ -116,6 +116,7 @@
116
116
  <div
117
117
  style:transform
118
118
  {...$$restProps}
119
+ class={cls('absolute', $$restProps.class)}
119
120
  on:click={onclick}
120
121
  on:dblclick={ondblclick}
121
122
  on:pointerenter={onpointerenter}
@@ -56,26 +56,19 @@
56
56
  <script lang="ts">
57
57
  import { chartContext } from './ChartContext.svelte';
58
58
  import { motionStore, type MotionOptions, motionFinishHandler } from '../stores/motionStore.js';
59
+ import { localPoint } from '@layerstack/utils';
59
60
 
60
61
  const { width, height } = chartContext();
61
62
 
62
63
  export let mode: TransformMode = 'none';
63
- /** Translate towards point (ex. mouse cursor/center) while zooming in/out */
64
- export let translateOnScale = false;
65
64
 
66
65
  export let spring: boolean | Parameters<typeof motionStore>[1]['spring'] = undefined;
67
66
  export let tweened: boolean | Parameters<typeof motionStore>[1]['tweened'] = undefined;
68
67
 
69
- export let processTranslate = (
70
- x: number,
71
- y: number,
72
- deltaX: number,
73
- deltaY: number,
74
- scale: number
75
- ) => {
68
+ export let processTranslate = (x: number, y: number, deltaX: number, deltaY: number) => {
76
69
  return {
77
- x: x + deltaX / scale,
78
- y: y + deltaY / scale,
70
+ x: x + deltaX,
71
+ y: y + deltaY,
79
72
  };
80
73
  };
81
74
 
@@ -162,7 +155,7 @@
162
155
  ondragstart?.();
163
156
  }
164
157
 
165
- function onPointerMove(e: PointerEvent) {
158
+ function onPointerMove(e: PointerEvent & { currentTarget: HTMLDivElement }) {
166
159
  if (!pointerDown) return;
167
160
 
168
161
  e.preventDefault(); // Stop text selection
@@ -178,11 +171,10 @@
178
171
 
179
172
  if ($dragging) {
180
173
  e.stopPropagation(); // Stop tooltip from trigging (along with `capture: true`)
181
- // @ts-expect-error
182
174
  e.currentTarget?.setPointerCapture(e.pointerId);
183
175
 
184
176
  setTranslate(
185
- processTranslate(startTranslate.x, startTranslate.y, deltaX, deltaY, $scale),
177
+ processTranslate(startTranslate.x, startTranslate.y, deltaX, deltaY),
186
178
  // @ts-expect-error
187
179
  spring ? { hard: true } : tweened ? { duration: 0 } : undefined
188
180
  );
@@ -232,7 +224,7 @@
232
224
  } else if ($scrollMode === 'translate') {
233
225
  translate.update(
234
226
  (startTranslate) =>
235
- processTranslate(startTranslate.x, startTranslate.y, -e.deltaX, -e.deltaY, $scale),
227
+ processTranslate(startTranslate.x, startTranslate.y, -e.deltaX, -e.deltaY),
236
228
  // @ts-expect-error
237
229
  spring ? { hard: true } : tweened ? { duration: 0 } : undefined
238
230
  );
@@ -251,18 +243,16 @@
251
243
  const newScale = $scale * value;
252
244
  setScale(newScale, options);
253
245
 
254
- if (translateOnScale) {
255
- // Translate towards point (ex. mouse cursor/center) while zooming in/out
256
- const invertTransformPoint = {
257
- x: (point.x - $translate.x) / currentScale,
258
- y: (point.y - $translate.y) / currentScale,
259
- };
260
- const newTranslate = {
261
- x: point.x - invertTransformPoint.x * newScale,
262
- y: point.y - invertTransformPoint.y * newScale,
263
- };
264
- setTranslate(newTranslate, options);
265
- }
246
+ // Translate towards point (ex. mouse cursor/center) while zooming in/out
247
+ const invertTransformPoint = {
248
+ x: (point.x - $translate.x) / currentScale,
249
+ y: (point.y - $translate.y) / currentScale,
250
+ };
251
+ const newTranslate = {
252
+ x: point.x - invertTransformPoint.x * newScale,
253
+ y: point.y - invertTransformPoint.y * newScale,
254
+ };
255
+ setTranslate(newTranslate, options);
266
256
  }
267
257
 
268
258
  const translating = motionFinishHandler();
@@ -281,13 +271,6 @@
281
271
  scaling.handle(scale.set(value, options));
282
272
  }
283
273
 
284
- function localPoint(e: PointerEvent | MouseEvent | WheelEvent) {
285
- return {
286
- x: e.offsetX,
287
- y: e.offsetY,
288
- };
289
- }
290
-
291
274
  $: center = { x: $width / 2, y: $height / 2 };
292
275
 
293
276
  $: viewportCenter = {
@@ -37,10 +37,9 @@ import { motionStore, type MotionOptions } from '../stores/motionStore.js';
37
37
  declare const __propDef: {
38
38
  props: {
39
39
  mode?: TransformMode;
40
- /** Translate towards point (ex. mouse cursor/center) while zooming in/out */ translateOnScale?: boolean;
41
40
  spring?: boolean | Parameters<typeof motionStore>[1]["spring"];
42
41
  tweened?: boolean | Parameters<typeof motionStore>[1]["tweened"];
43
- processTranslate?: (x: number, y: number, deltaX: number, deltaY: number, scale: number) => {
42
+ processTranslate?: (x: number, y: number, deltaX: number, deltaY: number) => {
44
43
  x: number;
45
44
  y: number;
46
45
  };
@@ -151,10 +151,9 @@ declare class __sveltets_Render<TData> {
151
151
  }> | undefined;
152
152
  transform?: Partial<{
153
153
  mode?: "none" | "canvas" | "manual";
154
- translateOnScale?: boolean;
155
154
  spring?: boolean | Parameters<typeof import("../../stores/motionStore").motionStore>[1]["spring"];
156
155
  tweened?: boolean | Parameters<typeof import("../../stores/motionStore").motionStore>[1]["tweened"];
157
- processTranslate?: (x: number, y: number, deltaX: number, deltaY: number, scale: number) => {
156
+ processTranslate?: (x: number, y: number, deltaX: number, deltaY: number) => {
158
157
  x: number;
159
158
  y: number;
160
159
  };
@@ -38,14 +38,13 @@
38
38
  <script lang="ts">
39
39
  import { onMount, onDestroy } from 'svelte';
40
40
  import { cls } from '@layerstack/tailwind';
41
- import { Logger } from '@layerstack/utils';
41
+ import { Logger, localPoint } from '@layerstack/utils';
42
42
 
43
43
  import { setRenderContext } from '../Chart.svelte';
44
44
  import { chartContext } from '../ChartContext.svelte';
45
45
  import { transformContext } from '../TransformContext.svelte';
46
46
  import { getPixelColor, scaleCanvas, type ComputedStylesOptions } from '../../utils/canvas.js';
47
47
  import { getColorStr, rgbColorGenerator } from '../../utils/color.js';
48
- import { localPoint } from '../../utils/event.js';
49
48
  const { width, height, containerWidth, containerHeight, padding } = chartContext();
50
49
 
51
50
  /** The `<canvas>` tag. Useful for bindings. */
@@ -104,7 +103,7 @@
104
103
  const componentByColor = new Map<string, ComponentRender>();
105
104
 
106
105
  function getPointerComponent(e: PointerEvent | MouseEvent | TouchEvent) {
107
- const { x, y } = localPoint(e.target as HTMLCanvasElement, e) ?? { x: 0, y: 0 };
106
+ const { x, y } = localPoint(e);
108
107
  const color = getPixelColor(hitCanvasContext!, x, y);
109
108
  const colorKey = getColorStr(color);
110
109
  const component = componentByColor.get(colorKey);
@@ -178,12 +177,7 @@
178
177
  };
179
178
  context.translate(newTranslate.x, newTranslate.y);
180
179
  } else if (mode === 'canvas') {
181
- const center = { x: $width / 2, y: $height / 2 };
182
- const newTranslate = {
183
- x: $translate.x * $scale + center.x - center.x * $scale,
184
- y: $translate.y * $scale + center.y - center.y * $scale,
185
- };
186
- context.translate(newTranslate.x, newTranslate.y);
180
+ context.translate($translate.x, $translate.y);
187
181
  context.scale($scale, $scale);
188
182
  }
189
183
 
@@ -40,12 +40,7 @@
40
40
  ? `translate(${center === 'x' || center === true ? $width / 2 : 0}, ${center === 'y' || center === true ? $height / 2 : 0})`
41
41
  : '';
42
42
  $: if (mode === 'canvas') {
43
- const center = { x: $width / 2, y: $height / 2 };
44
- const newTranslate = {
45
- x: $translate.x * $scale + center.x - center.x * $scale,
46
- y: $translate.y * $scale + center.y - center.y * $scale,
47
- };
48
- transform = `translate(${newTranslate.x}px,${newTranslate.y}px) scale(${$scale})`;
43
+ transform = `translate(${$translate.x}px,${$translate.y}px) scale(${$scale})`;
49
44
  }
50
45
 
51
46
  setRenderContext('html');
@@ -44,12 +44,7 @@
44
44
  ? `translate(${center === 'x' || center === true ? $width / 2 : 0}, ${center === 'y' || center === true ? $height / 2 : 0})`
45
45
  : '';
46
46
  $: if (mode === 'canvas') {
47
- const center = { x: $width / 2, y: $height / 2 };
48
- const newTranslate = {
49
- x: $translate.x * $scale + center.x - center.x * $scale,
50
- y: $translate.y * $scale + center.y - center.y * $scale,
51
- };
52
- transform = `translate(${newTranslate.x},${newTranslate.y}) scale(${$scale})`;
47
+ transform = `translate(${$translate.x},${$translate.y}) scale(${$scale})`;
53
48
  }
54
49
 
55
50
  setRenderContext('svg');
@@ -47,7 +47,7 @@
47
47
  import { writable } from 'svelte/store';
48
48
  import { bisector, max, min } from 'd3-array';
49
49
  import { quadtree as d3Quadtree, type Quadtree } from 'd3-quadtree';
50
- import { sortFunc } from '@layerstack/utils';
50
+ import { sortFunc, localPoint } from '@layerstack/utils';
51
51
  import { cls } from '@layerstack/tailwind';
52
52
 
53
53
  import Svg from './../layout/Svg.svelte';
@@ -55,7 +55,6 @@
55
55
  import ChartClipPath from './../ChartClipPath.svelte';
56
56
  import Voronoi from './../Voronoi.svelte';
57
57
 
58
- import { localPoint } from '../../utils/event.js';
59
58
  import { isScaleBand, scaleInvert } from '../../utils/scales.js';
60
59
  import { cartesianToPolar } from '../../utils/math.js';
61
60
  import { quadtreeRects } from '../../utils/quadtree.js';
@@ -189,7 +188,7 @@
189
188
  }
190
189
 
191
190
  const referenceNode = (e.target as Element).closest('.layercake-container')!;
192
- const point = localPoint(referenceNode, e);
191
+ const point = localPoint(e, referenceNode);
193
192
  const pointerX = point?.x ?? 0;
194
193
  const pointerY = point?.y ?? 0;
195
194
 
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.97.0",
7
+ "version": "0.98.0",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.27.12",
10
10
  "@mdi/js": "^7.4.47",
@@ -41,7 +41,7 @@
41
41
  "autoprefixer": "^10.4.20",
42
42
  "marked": "^15.0.7",
43
43
  "mdsvex": "^0.12.3",
44
- "posthog-js": "^1.217.0",
44
+ "posthog-js": "^1.217.2",
45
45
  "prettier": "^3.5.0",
46
46
  "prettier-plugin-svelte": "^3.3.3",
47
47
  "prism-svelte": "^0.5.0",
@@ -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.10",
53
+ "svelte": "5.20.0",
54
54
  "svelte-check": "^4.1.4",
55
55
  "svelte-json-tree": "^2.2.0",
56
56
  "svelte-ux": "^0.90.1",
@@ -68,10 +68,10 @@
68
68
  "type": "module",
69
69
  "dependencies": {
70
70
  "@dagrejs/dagre": "^1.1.4",
71
- "@layerstack/svelte-actions": "^0.0.11",
72
- "@layerstack/svelte-stores": "^0.0.10",
73
- "@layerstack/tailwind": "^0.0.11",
74
- "@layerstack/utils": "^0.0.7",
71
+ "@layerstack/svelte-actions": "^0.0.12",
72
+ "@layerstack/svelte-stores": "^0.0.11",
73
+ "@layerstack/tailwind": "^0.0.12",
74
+ "@layerstack/utils": "^0.1.0",
75
75
  "d3-array": "^3.2.4",
76
76
  "d3-color": "^3.1.0",
77
77
  "d3-delaunay": "^6.0.4",
@@ -1,4 +0,0 @@
1
- export declare function localPoint(node: Element, event: MouseEvent | TouchEvent | PointerEvent): {
2
- x: number;
3
- y: number;
4
- } | null;
@@ -1,44 +0,0 @@
1
- import { isSVGElement, isSVGGraphicsElement, isSVGSVGElement, isTouchEvent, } from '@layerstack/utils';
2
- // See: https://github.com/airbnb/visx/blob/master/packages/visx-event/src/localPointGeneric.ts
3
- // TODO: Matches event.layerX/Y, but are deprecated (https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/layerX).
4
- // Similar and could be replaced by event.offsetX/Y (but not identical)
5
- export function localPoint(node, event) {
6
- if (!node || !event)
7
- return null;
8
- const coords = getPointFromEvent(event);
9
- // find top-most SVG
10
- const svg = isSVGElement(node) ? node.ownerSVGElement : node;
11
- const screenCTM = isSVGGraphicsElement(svg) ? svg.getScreenCTM() : null;
12
- if (isSVGSVGElement(svg) && screenCTM) {
13
- let point = svg.createSVGPoint();
14
- point.x = coords.x;
15
- point.y = coords.y;
16
- point = point.matrixTransform(screenCTM.inverse());
17
- return {
18
- x: point.x,
19
- y: point.y,
20
- };
21
- }
22
- // fall back to bounding box
23
- const rect = node.getBoundingClientRect();
24
- return {
25
- x: coords.x - rect.left - node.clientLeft,
26
- y: coords.y - rect.top - node.clientTop,
27
- };
28
- }
29
- function getPointFromEvent(event) {
30
- if (!event)
31
- return { x: 0, y: 0 };
32
- if (isTouchEvent(event)) {
33
- return event.changedTouches.length > 0
34
- ? {
35
- x: event.changedTouches[0].clientX,
36
- y: event.changedTouches[0].clientY,
37
- }
38
- : { x: 0, y: 0 };
39
- }
40
- return {
41
- x: event.clientX,
42
- y: event.clientY,
43
- };
44
- }