layerchart 0.37.2 → 0.37.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.
- package/dist/components/Arc.svelte.d.ts +1 -1
- package/dist/components/Chart.svelte +76 -56
- package/dist/components/Chart.svelte.d.ts +23 -4
- package/dist/components/TransformContext.svelte +18 -7
- package/dist/components/TransformContext.svelte.d.ts +41 -6
- package/dist/docs/TransformDebug.svelte +0 -4
- package/dist/stores/motionStore.d.ts +1 -1
- package/dist/utils/geo.d.ts +7 -0
- package/dist/utils/geo.js +5 -0
- package/package.json +1 -1
|
@@ -15,12 +15,14 @@ export const Svg = _Svg;
|
|
|
15
15
|
export const WebGL = _WebGL;
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
|
-
<script>import {
|
|
18
|
+
<script>import { onMount } from 'svelte';
|
|
19
|
+
import { max, min } from 'd3-array';
|
|
19
20
|
import { get } from 'lodash-es';
|
|
20
21
|
import { isScaleBand } from '../utils/scales.js';
|
|
21
22
|
import GeoContext from './GeoContext.svelte';
|
|
22
23
|
import TooltipContext from './TooltipContext.svelte';
|
|
23
24
|
import TransformContext from './TransformContext.svelte';
|
|
25
|
+
import { geoFitObjectTransform } from '../utils/geo.js';
|
|
24
26
|
/**
|
|
25
27
|
* Resolve a value from data based on the accessor type
|
|
26
28
|
*/
|
|
@@ -73,7 +75,16 @@ export let tooltip = undefined;
|
|
|
73
75
|
/** Props passed to TransformContext */
|
|
74
76
|
export let transform = undefined;
|
|
75
77
|
export let transformContext = undefined;
|
|
78
|
+
/** Set transformContext's initial translate and scale based on geo object. Requires `geo.projection` to also be set */
|
|
79
|
+
export let fitGeoObject = undefined;
|
|
80
|
+
// Binded for access within TransformContext
|
|
76
81
|
let geoProjection = undefined;
|
|
82
|
+
// Track when mounted since LayerCake initializes width/height with `100` until binded `clientWidth`/`clientWidth` can run
|
|
83
|
+
// Useful to key/remount TransformContext with correct `initialTranslate` / `initialScale` values
|
|
84
|
+
let isMounted = false;
|
|
85
|
+
onMount(() => {
|
|
86
|
+
isMounted = true;
|
|
87
|
+
});
|
|
77
88
|
</script>
|
|
78
89
|
|
|
79
90
|
<LayerCake
|
|
@@ -103,60 +114,69 @@ let geoProjection = undefined;
|
|
|
103
114
|
let:data
|
|
104
115
|
let:flatData
|
|
105
116
|
>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
? (x, y, deltaX, deltaY, scale) => {
|
|
110
|
-
if (geo.applyTransform?.includes('rotate')) {
|
|
111
|
-
// When applying transform to rotate, invert `y` values and reduce sensitivity based on projection scale
|
|
112
|
-
// see: https://observablehq.com/@benoldenburg/simple-globe and https://observablehq.com/@michael-keith/draggable-globe-in-d3
|
|
113
|
-
const projectionScale = $geoProjection.scale();
|
|
114
|
-
const sensitivity = 75;
|
|
115
|
-
return {
|
|
116
|
-
x: x + deltaX * (sensitivity / projectionScale),
|
|
117
|
-
y: y + deltaY * (sensitivity / projectionScale) * -1,
|
|
118
|
-
};
|
|
119
|
-
} else if (geo.applyTransform?.includes('translate')) {
|
|
120
|
-
// When applying to `translate`, use pointer values as is (with no `scale` adjustment)
|
|
121
|
-
return { x: x + deltaX, y: y + deltaY };
|
|
122
|
-
} else {
|
|
123
|
-
// Apply default TransformContext.processTransform (passing `undefined` below appears to not work when checking for `geo?.applyTransform` exists)
|
|
124
|
-
return { x: x + deltaX / scale, y: y + deltaY / scale };
|
|
125
|
-
}
|
|
126
|
-
}
|
|
117
|
+
{@const initialTransform =
|
|
118
|
+
fitGeoObject && geo?.projection
|
|
119
|
+
? geoFitObjectTransform(geo.projection(), [width, height], fitGeoObject)
|
|
127
120
|
: undefined}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
121
|
+
|
|
122
|
+
{#key isMounted}
|
|
123
|
+
<TransformContext
|
|
124
|
+
bind:this={transformContext}
|
|
125
|
+
initialTranslate={initialTransform?.translate}
|
|
126
|
+
initialScale={initialTransform?.scale}
|
|
127
|
+
processTranslate={geo
|
|
128
|
+
? (x, y, deltaX, deltaY, scale) => {
|
|
129
|
+
if (geo.applyTransform?.includes('rotate')) {
|
|
130
|
+
// When applying transform to rotate, invert `y` values and reduce sensitivity based on projection scale
|
|
131
|
+
// see: https://observablehq.com/@benoldenburg/simple-globe and https://observablehq.com/@michael-keith/draggable-globe-in-d3
|
|
132
|
+
const projectionScale = $geoProjection.scale();
|
|
133
|
+
const sensitivity = 75;
|
|
134
|
+
return {
|
|
135
|
+
x: x + deltaX * (sensitivity / projectionScale),
|
|
136
|
+
y: y + deltaY * (sensitivity / projectionScale) * -1,
|
|
137
|
+
};
|
|
138
|
+
} else if (geo.applyTransform?.includes('translate')) {
|
|
139
|
+
// When applying to `translate`, use pointer values as is (with no `scale` adjustment)
|
|
140
|
+
return { x: x + deltaX, y: y + deltaY };
|
|
141
|
+
} else {
|
|
142
|
+
// Apply default TransformContext.processTransform (passing `undefined` below appears to not work when checking for `geo?.applyTransform` exists)
|
|
143
|
+
return { x: x + deltaX / scale, y: y + deltaY / scale };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
: undefined}
|
|
147
|
+
{...transform}
|
|
148
|
+
let:transform={_transform}
|
|
149
|
+
on:transform
|
|
150
|
+
on:dragstart
|
|
151
|
+
on:dragend
|
|
152
|
+
>
|
|
153
|
+
<GeoContext {...geo} bind:geo={geoProjection} let:projection>
|
|
154
|
+
{@const tooltipProps = typeof tooltip === 'object' ? tooltip : {}}
|
|
155
|
+
<TooltipContext {...tooltipProps} let:tooltip>
|
|
156
|
+
<slot
|
|
157
|
+
{aspectRatio}
|
|
158
|
+
{containerHeight}
|
|
159
|
+
{containerWidth}
|
|
160
|
+
{height}
|
|
161
|
+
{width}
|
|
162
|
+
{element}
|
|
163
|
+
{projection}
|
|
164
|
+
transform={_transform}
|
|
165
|
+
{tooltip}
|
|
166
|
+
{xScale}
|
|
167
|
+
{xGet}
|
|
168
|
+
{yScale}
|
|
169
|
+
{yGet}
|
|
170
|
+
{zScale}
|
|
171
|
+
{zGet}
|
|
172
|
+
{rScale}
|
|
173
|
+
{rGet}
|
|
174
|
+
{padding}
|
|
175
|
+
{data}
|
|
176
|
+
{flatData}
|
|
177
|
+
/>
|
|
178
|
+
</TooltipContext>
|
|
179
|
+
</GeoContext>
|
|
180
|
+
</TransformContext>
|
|
181
|
+
{/key}
|
|
162
182
|
</LayerCake>
|
|
@@ -6,10 +6,11 @@ export declare const Canvas: typeof _Canvas;
|
|
|
6
6
|
export declare const Html: typeof _Html;
|
|
7
7
|
export declare const Svg: typeof _Svg;
|
|
8
8
|
export declare const WebGL: typeof _WebGL;
|
|
9
|
-
import type
|
|
9
|
+
import { type ComponentProps } from 'svelte';
|
|
10
10
|
import GeoContext from './GeoContext.svelte';
|
|
11
11
|
import TooltipContext from './TooltipContext.svelte';
|
|
12
12
|
import TransformContext from './TransformContext.svelte';
|
|
13
|
+
import { geoFitObjectTransform } from '../utils/geo.js';
|
|
13
14
|
declare const __propDef: {
|
|
14
15
|
props: {
|
|
15
16
|
[x: string]: any;
|
|
@@ -23,6 +24,7 @@ declare const __propDef: {
|
|
|
23
24
|
tooltip?: Partial<ComponentProps<TooltipContext>> | boolean | undefined;
|
|
24
25
|
transform?: Partial<ComponentProps<TransformContext>> | undefined;
|
|
25
26
|
transformContext?: TransformContext | undefined;
|
|
27
|
+
fitGeoObject?: Parameters<typeof geoFitObjectTransform>[2] | undefined;
|
|
26
28
|
};
|
|
27
29
|
events: {
|
|
28
30
|
transform: CustomEvent<{
|
|
@@ -47,8 +49,25 @@ declare const __propDef: {
|
|
|
47
49
|
element: Element;
|
|
48
50
|
projection: import("d3-geo").GeoProjection | import("d3-geo").GeoIdentityTransform;
|
|
49
51
|
transform: {
|
|
50
|
-
scale:
|
|
51
|
-
|
|
52
|
+
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
|
+
translate: {
|
|
55
|
+
x: number;
|
|
56
|
+
y: number;
|
|
57
|
+
};
|
|
58
|
+
setTranslate: ((new_value: {
|
|
59
|
+
x: number;
|
|
60
|
+
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);
|
|
52
71
|
zoomTo: (center: {
|
|
53
72
|
x: number;
|
|
54
73
|
y: number;
|
|
@@ -61,7 +80,7 @@ declare const __propDef: {
|
|
|
61
80
|
tooltip: {
|
|
62
81
|
y: number;
|
|
63
82
|
x: number;
|
|
64
|
-
data: null;
|
|
83
|
+
data: null; /** Props passed to TransformContext */
|
|
65
84
|
show: (e: PointerEvent, tooltipData?: any) => void;
|
|
66
85
|
hide: () => void;
|
|
67
86
|
};
|
|
@@ -42,15 +42,17 @@ export let clickDistance = 10;
|
|
|
42
42
|
const dispatch = createEventDispatcher();
|
|
43
43
|
let pointerDown = false;
|
|
44
44
|
const dragging = writable(false);
|
|
45
|
-
|
|
46
|
-
export
|
|
47
|
-
export
|
|
48
|
-
|
|
45
|
+
const DEFAULT_TRANSLATE = { x: 0, y: 0 };
|
|
46
|
+
export let initialTranslate = undefined;
|
|
47
|
+
export const translate = motionStore(initialTranslate ?? DEFAULT_TRANSLATE, { spring, tweened });
|
|
48
|
+
const DEFAULT_SCALE = 1;
|
|
49
|
+
export let initialScale = undefined;
|
|
50
|
+
export const scale = motionStore(initialScale ?? DEFAULT_SCALE, { spring, tweened });
|
|
49
51
|
let startPoint = { x: 0, y: 0 };
|
|
50
52
|
let startTranslate = { x: 0, y: 0 };
|
|
51
53
|
export function reset() {
|
|
52
|
-
$translate = initialTranslate;
|
|
53
|
-
$scale = initialScale;
|
|
54
|
+
$translate = initialTranslate ?? DEFAULT_TRANSLATE;
|
|
55
|
+
$scale = initialScale ?? DEFAULT_SCALE;
|
|
54
56
|
}
|
|
55
57
|
export function zoomIn() {
|
|
56
58
|
scaleTo(1.25, { x: $width / 2, y: $height / 2 });
|
|
@@ -197,5 +199,14 @@ $: dispatch('transform', { scale: $scale, translate: $translate });
|
|
|
197
199
|
on:keypress
|
|
198
200
|
class="h-full"
|
|
199
201
|
>
|
|
200
|
-
<slot
|
|
202
|
+
<slot
|
|
203
|
+
transform={{
|
|
204
|
+
scale: $scale,
|
|
205
|
+
setScale: scale.set,
|
|
206
|
+
translate: $translate,
|
|
207
|
+
setTranslate: translate.set,
|
|
208
|
+
zoomTo,
|
|
209
|
+
reset,
|
|
210
|
+
}}
|
|
211
|
+
/>
|
|
201
212
|
</div>
|
|
@@ -41,9 +41,18 @@ declare const __propDef: {
|
|
|
41
41
|
x: number;
|
|
42
42
|
y: number;
|
|
43
43
|
} | undefined;
|
|
44
|
-
translate?: import("svelte/motion").Spring<
|
|
44
|
+
translate?: import("svelte/motion").Spring<{
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
}> | import("svelte/motion").Tweened<{
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
}> | Writable<{
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
}> | undefined;
|
|
45
54
|
initialScale?: number | undefined;
|
|
46
|
-
scale?: import("svelte/motion").Spring<
|
|
55
|
+
scale?: import("svelte/motion").Spring<number> | import("svelte/motion").Tweened<number> | Writable<number> | undefined;
|
|
47
56
|
reset?: (() => void) | undefined;
|
|
48
57
|
zoomIn?: (() => void) | undefined;
|
|
49
58
|
zoomOut?: (() => void) | undefined;
|
|
@@ -76,8 +85,25 @@ declare const __propDef: {
|
|
|
76
85
|
slots: {
|
|
77
86
|
default: {
|
|
78
87
|
transform: {
|
|
79
|
-
scale:
|
|
80
|
-
|
|
88
|
+
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);
|
|
90
|
+
translate: {
|
|
91
|
+
x: number;
|
|
92
|
+
y: number;
|
|
93
|
+
};
|
|
94
|
+
setTranslate: ((new_value: {
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
}, opts?: import("svelte/motion").SpringUpdateOpts | undefined) => Promise<void>) | ((value: {
|
|
98
|
+
x: number;
|
|
99
|
+
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);
|
|
81
107
|
zoomTo: (center: {
|
|
82
108
|
x: number;
|
|
83
109
|
y: number;
|
|
@@ -94,8 +120,17 @@ export type TransformContextProps = typeof __propDef.props;
|
|
|
94
120
|
export type TransformContextEvents = typeof __propDef.events;
|
|
95
121
|
export type TransformContextSlots = typeof __propDef.slots;
|
|
96
122
|
export default class TransformContext extends SvelteComponentTyped<TransformContextProps, TransformContextEvents, TransformContextSlots> {
|
|
97
|
-
get translate(): NonNullable<import("svelte/motion").Spring<
|
|
98
|
-
|
|
123
|
+
get translate(): NonNullable<import("svelte/motion").Spring<{
|
|
124
|
+
x: number;
|
|
125
|
+
y: number;
|
|
126
|
+
}> | import("svelte/motion").Tweened<{
|
|
127
|
+
x: number;
|
|
128
|
+
y: number;
|
|
129
|
+
}> | Writable<{
|
|
130
|
+
x: number;
|
|
131
|
+
y: number;
|
|
132
|
+
}> | undefined>;
|
|
133
|
+
get scale(): NonNullable<import("svelte/motion").Spring<number> | import("svelte/motion").Tweened<number> | Writable<number> | undefined>;
|
|
99
134
|
get reset(): () => void;
|
|
100
135
|
get zoomIn(): () => void;
|
|
101
136
|
get zoomOut(): () => void;
|
|
@@ -12,10 +12,6 @@ const { translate, scale } = transform;
|
|
|
12
12
|
<span class="opacity-50">translate:</span>
|
|
13
13
|
<div class="text-right">{format($translate.x, 'decimal')}</div>
|
|
14
14
|
<div class="text-right">{format($translate.y, 'decimal')}</div>
|
|
15
|
-
|
|
16
|
-
<span class="opacity-50">delta:</span>
|
|
17
|
-
<div class="text-right">{format($translate.deltaX, 'decimal')}</div>
|
|
18
|
-
<div class="text-right">{format($translate.deltaY, 'decimal')}</div>
|
|
19
15
|
</div>
|
|
20
16
|
</div>
|
|
21
17
|
</div>
|
|
@@ -17,7 +17,7 @@ export type PropMotionOptions = {
|
|
|
17
17
|
/**
|
|
18
18
|
* Convenient wrapper to create a motion store (spring(), tweened()) based on properties, or fall back to basic writable() store
|
|
19
19
|
*/
|
|
20
|
-
export declare function motionStore<T = any>(value:
|
|
20
|
+
export declare function motionStore<T = any>(value: T, options: MotionOptions): import("svelte/motion").Spring<T> | import("svelte/motion").Tweened<T> | import("svelte/store").Writable<T>;
|
|
21
21
|
/**
|
|
22
22
|
* Helper to resolve motion options with specific property option (useful for specifying per-prop delays)
|
|
23
23
|
*/
|
package/dist/utils/geo.d.ts
CHANGED
|
@@ -16,3 +16,10 @@ export declare function antipode([longitude, latitude]: [number, number]): [numb
|
|
|
16
16
|
* @see: https://observablehq.com/@d3/testing-projection-visibility
|
|
17
17
|
*/
|
|
18
18
|
export declare function isVisible(projection: GeoProjection | GeoStreamWrapper): ([x, y]: [any, any]) => boolean;
|
|
19
|
+
export declare function geoFitObjectTransform(projection: GeoProjection, size: [number, number], object: Parameters<typeof projection.fitSize>[1]): {
|
|
20
|
+
translate: {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
};
|
|
24
|
+
scale: number;
|
|
25
|
+
};
|
package/dist/utils/geo.js
CHANGED
|
@@ -59,3 +59,8 @@ export function isVisible(projection) {
|
|
|
59
59
|
});
|
|
60
60
|
return ([x, y]) => ((visible = false), stream.point(x, y), visible);
|
|
61
61
|
}
|
|
62
|
+
export function geoFitObjectTransform(projection, size, object) {
|
|
63
|
+
const newProjection = projection.fitSize(size, object);
|
|
64
|
+
const translate = newProjection.translate();
|
|
65
|
+
return { translate: { x: translate[0], y: translate[1] }, scale: newProjection.scale() };
|
|
66
|
+
}
|