layerchart 0.38.6 → 0.40.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.
- package/dist/components/Brush.svelte +244 -0
- package/dist/components/Brush.svelte.d.ts +53 -0
- package/dist/components/Chart.svelte +3 -4
- package/dist/components/Chart.svelte.d.ts +0 -2
- package/dist/components/ChartClipPath.svelte +6 -6
- package/dist/components/ChartClipPath.svelte.d.ts +1 -1
- package/dist/components/Frame.svelte +5 -0
- package/dist/components/Frame.svelte.d.ts +3 -0
- package/dist/components/Group.svelte +1 -0
- package/dist/components/Group.svelte.d.ts +1 -0
- package/dist/components/Rect.svelte +1 -0
- package/dist/components/Rect.svelte.d.ts +1 -0
- package/dist/components/TooltipContext.svelte +34 -19
- package/dist/components/TransformContext.svelte +13 -4
- package/dist/components/TransformContext.svelte.d.ts +10 -4
- package/dist/components/TransformControls.svelte +93 -30
- package/dist/components/TransformControls.svelte.d.ts +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/utils/genData.d.ts +6 -0
- package/dist/utils/genData.js +9 -0
- package/package.json +11 -11
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
<script>import { createEventDispatcher, getContext } from 'svelte';
|
|
2
|
+
import { extent } from 'd3-array';
|
|
3
|
+
import { clamp, cls } from 'svelte-ux';
|
|
4
|
+
import Frame from './Frame.svelte';
|
|
5
|
+
import { localPoint } from '../utils/event.js';
|
|
6
|
+
import Group from './Group.svelte';
|
|
7
|
+
const { xScale, yScale, width, height, padding } = getContext('LayerCake');
|
|
8
|
+
const dispatch = createEventDispatcher();
|
|
9
|
+
/** Axis to apply brushing */
|
|
10
|
+
export let axis = 'x';
|
|
11
|
+
/** Size of draggable handles (width/height) */
|
|
12
|
+
export let handleSize = 5;
|
|
13
|
+
/** Only show range while actively brushing. Useful with `brushEnd` event */
|
|
14
|
+
export let resetOnEnd = false;
|
|
15
|
+
export let xDomain = $xScale.domain();
|
|
16
|
+
export let yDomain = $yScale.domain();
|
|
17
|
+
// Capture original domains for reset()
|
|
18
|
+
const originalXDomain = $xScale.domain();
|
|
19
|
+
const originalYDomain = $yScale.domain();
|
|
20
|
+
$: [xDomainMin, xDomainMax] = extent($xScale.domain());
|
|
21
|
+
$: [yDomainMin, yDomainMax] = extent($yScale.domain());
|
|
22
|
+
/** Attributes passed to range <rect> element */
|
|
23
|
+
export let range = undefined;
|
|
24
|
+
/** Attributes passed to handle <rect> elements */
|
|
25
|
+
export let handle = undefined;
|
|
26
|
+
export let classes = {};
|
|
27
|
+
let frameEl;
|
|
28
|
+
function handler(fn) {
|
|
29
|
+
return (e) => {
|
|
30
|
+
const start = {
|
|
31
|
+
xDomain: [xDomain[0] ?? xDomainMin, xDomain[1] ?? xDomainMax],
|
|
32
|
+
yDomain: [yDomain[0] ?? yDomainMin, yDomain[1] ?? yDomainMax],
|
|
33
|
+
value: {
|
|
34
|
+
x: $xScale.invert(localPoint(frameEl, e)?.x - $padding.left),
|
|
35
|
+
y: $yScale.invert(localPoint(frameEl, e)?.y - $padding.top),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
dispatch('brushStart', { xDomain, yDomain });
|
|
39
|
+
const onPointerMove = (e) => {
|
|
40
|
+
fn(start, {
|
|
41
|
+
x: $xScale.invert(localPoint(frameEl, e)?.x - $padding.left),
|
|
42
|
+
y: $yScale.invert(localPoint(frameEl, e)?.y - $padding.top),
|
|
43
|
+
});
|
|
44
|
+
// if (xDomain[0] === xDomain[1] || yDomain[0] === yDomain[1]) {
|
|
45
|
+
// // Ignore?
|
|
46
|
+
// // TODO: What about when using `x` or `y` axis?
|
|
47
|
+
// } else {
|
|
48
|
+
dispatch('change', { xDomain, yDomain });
|
|
49
|
+
// }
|
|
50
|
+
};
|
|
51
|
+
const onPointerUp = (e) => {
|
|
52
|
+
if (e.target === frameEl) {
|
|
53
|
+
reset();
|
|
54
|
+
dispatch('change', { xDomain, yDomain });
|
|
55
|
+
}
|
|
56
|
+
dispatch('brushEnd', { xDomain, yDomain });
|
|
57
|
+
if (resetOnEnd) {
|
|
58
|
+
reset();
|
|
59
|
+
}
|
|
60
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
61
|
+
window.removeEventListener('pointerup', onPointerUp);
|
|
62
|
+
};
|
|
63
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
64
|
+
window.addEventListener('pointerup', onPointerUp);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const createRange = handler((start, value) => {
|
|
68
|
+
isActive = true;
|
|
69
|
+
xDomain = [
|
|
70
|
+
clamp(Math.min(start.value.x, value.x), xDomainMin, xDomainMax),
|
|
71
|
+
clamp(Math.max(start.value.x, value.x), xDomainMin, xDomainMax),
|
|
72
|
+
];
|
|
73
|
+
yDomain = [
|
|
74
|
+
clamp(Math.min(start.value.y, value.y), yDomainMin, yDomainMax),
|
|
75
|
+
clamp(Math.max(start.value.y, value.y), yDomainMin, yDomainMax),
|
|
76
|
+
];
|
|
77
|
+
});
|
|
78
|
+
const adjustRange = handler((start, value) => {
|
|
79
|
+
const dx = clamp(value.x - start.value.x, xDomainMin - start.xDomain[0], xDomainMax - start.xDomain[1]);
|
|
80
|
+
xDomain = [Number(start.xDomain[0]) + dx, Number(start.xDomain[1]) + dx];
|
|
81
|
+
const dy = clamp(value.y - start.value.y, yDomainMin - start.yDomain[0], yDomainMax - start.yDomain[1]);
|
|
82
|
+
yDomain = [Number(start.yDomain[0]) + dy, Number(start.yDomain[1]) + dy];
|
|
83
|
+
});
|
|
84
|
+
const adjustBottom = handler((start, value) => {
|
|
85
|
+
yDomain = [
|
|
86
|
+
clamp(value.y > start.yDomain[1] ? start.yDomain[1] : value.y, yDomainMin, yDomainMax),
|
|
87
|
+
clamp(value.y > start.yDomain[1] ? value.y : start.yDomain[1], yDomainMin, yDomainMax),
|
|
88
|
+
];
|
|
89
|
+
});
|
|
90
|
+
const adjustTop = handler((start, value) => {
|
|
91
|
+
yDomain = [
|
|
92
|
+
clamp(value.y < start.yDomain[1] ? value.y : start.yDomain[0], yDomainMin, yDomainMax),
|
|
93
|
+
clamp(value.y < start.yDomain[1] ? start.yDomain[0] : value.y, yDomainMin, yDomainMax),
|
|
94
|
+
];
|
|
95
|
+
});
|
|
96
|
+
const adjustLeft = handler((start, value) => {
|
|
97
|
+
xDomain = [
|
|
98
|
+
clamp(value.x > start.xDomain[1] ? start.xDomain[1] : value.x, xDomainMin, xDomainMax),
|
|
99
|
+
clamp(value.x > start.xDomain[1] ? value.x : start.xDomain[1], xDomainMin, xDomainMax),
|
|
100
|
+
];
|
|
101
|
+
});
|
|
102
|
+
const adjustRight = handler((start, value) => {
|
|
103
|
+
xDomain = [
|
|
104
|
+
clamp(value.x < start.xDomain[0] ? value.x : start.xDomain[0], xDomainMin, xDomainMax),
|
|
105
|
+
clamp(value.x < start.xDomain[0] ? start.xDomain[0] : value.x, xDomainMin, xDomainMax),
|
|
106
|
+
];
|
|
107
|
+
});
|
|
108
|
+
function reset() {
|
|
109
|
+
isActive = false;
|
|
110
|
+
xDomain = originalXDomain;
|
|
111
|
+
yDomain = originalYDomain;
|
|
112
|
+
}
|
|
113
|
+
function selectAll() {
|
|
114
|
+
xDomain = [xDomainMin, xDomainMax];
|
|
115
|
+
yDomain = [yDomainMin, yDomainMax];
|
|
116
|
+
}
|
|
117
|
+
$: top = $yScale(yDomain[1]);
|
|
118
|
+
$: bottom = $yScale(yDomain[0]);
|
|
119
|
+
$: left = $xScale(xDomain[0]);
|
|
120
|
+
$: right = $xScale(xDomain[1]);
|
|
121
|
+
$: rangeTop = axis === 'both' || axis === 'y' ? top : 0;
|
|
122
|
+
$: rangeLeft = axis === 'both' || axis === 'x' ? left : 0;
|
|
123
|
+
$: rangeWidth = axis === 'both' || axis === 'x' ? right - left : $width;
|
|
124
|
+
$: rangeHeight = axis === 'both' || axis === 'y' ? bottom - top : $height;
|
|
125
|
+
// Set reactively to handle cases where xDomain/yDomain are set externally (ex. `bind:xDomain`)
|
|
126
|
+
$: isActive =
|
|
127
|
+
xDomain[0]?.valueOf() !== originalXDomain[0]?.valueOf() ||
|
|
128
|
+
xDomain[1]?.valueOf() !== originalXDomain[1]?.valueOf() ||
|
|
129
|
+
yDomain[0]?.valueOf() !== originalYDomain[0]?.valueOf() ||
|
|
130
|
+
yDomain[1]?.valueOf() !== originalYDomain[1]?.valueOf();
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
<g class={cls('Brush select-none', classes.root, $$props.class)}>
|
|
134
|
+
<Frame
|
|
135
|
+
class={cls('frame', 'fill-transparent', classes.frame)}
|
|
136
|
+
on:pointerdown={createRange}
|
|
137
|
+
on:dblclick={() => selectAll()}
|
|
138
|
+
bind:rectEl={frameEl}
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
{#if isActive}
|
|
142
|
+
<Group x={rangeLeft} y={rangeTop} class="range">
|
|
143
|
+
<slot name="range" {rangeWidth} {rangeHeight}>
|
|
144
|
+
<rect
|
|
145
|
+
width={rangeWidth}
|
|
146
|
+
height={rangeHeight}
|
|
147
|
+
class={cls(
|
|
148
|
+
'cursor-move select-none',
|
|
149
|
+
range?.fill == null && 'fill-surface-content/10',
|
|
150
|
+
classes.range
|
|
151
|
+
)}
|
|
152
|
+
on:pointerdown={adjustRange}
|
|
153
|
+
on:dblclick={() => reset()}
|
|
154
|
+
{...range}
|
|
155
|
+
/>
|
|
156
|
+
</slot>
|
|
157
|
+
</Group>
|
|
158
|
+
|
|
159
|
+
{#if axis === 'both' || axis === 'y'}
|
|
160
|
+
<Group
|
|
161
|
+
x={rangeLeft}
|
|
162
|
+
y={rangeTop}
|
|
163
|
+
class="handle top"
|
|
164
|
+
on:pointerdown={adjustTop}
|
|
165
|
+
on:dblclick={() => {
|
|
166
|
+
yDomain[0] = yDomainMin;
|
|
167
|
+
dispatch('change', { xDomain, yDomain });
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
170
|
+
<slot name="handle" edge="top" {rangeWidth} {rangeHeight}>
|
|
171
|
+
<rect
|
|
172
|
+
width={rangeWidth}
|
|
173
|
+
height={handleSize}
|
|
174
|
+
class={cls('fill-transparent cursor-ns-resize select-none', classes.handle)}
|
|
175
|
+
{...handle}
|
|
176
|
+
/>
|
|
177
|
+
</slot>
|
|
178
|
+
</Group>
|
|
179
|
+
|
|
180
|
+
<Group
|
|
181
|
+
x={rangeLeft}
|
|
182
|
+
y={bottom - handleSize + 1}
|
|
183
|
+
class="handle bottom"
|
|
184
|
+
on:pointerdown={adjustBottom}
|
|
185
|
+
on:dblclick={() => {
|
|
186
|
+
yDomain[1] = yDomainMax;
|
|
187
|
+
}}
|
|
188
|
+
>
|
|
189
|
+
<slot name="handle" edge="bottom" {rangeWidth} {rangeHeight}>
|
|
190
|
+
<rect
|
|
191
|
+
width={rangeWidth}
|
|
192
|
+
height={handleSize}
|
|
193
|
+
class={cls('fill-transparent cursor-ns-resize select-none', classes.handle)}
|
|
194
|
+
{...handle}
|
|
195
|
+
/>
|
|
196
|
+
</slot>
|
|
197
|
+
</Group>
|
|
198
|
+
{/if}
|
|
199
|
+
|
|
200
|
+
{#if axis === 'both' || axis === 'x'}
|
|
201
|
+
<Group
|
|
202
|
+
x={rangeLeft}
|
|
203
|
+
y={rangeTop}
|
|
204
|
+
class="handle left"
|
|
205
|
+
on:pointerdown={adjustLeft}
|
|
206
|
+
on:dblclick={() => {
|
|
207
|
+
xDomain[0] = xDomainMin;
|
|
208
|
+
dispatch('change', { xDomain, yDomain });
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
<slot name="handle" edge="left" {rangeWidth} {rangeHeight}>
|
|
212
|
+
<rect
|
|
213
|
+
width={handleSize}
|
|
214
|
+
height={rangeHeight}
|
|
215
|
+
class={cls('fill-transparent cursor-ew-resize select-none', classes.handle)}
|
|
216
|
+
{...handle}
|
|
217
|
+
/>
|
|
218
|
+
</slot>
|
|
219
|
+
</Group>
|
|
220
|
+
|
|
221
|
+
<Group
|
|
222
|
+
x={right - handleSize + 1}
|
|
223
|
+
y={rangeTop}
|
|
224
|
+
class="handle right"
|
|
225
|
+
on:pointerdown={adjustRight}
|
|
226
|
+
on:dblclick={() => {
|
|
227
|
+
xDomain[1] = xDomainMax;
|
|
228
|
+
dispatch('change', { xDomain, yDomain });
|
|
229
|
+
}}
|
|
230
|
+
>
|
|
231
|
+
<slot name="handle" edge="right" {rangeWidth} {rangeHeight}>
|
|
232
|
+
<rect
|
|
233
|
+
width={handleSize}
|
|
234
|
+
height={rangeHeight}
|
|
235
|
+
class={cls('fill-transparent cursor-ew-resize select-none', classes.handle)}
|
|
236
|
+
{...handle}
|
|
237
|
+
/>
|
|
238
|
+
</slot>
|
|
239
|
+
</Group>
|
|
240
|
+
{/if}
|
|
241
|
+
|
|
242
|
+
<!-- TODO: Add diagonal/corner handles -->
|
|
243
|
+
{/if}
|
|
244
|
+
</g>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { SVGAttributes } from 'svelte/elements';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
axis?: "x" | "y" | "both" | undefined;
|
|
7
|
+
handleSize?: number | undefined;
|
|
8
|
+
resetOnEnd?: boolean | undefined;
|
|
9
|
+
xDomain?: [number | null, number | null] | undefined;
|
|
10
|
+
yDomain?: [number | null, number | null] | undefined;
|
|
11
|
+
range?: SVGAttributes<SVGRectElement> | undefined;
|
|
12
|
+
handle?: SVGAttributes<SVGRectElement> | undefined;
|
|
13
|
+
classes?: {
|
|
14
|
+
root?: string | undefined;
|
|
15
|
+
frame?: string | undefined;
|
|
16
|
+
range?: string | undefined;
|
|
17
|
+
handle?: string | undefined;
|
|
18
|
+
} | undefined;
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
change: CustomEvent<{
|
|
22
|
+
xDomain?: [any, any] | undefined;
|
|
23
|
+
yDomain?: [any, any] | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
brushStart: CustomEvent<{
|
|
26
|
+
xDomain?: [any, any] | undefined;
|
|
27
|
+
yDomain?: [any, any] | undefined;
|
|
28
|
+
}>;
|
|
29
|
+
brushEnd: CustomEvent<{
|
|
30
|
+
xDomain?: [any, any] | undefined;
|
|
31
|
+
yDomain?: [any, any] | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
} & {
|
|
34
|
+
[evt: string]: CustomEvent<any>;
|
|
35
|
+
};
|
|
36
|
+
slots: {
|
|
37
|
+
range: {
|
|
38
|
+
rangeWidth: any;
|
|
39
|
+
rangeHeight: any;
|
|
40
|
+
};
|
|
41
|
+
handle: {
|
|
42
|
+
edge: string;
|
|
43
|
+
rangeWidth: any;
|
|
44
|
+
rangeHeight: any;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export type BrushProps = typeof __propDef.props;
|
|
49
|
+
export type BrushEvents = typeof __propDef.events;
|
|
50
|
+
export type BrushSlots = typeof __propDef.slots;
|
|
51
|
+
export default class Brush extends SvelteComponentTyped<BrushProps, BrushEvents, BrushSlots> {
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
@@ -76,8 +76,6 @@ export let tooltip = undefined;
|
|
|
76
76
|
/** Props passed to TransformContext */
|
|
77
77
|
export let transform = undefined;
|
|
78
78
|
export let transformContext = undefined;
|
|
79
|
-
/** Set transformContext's initial translate and scale based on geo object. Requires `geo.projection` to also be set */
|
|
80
|
-
export let fitGeoObject = undefined;
|
|
81
79
|
// Binded for access within TransformContext
|
|
82
80
|
let geoProjection = undefined;
|
|
83
81
|
// Track when mounted since LayerCake initializes width/height with `100` until binded `clientWidth`/`clientWidth` can run
|
|
@@ -115,9 +113,10 @@ onMount(() => {
|
|
|
115
113
|
let:data
|
|
116
114
|
let:flatData
|
|
117
115
|
>
|
|
116
|
+
<!-- Apply fitGeojson using TransformContext instead of GeoContext if `applyTransform` is used -->
|
|
118
117
|
{@const initialTransform =
|
|
119
|
-
|
|
120
|
-
? geoFitObjectTransform(geo.projection(), [width, height],
|
|
118
|
+
geo?.applyTransform && geo?.fitGeojson && geo?.projection
|
|
119
|
+
? geoFitObjectTransform(geo.projection(), [width, height], geo.fitGeojson)
|
|
121
120
|
: undefined}
|
|
122
121
|
|
|
123
122
|
{#key isMounted}
|
|
@@ -11,7 +11,6 @@ import { type ComponentProps } from 'svelte';
|
|
|
11
11
|
import GeoContext from './GeoContext.svelte';
|
|
12
12
|
import TooltipContext from './TooltipContext.svelte';
|
|
13
13
|
import TransformContext from './TransformContext.svelte';
|
|
14
|
-
import { geoFitObjectTransform } from '../utils/geo.js';
|
|
15
14
|
declare const __propDef: {
|
|
16
15
|
props: {
|
|
17
16
|
[x: string]: any;
|
|
@@ -25,7 +24,6 @@ declare const __propDef: {
|
|
|
25
24
|
tooltip?: Partial<ComponentProps<TooltipContext>> | boolean | undefined;
|
|
26
25
|
transform?: Partial<ComponentProps<TransformContext>> | undefined;
|
|
27
26
|
transformContext?: TransformContext | undefined;
|
|
28
|
-
fitGeoObject?: Parameters<typeof geoFitObjectTransform>[2] | undefined;
|
|
29
27
|
};
|
|
30
28
|
events: {
|
|
31
29
|
transform: CustomEvent<{
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<script>import { getContext } from 'svelte';
|
|
2
2
|
import RectClipPath from './RectClipPath.svelte';
|
|
3
3
|
const { width, height, padding } = getContext('LayerCake');
|
|
4
|
-
/**
|
|
5
|
-
export let
|
|
4
|
+
/** Include padding area (ex. axis) */
|
|
5
|
+
export let full = false;
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<RectClipPath
|
|
9
|
-
x={
|
|
10
|
-
y={
|
|
11
|
-
width={$width + (
|
|
12
|
-
height={$height + (
|
|
9
|
+
x={full ? -$padding.left : 0}
|
|
10
|
+
y={full ? -$padding.top : 0}
|
|
11
|
+
width={$width + (full ? $padding.left + $padding.right : 0)}
|
|
12
|
+
height={$height + (full ? $padding.top + $padding.bottom : 0)}
|
|
13
13
|
on:click
|
|
14
14
|
{...$$restProps}
|
|
15
15
|
>
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
const { width, height, padding } = getContext('LayerCake');
|
|
3
3
|
/** Include padding area */
|
|
4
4
|
export let full = false;
|
|
5
|
+
/** Access underlying `<rect>` element */
|
|
6
|
+
export let rectEl;
|
|
5
7
|
</script>
|
|
6
8
|
|
|
7
9
|
<rect
|
|
@@ -10,5 +12,8 @@ export let full = false;
|
|
|
10
12
|
width={$width + (full ? $padding.left + $padding.right : 0)}
|
|
11
13
|
height={$height + (full ? $padding.top + $padding.bottom : 0)}
|
|
12
14
|
on:click
|
|
15
|
+
on:pointerdown
|
|
16
|
+
on:dblclick
|
|
17
|
+
bind:this={rectEl}
|
|
13
18
|
{...$$restProps}
|
|
14
19
|
/>
|
|
@@ -3,9 +3,12 @@ declare const __propDef: {
|
|
|
3
3
|
props: {
|
|
4
4
|
[x: string]: any;
|
|
5
5
|
full?: boolean | undefined;
|
|
6
|
+
rectEl: SVGRectElement;
|
|
6
7
|
};
|
|
7
8
|
events: {
|
|
8
9
|
click: MouseEvent;
|
|
10
|
+
pointerdown: PointerEvent;
|
|
11
|
+
dblclick: MouseEvent;
|
|
9
12
|
} & {
|
|
10
13
|
[evt: string]: CustomEvent<any>;
|
|
11
14
|
};
|
|
@@ -112,6 +112,14 @@ function showTooltip(e, tooltipData) {
|
|
|
112
112
|
const point = localPoint(referenceNode, e);
|
|
113
113
|
const localX = point?.x ?? 0;
|
|
114
114
|
const localY = point?.y ?? 0;
|
|
115
|
+
if (e.offsetX < e.currentTarget.offsetLeft ||
|
|
116
|
+
e.offsetX > e.currentTarget.offsetLeft + e.currentTarget.offsetWidth ||
|
|
117
|
+
e.offsetY < e.currentTarget.offsetTop ||
|
|
118
|
+
e.offsetY > e.currentTarget.offsetTop + e.currentTarget.offsetHeight) {
|
|
119
|
+
// Ignore if within padding of chart
|
|
120
|
+
hideTooltip();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
115
123
|
// If tooltipData not provided already (voronoi, etc), attempt to find it
|
|
116
124
|
// TODO: When using bisect-x/y/band, values should be sorted. Tyipcally are for `x`, but not `y` (and band depends on if x or y scale)
|
|
117
125
|
if (tooltipData == null) {
|
|
@@ -267,26 +275,30 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
267
275
|
}
|
|
268
276
|
</script>
|
|
269
277
|
|
|
270
|
-
<slot tooltip={$tooltip} />
|
|
271
|
-
|
|
272
278
|
{#if ['bisect-x', 'bisect-y', 'bisect-band', 'quadtree'].includes(mode)}
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
279
|
+
<div
|
|
280
|
+
style:width="{$width}px"
|
|
281
|
+
style:height="{$height}px"
|
|
282
|
+
style:top="{$padding.top}px"
|
|
283
|
+
style:left="{$padding.left}px"
|
|
284
|
+
class={cls(
|
|
285
|
+
'tooltip-trigger absolute touch-none',
|
|
286
|
+
debug && 'bg-danger/10 outline outline-danger'
|
|
287
|
+
)}
|
|
288
|
+
on:pointerenter={showTooltip}
|
|
289
|
+
on:pointermove={showTooltip}
|
|
290
|
+
on:pointerleave={hideTooltip}
|
|
291
|
+
on:click={(e) => {
|
|
292
|
+
onClick({ data: $tooltip?.data });
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
<!-- Rendering slot within tooltip-trigger allows pointer events to bubble up (ex. Brush) -->
|
|
296
|
+
<div class="absolute" style:top="-{$padding.top}px" style:left="-{$padding.left}px">
|
|
297
|
+
<slot tooltip={$tooltip} />
|
|
298
|
+
</div>
|
|
299
|
+
</div>
|
|
289
300
|
{:else if mode === 'voronoi'}
|
|
301
|
+
<slot tooltip={$tooltip} />
|
|
290
302
|
<Svg>
|
|
291
303
|
<Voronoi
|
|
292
304
|
on:pointerenter={(e) => showTooltip(e.detail.event, e.detail.data)}
|
|
@@ -299,6 +311,7 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
299
311
|
/>
|
|
300
312
|
</Svg>
|
|
301
313
|
{:else if mode === 'bounds' || mode === 'band'}
|
|
314
|
+
<slot tooltip={$tooltip} />
|
|
302
315
|
<Svg>
|
|
303
316
|
<g class="tooltip-rects">
|
|
304
317
|
{#each rects as rect}
|
|
@@ -318,10 +331,12 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
318
331
|
{/each}
|
|
319
332
|
</g>
|
|
320
333
|
</Svg>
|
|
334
|
+
{:else}
|
|
335
|
+
<slot tooltip={$tooltip} />
|
|
321
336
|
{/if}
|
|
322
337
|
|
|
323
338
|
{#if mode === 'quadtree' && debug}
|
|
324
|
-
<Svg>
|
|
339
|
+
<Svg pointerEvents={false}>
|
|
325
340
|
<ChartClipPath>
|
|
326
341
|
<g class="tooltip-quadtree">
|
|
327
342
|
{#each quadtreeRects(quadtree, false) as rect}
|
|
@@ -11,6 +11,8 @@ const defaultContext = {
|
|
|
11
11
|
setTranslate: defaultTranslate.set,
|
|
12
12
|
moving: writable(false),
|
|
13
13
|
dragging: writable(false),
|
|
14
|
+
scrollMode: writable('none'),
|
|
15
|
+
setScrollMode: () => { },
|
|
14
16
|
reset: () => { },
|
|
15
17
|
zoomIn: () => { },
|
|
16
18
|
zoomOut: () => { },
|
|
@@ -29,6 +31,7 @@ function setTransformContext(transform) {
|
|
|
29
31
|
import { motionStore, motionFinishHandler } from '../stores/motionStore.js';
|
|
30
32
|
const { width, height } = getContext('LayerCake');
|
|
31
33
|
export let mode = 'none';
|
|
34
|
+
/** Translate towards point (ex. mouse cursor/center) while zooming in/out */
|
|
32
35
|
export let translateOnScale = false;
|
|
33
36
|
export let spring = undefined;
|
|
34
37
|
export let tweened = undefined;
|
|
@@ -41,12 +44,13 @@ export let processTranslate = (x, y, deltaX, deltaY, scale) => {
|
|
|
41
44
|
/** Disable pointer events including move/dragging. Useful for `mode="canvas" but only want zoomTo() interactions */
|
|
42
45
|
export let disablePointer = false;
|
|
43
46
|
/** Action to take during wheel scroll */
|
|
44
|
-
export let
|
|
47
|
+
export let initialScrollMode = 'none';
|
|
45
48
|
/** Distance/threshold to consider drag vs click (disable click propagation) */
|
|
46
49
|
export let clickDistance = 10;
|
|
47
50
|
const dispatch = createEventDispatcher();
|
|
48
51
|
let pointerDown = false;
|
|
49
52
|
const dragging = writable(false);
|
|
53
|
+
const scrollMode = writable(initialScrollMode);
|
|
50
54
|
const DEFAULT_TRANSLATE = { x: 0, y: 0 };
|
|
51
55
|
export let initialTranslate = undefined;
|
|
52
56
|
export const translate = motionStore(initialTranslate ?? DEFAULT_TRANSLATE, { spring, tweened });
|
|
@@ -55,6 +59,9 @@ export let initialScale = undefined;
|
|
|
55
59
|
export const scale = motionStore(initialScale ?? DEFAULT_SCALE, { spring, tweened });
|
|
56
60
|
let startPoint = { x: 0, y: 0 };
|
|
57
61
|
let startTranslate = { x: 0, y: 0 };
|
|
62
|
+
export function setScrollMode(mode) {
|
|
63
|
+
$scrollMode = mode;
|
|
64
|
+
}
|
|
58
65
|
export function reset() {
|
|
59
66
|
$translate = initialTranslate ?? DEFAULT_TRANSLATE;
|
|
60
67
|
$scale = initialScale ?? DEFAULT_SCALE;
|
|
@@ -126,18 +133,18 @@ function onDoubleClick(e) {
|
|
|
126
133
|
scaleTo(e.shiftKey ? 0.5 : 2, point);
|
|
127
134
|
}
|
|
128
135
|
function onWheel(e) {
|
|
129
|
-
if (mode === 'none' || disablePointer ||
|
|
136
|
+
if (mode === 'none' || disablePointer || $scrollMode === 'none')
|
|
130
137
|
return;
|
|
131
138
|
e.preventDefault();
|
|
132
139
|
const point = (startPoint = localPoint(e));
|
|
133
140
|
// Pinch to zoom is registered as a wheel event with control key
|
|
134
141
|
const pinchToZoom = e.ctrlKey;
|
|
135
|
-
if (
|
|
142
|
+
if ($scrollMode === 'scale' || pinchToZoom) {
|
|
136
143
|
// https://github.com/d3/d3-zoom#zoom_wheelDelta
|
|
137
144
|
const scaleBy = -e.deltaY * (e.deltaMode === 1 ? 0.05 : e.deltaMode ? 1 : 0.002) * (e.ctrlKey ? 10 : 1);
|
|
138
145
|
scaleTo(Math.pow(2, scaleBy), point, spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
|
|
139
146
|
}
|
|
140
|
-
else if (
|
|
147
|
+
else if ($scrollMode === 'translate') {
|
|
141
148
|
translate.update((startTranslate) => processTranslate(startTranslate.x, startTranslate.y, -e.deltaX, -e.deltaY, $scale), spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
|
|
142
149
|
}
|
|
143
150
|
}
|
|
@@ -195,6 +202,8 @@ setTransformContext({
|
|
|
195
202
|
zoomOut,
|
|
196
203
|
translateCenter,
|
|
197
204
|
zoomTo,
|
|
205
|
+
scrollMode,
|
|
206
|
+
setScrollMode,
|
|
198
207
|
});
|
|
199
208
|
</script>
|
|
200
209
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
import { type Readable, type Writable } from 'svelte/store';
|
|
3
3
|
export declare const transformContextKey: unique symbol;
|
|
4
|
+
type TransformMode = 'canvas' | 'manual' | 'none';
|
|
5
|
+
type TransformScrollMode = 'scale' | 'translate' | 'none';
|
|
4
6
|
export type TransformContextValue = {
|
|
5
|
-
mode:
|
|
7
|
+
mode: TransformMode;
|
|
6
8
|
scale: Writable<number>;
|
|
7
9
|
setScale(value: number, options?: MotionOptions): void;
|
|
8
10
|
translate: Writable<{
|
|
@@ -15,6 +17,8 @@ export type TransformContextValue = {
|
|
|
15
17
|
}, options?: MotionOptions): void;
|
|
16
18
|
moving: Readable<boolean>;
|
|
17
19
|
dragging: Readable<boolean>;
|
|
20
|
+
scrollMode: Readable<TransformScrollMode>;
|
|
21
|
+
setScrollMode(mode: TransformScrollMode): void;
|
|
18
22
|
reset(): void;
|
|
19
23
|
zoomIn(): void;
|
|
20
24
|
zoomOut(): void;
|
|
@@ -32,8 +36,8 @@ export declare function transformContext(): TransformContext;
|
|
|
32
36
|
import { motionStore, type MotionOptions } from '../stores/motionStore.js';
|
|
33
37
|
declare const __propDef: {
|
|
34
38
|
props: {
|
|
35
|
-
mode?:
|
|
36
|
-
translateOnScale?: boolean | undefined;
|
|
39
|
+
mode?: TransformMode | undefined;
|
|
40
|
+
/** Translate towards point (ex. mouse cursor/center) while zooming in/out */ translateOnScale?: boolean | undefined;
|
|
37
41
|
spring?: boolean | Parameters<typeof motionStore>[1]['spring'];
|
|
38
42
|
tweened?: boolean | Parameters<typeof motionStore>[1]['tweened'];
|
|
39
43
|
processTranslate?: ((x: number, y: number, deltaX: number, deltaY: number, scale: number) => {
|
|
@@ -41,7 +45,7 @@ declare const __propDef: {
|
|
|
41
45
|
y: number;
|
|
42
46
|
}) | undefined;
|
|
43
47
|
/** Disable pointer events including move/dragging. Useful for `mode="canvas" but only want zoomTo() interactions */ disablePointer?: boolean | undefined;
|
|
44
|
-
/** Action to take during wheel scroll */
|
|
48
|
+
/** Action to take during wheel scroll */ initialScrollMode?: TransformScrollMode | undefined;
|
|
45
49
|
/** Distance/threshold to consider drag vs click (disable click propagation) */ clickDistance?: number | undefined;
|
|
46
50
|
initialTranslate?: {
|
|
47
51
|
x: number;
|
|
@@ -59,6 +63,7 @@ declare const __propDef: {
|
|
|
59
63
|
}> | undefined;
|
|
60
64
|
initialScale?: number | undefined;
|
|
61
65
|
scale?: import("svelte/motion").Spring<number> | import("svelte/motion").Tweened<number> | Writable<number> | undefined;
|
|
66
|
+
setScrollMode?: ((mode: TransformScrollMode) => void) | undefined;
|
|
62
67
|
reset?: (() => void) | undefined;
|
|
63
68
|
zoomIn?: (() => void) | undefined;
|
|
64
69
|
zoomOut?: (() => void) | undefined;
|
|
@@ -133,6 +138,7 @@ export default class TransformContext extends SvelteComponentTyped<TransformCont
|
|
|
133
138
|
y: number;
|
|
134
139
|
}> | undefined>;
|
|
135
140
|
get scale(): NonNullable<import("svelte/motion").Spring<number> | import("svelte/motion").Tweened<number> | Writable<number> | undefined>;
|
|
141
|
+
get setScrollMode(): (mode: TransformScrollMode) => void;
|
|
136
142
|
get reset(): () => void;
|
|
137
143
|
get zoomIn(): () => void;
|
|
138
144
|
get zoomOut(): () => void;
|
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
<script>import { Button, Tooltip, cls } from 'svelte-ux';
|
|
2
|
-
import { mdiArrowULeftTop, mdiMagnifyPlusOutline, mdiMagnifyMinusOutline, mdiImageFilterCenterFocus, } from '@mdi/js';
|
|
1
|
+
<script>import { Button, Icon, MenuButton, Tooltip, cls } from 'svelte-ux';
|
|
2
|
+
import { mdiArrowULeftTop, mdiMagnifyPlusOutline, mdiMagnifyMinusOutline, mdiImageFilterCenterFocus, mdiChevronDown, mdiResize, mdiArrowExpandAll, mdiCancel, } from '@mdi/js';
|
|
3
3
|
import { transformContext } from './TransformContext.svelte';
|
|
4
4
|
export let placement = 'top-right';
|
|
5
5
|
export let orientation = 'vertical';
|
|
6
|
+
export let show = ['zoomIn', 'zoomOut', 'center', 'reset', 'scrollMode'];
|
|
7
|
+
$: menuPlacementByOrientationAndPlacement = {
|
|
8
|
+
horizontal: {
|
|
9
|
+
'top-left': 'bottom-end',
|
|
10
|
+
top: 'bottom-end',
|
|
11
|
+
'top-right': 'bottom-end',
|
|
12
|
+
left: 'bottom-end',
|
|
13
|
+
center: 'bottom-end',
|
|
14
|
+
right: 'bottom-end',
|
|
15
|
+
'bottom-left': 'top-end',
|
|
16
|
+
bottom: 'top-end',
|
|
17
|
+
'bottom-right': 'top-end',
|
|
18
|
+
},
|
|
19
|
+
vertical: {
|
|
20
|
+
'top-left': 'right-start',
|
|
21
|
+
top: 'right-start',
|
|
22
|
+
'top-right': 'left-start',
|
|
23
|
+
left: 'right-start',
|
|
24
|
+
center: 'right-start',
|
|
25
|
+
right: 'left-start',
|
|
26
|
+
'bottom-left': 'right-end',
|
|
27
|
+
bottom: 'right-end',
|
|
28
|
+
'bottom-right': 'left-end',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
6
31
|
const transform = transformContext();
|
|
32
|
+
const scrollMode = transform.scrollMode;
|
|
7
33
|
</script>
|
|
8
34
|
|
|
9
35
|
<div
|
|
@@ -23,33 +49,70 @@ const transform = transformContext();
|
|
|
23
49
|
}[placement],
|
|
24
50
|
$$props.class
|
|
25
51
|
)}
|
|
52
|
+
on:dblclick={(e) => {
|
|
53
|
+
// Stop from propagating to TransformContext
|
|
54
|
+
e.stopPropagation();
|
|
55
|
+
}}
|
|
26
56
|
>
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
{#if show.includes('zoomIn')}
|
|
58
|
+
<Tooltip title="Zoom in">
|
|
59
|
+
<Button
|
|
60
|
+
icon={mdiMagnifyPlusOutline}
|
|
61
|
+
on:click={() => transform.zoomIn()}
|
|
62
|
+
class="text-surface-content p-2"
|
|
63
|
+
/>
|
|
64
|
+
</Tooltip>
|
|
65
|
+
{/if}
|
|
66
|
+
|
|
67
|
+
{#if show.includes('zoomOut')}
|
|
68
|
+
<Tooltip title="Zoom out">
|
|
69
|
+
<Button
|
|
70
|
+
icon={mdiMagnifyMinusOutline}
|
|
71
|
+
on:click={() => transform.zoomOut()}
|
|
72
|
+
class="text-surface-content p-2"
|
|
73
|
+
/>
|
|
74
|
+
</Tooltip>
|
|
75
|
+
{/if}
|
|
76
|
+
|
|
77
|
+
{#if show.includes('center')}
|
|
78
|
+
<Tooltip title="Center">
|
|
79
|
+
<Button
|
|
80
|
+
icon={mdiImageFilterCenterFocus}
|
|
81
|
+
on:click={() => transform.translateCenter()}
|
|
82
|
+
class="text-surface-content p-2"
|
|
83
|
+
/>
|
|
84
|
+
</Tooltip>
|
|
85
|
+
{/if}
|
|
86
|
+
|
|
87
|
+
{#if show.includes('reset')}
|
|
88
|
+
<Tooltip title="Reset">
|
|
89
|
+
<Button
|
|
90
|
+
icon={mdiArrowULeftTop}
|
|
91
|
+
on:click={() => transform.reset()}
|
|
92
|
+
class="text-surface-content p-2"
|
|
93
|
+
/>
|
|
94
|
+
</Tooltip>
|
|
95
|
+
{/if}
|
|
96
|
+
|
|
97
|
+
{#if show.includes('scrollMode')}
|
|
98
|
+
<Tooltip title="Scroll mode">
|
|
99
|
+
<MenuButton
|
|
100
|
+
iconOnly
|
|
101
|
+
options={[
|
|
102
|
+
{ label: 'None', value: 'none', icon: mdiCancel },
|
|
103
|
+
{ label: 'Zoom', value: 'scale', icon: mdiResize },
|
|
104
|
+
{ label: 'Move', value: 'translate', icon: mdiArrowExpandAll },
|
|
105
|
+
]}
|
|
106
|
+
menuProps={{ placement: menuPlacementByOrientationAndPlacement[orientation][placement] }}
|
|
107
|
+
menuIcon={null}
|
|
108
|
+
value={$scrollMode}
|
|
109
|
+
on:change={(e) => transform.setScrollMode(e.detail.value)}
|
|
110
|
+
class="text-surface-content"
|
|
111
|
+
>
|
|
112
|
+
<svelte:fragment slot="selection" let:value>
|
|
113
|
+
<Icon data={value?.icon ?? mdiChevronDown} />
|
|
114
|
+
</svelte:fragment>
|
|
115
|
+
</MenuButton>
|
|
116
|
+
</Tooltip>
|
|
117
|
+
{/if}
|
|
55
118
|
</div>
|
|
@@ -4,6 +4,7 @@ declare const __propDef: {
|
|
|
4
4
|
[x: string]: any;
|
|
5
5
|
placement?: ("center" | "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
|
|
6
6
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
7
|
+
show?: ("reset" | "center" | "scrollMode" | "zoomIn" | "zoomOut")[] | undefined;
|
|
7
8
|
};
|
|
8
9
|
events: {
|
|
9
10
|
[evt: string]: CustomEvent<any>;
|
|
@@ -6,6 +6,7 @@ export { default as Axis } from './Axis.svelte';
|
|
|
6
6
|
export { default as Bar } from './Bar.svelte';
|
|
7
7
|
export { default as Bars } from './Bars.svelte';
|
|
8
8
|
export { default as Blur } from './Blur.svelte';
|
|
9
|
+
export { default as Brush } from './Brush.svelte';
|
|
9
10
|
export { default as Bounds } from './Bounds.svelte';
|
|
10
11
|
export { default as Calendar } from './Calendar.svelte';
|
|
11
12
|
export { default as Canvas } from './layout/Canvas.svelte';
|
package/dist/components/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export { default as Axis } from './Axis.svelte';
|
|
|
7
7
|
export { default as Bar } from './Bar.svelte';
|
|
8
8
|
export { default as Bars } from './Bars.svelte';
|
|
9
9
|
export { default as Blur } from './Blur.svelte';
|
|
10
|
+
export { default as Brush } from './Brush.svelte';
|
|
10
11
|
export { default as Bounds } from './Bounds.svelte';
|
|
11
12
|
export { default as Calendar } from './Calendar.svelte';
|
|
12
13
|
export { default as Canvas } from './layout/Canvas.svelte';
|
package/dist/utils/genData.d.ts
CHANGED
|
@@ -8,6 +8,12 @@ export declare function getRandomNumber(min: number, max: number): number;
|
|
|
8
8
|
* see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#getting_a_random_integer_between_two_values_inclusive
|
|
9
9
|
*/
|
|
10
10
|
export declare function getRandomInteger(min: number, max: number, includeMax?: boolean): number;
|
|
11
|
+
/**
|
|
12
|
+
* @see: https://observablehq.com/@d3/d3-cumsum
|
|
13
|
+
*/
|
|
14
|
+
export declare function randomWalk(options?: {
|
|
15
|
+
count?: number;
|
|
16
|
+
}): number[];
|
|
11
17
|
export declare function createSeries(options: {
|
|
12
18
|
count?: number;
|
|
13
19
|
min: number;
|
package/dist/utils/genData.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { addMinutes, startOfDay, startOfToday, subDays } from 'date-fns';
|
|
2
|
+
import { cumsum } from 'd3-array';
|
|
3
|
+
import { randomNormal } from 'd3-random';
|
|
2
4
|
import { degreesToRadians, radiansToDegrees } from './math.js';
|
|
3
5
|
/**
|
|
4
6
|
* Get random number between min (inclusive) and max (exclusive)
|
|
@@ -16,6 +18,13 @@ export function getRandomInteger(min, max, includeMax = true) {
|
|
|
16
18
|
max = Math.floor(max);
|
|
17
19
|
return Math.floor(Math.random() * (max - min + (includeMax ? 1 : 0)) + min);
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* @see: https://observablehq.com/@d3/d3-cumsum
|
|
23
|
+
*/
|
|
24
|
+
export function randomWalk(options) {
|
|
25
|
+
const random = randomNormal();
|
|
26
|
+
return Array.from(cumsum({ length: options?.count ?? 100 }, random));
|
|
27
|
+
}
|
|
19
28
|
export function createSeries(options) {
|
|
20
29
|
const count = options.count ?? 10;
|
|
21
30
|
const min = options.min;
|
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.
|
|
7
|
+
"version": "0.40.0",
|
|
8
8
|
"devDependencies": {
|
|
9
9
|
"@changesets/cli": "^2.27.5",
|
|
10
10
|
"@mdi/js": "^7.4.47",
|
|
@@ -36,29 +36,29 @@
|
|
|
36
36
|
"@types/topojson-simplify": "^3.0.3",
|
|
37
37
|
"autoprefixer": "^10.4.19",
|
|
38
38
|
"marked": "^12.0.2",
|
|
39
|
-
"mdsvex": "^0.11.
|
|
39
|
+
"mdsvex": "^0.11.2",
|
|
40
40
|
"posthog-js": "^1.95.1",
|
|
41
|
-
"prettier": "^3.
|
|
42
|
-
"prettier-plugin-svelte": "^3.2.
|
|
41
|
+
"prettier": "^3.3.1",
|
|
42
|
+
"prettier-plugin-svelte": "^3.2.4",
|
|
43
43
|
"prism-svelte": "^0.5.0",
|
|
44
44
|
"prism-themes": "^1.9.0",
|
|
45
45
|
"prismjs": "^1.29.0",
|
|
46
46
|
"rehype-slug": "^6.0.0",
|
|
47
47
|
"shapefile": "^0.6.6",
|
|
48
48
|
"solar-calculator": "^0.3.0",
|
|
49
|
-
"svelte": "^4.2.
|
|
49
|
+
"svelte": "^4.2.18",
|
|
50
50
|
"svelte-check": "^3.8.0",
|
|
51
51
|
"svelte-json-tree": "^2.2.0",
|
|
52
52
|
"svelte-preprocess": "^5.1.4",
|
|
53
53
|
"svelte2tsx": "^0.7.9",
|
|
54
|
-
"tailwindcss": "^3.4.
|
|
54
|
+
"tailwindcss": "^3.4.4",
|
|
55
55
|
"topojson-client": "^3.1.0",
|
|
56
56
|
"topojson-simplify": "^3.0.3",
|
|
57
|
-
"tslib": "^2.6.
|
|
57
|
+
"tslib": "^2.6.3",
|
|
58
58
|
"typescript": "^5.4.5",
|
|
59
59
|
"unist-util-visit": "^5.0.0",
|
|
60
60
|
"us-atlas": "^3.0.1",
|
|
61
|
-
"vite": "^5.2.
|
|
61
|
+
"vite": "^5.2.13"
|
|
62
62
|
},
|
|
63
63
|
"type": "module",
|
|
64
64
|
"dependencies": {
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
"d3-tile": "^1.0.0",
|
|
84
84
|
"d3-time": "^3.1.0",
|
|
85
85
|
"date-fns": "^3.6.0",
|
|
86
|
-
"layercake": "^8.
|
|
86
|
+
"layercake": "^8.3.0",
|
|
87
87
|
"lodash-es": "^4.17.21",
|
|
88
|
-
"posthog-js": "^1.
|
|
88
|
+
"posthog-js": "^1.138.3",
|
|
89
89
|
"shapefile": "^0.6.6",
|
|
90
|
-
"svelte-ux": "^0.66.
|
|
90
|
+
"svelte-ux": "^0.66.6",
|
|
91
91
|
"topojson-client": "^3.1.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|