layerchart 0.80.0 → 0.81.1
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { type ComponentProps } from 'svelte';
|
|
3
3
|
import type { SVGAttributes } from 'svelte/elements';
|
|
4
4
|
import { extent, min, max } from 'd3-array';
|
|
5
5
|
import { clamp } from '@layerstack/utils';
|
|
@@ -17,12 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
const { xScale, yScale, width, height, padding } = chartContext();
|
|
19
19
|
|
|
20
|
-
const dispatch = createEventDispatcher<{
|
|
21
|
-
change: { xDomain?: DomainType; yDomain?: DomainType };
|
|
22
|
-
brushStart: { xDomain?: DomainType; yDomain?: DomainType };
|
|
23
|
-
brushEnd: { xDomain?: DomainType; yDomain?: DomainType };
|
|
24
|
-
}>();
|
|
25
|
-
|
|
26
20
|
/** Axis to apply brushing */
|
|
27
21
|
export let axis: 'x' | 'y' | 'both' = 'x';
|
|
28
22
|
|
|
@@ -37,6 +31,12 @@
|
|
|
37
31
|
|
|
38
32
|
export let labels: ComponentProps<Text> | boolean = false;
|
|
39
33
|
|
|
34
|
+
/** Mode of operation
|
|
35
|
+
* `integrated`: use with single chart
|
|
36
|
+
* `separated`: use with separate (typically smaller) chart and state can be managed externally (sync with other charts, etc). Show active selection when domain does not equal original
|
|
37
|
+
*/
|
|
38
|
+
export let mode: 'integrated' | 'separated' = 'integrated';
|
|
39
|
+
|
|
40
40
|
// Capture original domains for reset()
|
|
41
41
|
const originalXDomain = $xScale.domain() as [number, number];
|
|
42
42
|
const originalYDomain = $yScale.domain() as [number, number];
|
|
@@ -61,6 +61,10 @@
|
|
|
61
61
|
labels?: string;
|
|
62
62
|
} = {};
|
|
63
63
|
|
|
64
|
+
export let onChange: (e: { xDomain?: DomainType; yDomain?: DomainType }) => void = () => {};
|
|
65
|
+
export let onBrushStart: (e: { xDomain?: DomainType; yDomain?: DomainType }) => void = () => {};
|
|
66
|
+
export let onBrushEnd: (e: { xDomain?: DomainType; yDomain?: DomainType }) => void = () => {};
|
|
67
|
+
|
|
64
68
|
let frameEl: SVGRectElement;
|
|
65
69
|
|
|
66
70
|
function handler(
|
|
@@ -83,7 +87,7 @@
|
|
|
83
87
|
},
|
|
84
88
|
};
|
|
85
89
|
|
|
86
|
-
|
|
90
|
+
onBrushStart({ xDomain, yDomain });
|
|
87
91
|
|
|
88
92
|
const onPointerMove = (e: PointerEvent) => {
|
|
89
93
|
fn(start, {
|
|
@@ -95,17 +99,17 @@
|
|
|
95
99
|
// // Ignore?
|
|
96
100
|
// // TODO: What about when using `x` or `y` axis?
|
|
97
101
|
// } else {
|
|
98
|
-
|
|
102
|
+
onChange({ xDomain, yDomain });
|
|
99
103
|
// }
|
|
100
104
|
};
|
|
101
105
|
|
|
102
106
|
const onPointerUp = (e: PointerEvent) => {
|
|
103
107
|
if (e.target === frameEl) {
|
|
104
108
|
reset();
|
|
105
|
-
|
|
109
|
+
onChange({ xDomain, yDomain });
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
|
|
112
|
+
onBrushEnd({ xDomain, yDomain });
|
|
109
113
|
|
|
110
114
|
if (resetOnEnd) {
|
|
111
115
|
reset();
|
|
@@ -214,12 +218,15 @@
|
|
|
214
218
|
$: rangeWidth = axis === 'both' || axis === 'x' ? right - left : $width;
|
|
215
219
|
$: rangeHeight = axis === 'both' || axis === 'y' ? bottom - top : $height;
|
|
216
220
|
|
|
217
|
-
|
|
218
|
-
$:
|
|
219
|
-
xDomain
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
let isActive = false;
|
|
222
|
+
$: if (mode === 'separated') {
|
|
223
|
+
// Set reactively to handle cases where xDomain/yDomain are set externally (ex. `bind:xDomain`)
|
|
224
|
+
isActive =
|
|
225
|
+
xDomain?.[0]?.valueOf() !== originalXDomain[0]?.valueOf() ||
|
|
226
|
+
xDomain?.[1]?.valueOf() !== originalXDomain[1]?.valueOf() ||
|
|
227
|
+
yDomain?.[0]?.valueOf() !== originalYDomain[0]?.valueOf() ||
|
|
228
|
+
yDomain?.[1]?.valueOf() !== originalYDomain[1]?.valueOf();
|
|
229
|
+
}
|
|
223
230
|
</script>
|
|
224
231
|
|
|
225
232
|
<g class={cls('Brush select-none', classes.root, $$props.class)}>
|
|
@@ -258,7 +265,7 @@
|
|
|
258
265
|
on:dblclick={() => {
|
|
259
266
|
if (yDomain) {
|
|
260
267
|
yDomain[0] = yDomainMin;
|
|
261
|
-
|
|
268
|
+
onChange({ xDomain, yDomain });
|
|
262
269
|
}
|
|
263
270
|
}}
|
|
264
271
|
>
|
|
@@ -303,7 +310,7 @@
|
|
|
303
310
|
on:dblclick={() => {
|
|
304
311
|
if (xDomain) {
|
|
305
312
|
xDomain[0] = xDomainMin;
|
|
306
|
-
|
|
313
|
+
onChange({ xDomain, yDomain });
|
|
307
314
|
}
|
|
308
315
|
}}
|
|
309
316
|
>
|
|
@@ -325,7 +332,7 @@
|
|
|
325
332
|
on:dblclick={() => {
|
|
326
333
|
if (xDomain) {
|
|
327
334
|
xDomain[1] = xDomainMax;
|
|
328
|
-
|
|
335
|
+
onChange({ xDomain, yDomain });
|
|
329
336
|
}
|
|
330
337
|
}}
|
|
331
338
|
>
|
|
@@ -13,6 +13,7 @@ declare const __propDef: {
|
|
|
13
13
|
xDomain?: DomainType | undefined;
|
|
14
14
|
yDomain?: DomainType | undefined;
|
|
15
15
|
labels?: (ComponentProps<Text> | boolean) | undefined;
|
|
16
|
+
mode?: "integrated" | "separated" | undefined;
|
|
16
17
|
range?: SVGAttributes<SVGRectElement> | undefined;
|
|
17
18
|
handle?: SVGAttributes<SVGRectElement> | undefined;
|
|
18
19
|
format?: FormatType | undefined;
|
|
@@ -23,21 +24,20 @@ declare const __propDef: {
|
|
|
23
24
|
handle?: string;
|
|
24
25
|
labels?: string;
|
|
25
26
|
} | undefined;
|
|
26
|
-
|
|
27
|
-
events: {
|
|
28
|
-
change: CustomEvent<{
|
|
27
|
+
onChange?: ((e: {
|
|
29
28
|
xDomain?: DomainType;
|
|
30
29
|
yDomain?: DomainType;
|
|
31
|
-
}
|
|
32
|
-
|
|
30
|
+
}) => void) | undefined;
|
|
31
|
+
onBrushStart?: ((e: {
|
|
33
32
|
xDomain?: DomainType;
|
|
34
33
|
yDomain?: DomainType;
|
|
35
|
-
}
|
|
36
|
-
|
|
34
|
+
}) => void) | undefined;
|
|
35
|
+
onBrushEnd?: ((e: {
|
|
37
36
|
xDomain?: DomainType;
|
|
38
37
|
yDomain?: DomainType;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
38
|
+
}) => void) | undefined;
|
|
39
|
+
};
|
|
40
|
+
events: {
|
|
41
41
|
[evt: string]: CustomEvent<any>;
|
|
42
42
|
};
|
|
43
43
|
slots: {
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
$: stackSeries = seriesLayout.startsWith('stack');
|
|
76
76
|
|
|
77
77
|
export let axis: ComponentProps<Axis> | 'x' | 'y' | boolean = true;
|
|
78
|
-
export let brush:
|
|
78
|
+
export let brush: ComponentProps<Brush> | boolean = false;
|
|
79
79
|
export let grid: ComponentProps<Grid> | boolean = true;
|
|
80
80
|
export let labels: ComponentProps<Labels> | boolean = false;
|
|
81
81
|
export let legend: ComponentProps<Legend> | boolean = false;
|
|
@@ -396,17 +396,18 @@
|
|
|
396
396
|
{/if}
|
|
397
397
|
</svelte:component>
|
|
398
398
|
|
|
399
|
-
{#if brush && brush.mode === 'integrated'}
|
|
399
|
+
{#if brush && (brush === true || brush.mode == undefined || brush.mode === 'integrated')}
|
|
400
400
|
<Svg>
|
|
401
|
+
{@const brushProps = { ...(typeof brush === 'object' ? brush : null), ...props.brush }}
|
|
401
402
|
<Brush
|
|
402
403
|
axis="x"
|
|
403
404
|
resetOnEnd
|
|
404
405
|
{xDomain}
|
|
405
|
-
|
|
406
|
-
|
|
406
|
+
{...brushProps}
|
|
407
|
+
onBrushEnd={(e) => {
|
|
408
|
+
xDomain = e.xDomain;
|
|
409
|
+
brushProps.onBrushEnd?.(e);
|
|
407
410
|
}}
|
|
408
|
-
{...typeof brush === 'object' ? brush : null}
|
|
409
|
-
{...props.brush}
|
|
410
411
|
/>
|
|
411
412
|
</Svg>
|
|
412
413
|
{/if}
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
$: isDefaultSeries = series.length === 1 && series[0].key === 'default';
|
|
68
68
|
|
|
69
69
|
export let axis: ComponentProps<Axis> | 'x' | 'y' | boolean = true;
|
|
70
|
-
export let brush:
|
|
70
|
+
export let brush: ComponentProps<Brush> | boolean = false;
|
|
71
71
|
export let grid: ComponentProps<Grid> | boolean = true;
|
|
72
72
|
export let labels: ComponentProps<Labels> | boolean = false;
|
|
73
73
|
export let legend: ComponentProps<Legend> | boolean = false;
|
|
@@ -322,17 +322,18 @@
|
|
|
322
322
|
</slot>
|
|
323
323
|
</svelte:component>
|
|
324
324
|
|
|
325
|
-
{#if brush && brush.mode === 'integrated'}
|
|
325
|
+
{#if brush && (brush === true || brush.mode == undefined || brush.mode === 'integrated')}
|
|
326
326
|
<Svg>
|
|
327
|
+
{@const brushProps = { ...(typeof brush === 'object' ? brush : null), ...props.brush }}
|
|
327
328
|
<Brush
|
|
328
329
|
axis="x"
|
|
329
330
|
resetOnEnd
|
|
330
331
|
{xDomain}
|
|
331
|
-
|
|
332
|
-
|
|
332
|
+
{...brushProps}
|
|
333
|
+
onBrushEnd={(e) => {
|
|
334
|
+
xDomain = e.xDomain;
|
|
335
|
+
brushProps.onBrushEnd?.(e);
|
|
333
336
|
}}
|
|
334
|
-
{...typeof brush === 'object' ? brush : null}
|
|
335
|
-
{...props.brush}
|
|
336
337
|
/>
|
|
337
338
|
</Svg>
|
|
338
339
|
{/if}
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
$: isDefaultSeries = series.length === 1 && series[0].key === 'default';
|
|
59
59
|
|
|
60
60
|
export let axis: ComponentProps<Axis> | 'x' | 'y' | boolean = true;
|
|
61
|
-
export let brush:
|
|
61
|
+
export let brush: ComponentProps<Brush> | boolean = false;
|
|
62
62
|
export let grid: ComponentProps<Grid> | boolean = true;
|
|
63
63
|
export let labels: ComponentProps<Labels> | boolean = false;
|
|
64
64
|
export let legend: ComponentProps<Legend> | boolean = false;
|
|
@@ -270,19 +270,20 @@
|
|
|
270
270
|
</svelte:component>
|
|
271
271
|
|
|
272
272
|
<!-- TODO: Determine how to coordinate with `tooltip={{ mode: 'voronoi' }} -->
|
|
273
|
-
{#if brush && brush.mode === 'integrated'}
|
|
273
|
+
{#if brush && (brush === true || brush.mode == undefined || brush.mode === 'integrated')}
|
|
274
274
|
<Svg>
|
|
275
|
+
{@const brushProps = { ...(typeof brush === 'object' ? brush : null), ...props.brush }}
|
|
275
276
|
<Brush
|
|
276
277
|
axis="both"
|
|
277
278
|
resetOnEnd
|
|
278
279
|
{xDomain}
|
|
279
280
|
{yDomain}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
{...brushProps}
|
|
282
|
+
onBrushEnd={(e) => {
|
|
283
|
+
xDomain = e.xDomain;
|
|
284
|
+
yDomain = e.yDomain;
|
|
285
|
+
brushProps.onBrushEnd?.(e);
|
|
283
286
|
}}
|
|
284
|
-
{...typeof brush === 'object' ? brush : null}
|
|
285
|
-
{...props.brush}
|
|
286
287
|
/>
|
|
287
288
|
</Svg>
|
|
288
289
|
{/if}
|