layerchart 0.92.0 → 0.93.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/BrushContext.svelte +476 -0
- package/dist/components/BrushContext.svelte.d.ts +73 -0
- package/dist/components/Chart.svelte +64 -47
- package/dist/components/Chart.svelte.d.ts +51 -12
- package/dist/components/charts/AreaChart.svelte +27 -22
- package/dist/components/charts/LineChart.svelte +23 -21
- package/dist/components/charts/PieChart.svelte.d.ts +45 -9
- package/dist/components/charts/ScatterChart.svelte +21 -24
- package/dist/components/index.d.ts +0 -1
- package/dist/components/index.js +0 -1
- package/dist/components/tooltip/TooltipContext.svelte +7 -7
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +2 -2
- package/dist/utils/math.d.ts +2 -0
- package/dist/utils/math.js +9 -0
- package/package.json +1 -1
- package/dist/components/Brush.svelte +0 -418
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
<script lang="ts" context="module">
|
|
2
|
+
import { getContext, setContext } from 'svelte';
|
|
3
|
+
import { writable, type Readable } from 'svelte/store';
|
|
4
|
+
|
|
5
|
+
export const brushContextKey = Symbol();
|
|
6
|
+
|
|
7
|
+
export type BrushContextValue = {
|
|
8
|
+
xDomain: DomainType;
|
|
9
|
+
yDomain: DomainType;
|
|
10
|
+
isActive: boolean;
|
|
11
|
+
range: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
};
|
|
17
|
+
handleSize: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type BrushContext = Readable<BrushContextValue>;
|
|
21
|
+
|
|
22
|
+
const defaultContext: BrushContext = writable({
|
|
23
|
+
xDomain: null,
|
|
24
|
+
yDomain: null,
|
|
25
|
+
isActive: false,
|
|
26
|
+
range: {
|
|
27
|
+
x: 0,
|
|
28
|
+
y: 0,
|
|
29
|
+
width: 0,
|
|
30
|
+
height: 0,
|
|
31
|
+
},
|
|
32
|
+
handleSize: 0,
|
|
33
|
+
});
|
|
34
|
+
export function brushContext() {
|
|
35
|
+
return getContext<BrushContext>(brushContextKey) ?? defaultContext;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function setBrushContext(brush: BrushContext) {
|
|
39
|
+
setContext(brushContextKey, brush);
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<script lang="ts">
|
|
44
|
+
import { extent, min, max } from 'd3-array';
|
|
45
|
+
import { clamp } from '@layerstack/utils';
|
|
46
|
+
import { cls } from '@layerstack/tailwind';
|
|
47
|
+
import { Logger } from '@layerstack/utils';
|
|
48
|
+
|
|
49
|
+
import { chartContext } from './ChartContext.svelte';
|
|
50
|
+
|
|
51
|
+
import { localPoint } from '../utils/event.js';
|
|
52
|
+
import type { DomainType } from '../utils/scales.js';
|
|
53
|
+
import { add } from '../utils/math.js';
|
|
54
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
55
|
+
|
|
56
|
+
const { xScale, yScale, width, height, padding, containerWidth, containerHeight, config } =
|
|
57
|
+
chartContext();
|
|
58
|
+
|
|
59
|
+
/** Axis to apply brushing */
|
|
60
|
+
export let axis: 'x' | 'y' | 'both' = 'x';
|
|
61
|
+
|
|
62
|
+
/** Size of draggable handles (width/height) */
|
|
63
|
+
export let handleSize = 5;
|
|
64
|
+
|
|
65
|
+
/** Only show range while actively brushing. Useful with `brushEnd` event */
|
|
66
|
+
export let resetOnEnd = false;
|
|
67
|
+
|
|
68
|
+
export let xDomain: DomainType = $xScale.domain() as [number, number];
|
|
69
|
+
export let yDomain: DomainType = $yScale.domain() as [number, number];
|
|
70
|
+
|
|
71
|
+
/** Mode of operation
|
|
72
|
+
* `integrated`: use with single chart
|
|
73
|
+
* `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
|
|
74
|
+
*/
|
|
75
|
+
export let mode: 'integrated' | 'separated' = 'integrated';
|
|
76
|
+
|
|
77
|
+
/** Disable brush */
|
|
78
|
+
export let disabled = false;
|
|
79
|
+
|
|
80
|
+
// Capture original domains for reset()
|
|
81
|
+
const originalXDomain = $config.xDomain;
|
|
82
|
+
const originalYDomain = $config.yDomain;
|
|
83
|
+
|
|
84
|
+
$: [xDomainMin, xDomainMax] = extent<number>($xScale.domain()) as [number, number];
|
|
85
|
+
$: [yDomainMin, yDomainMax] = extent<number>($yScale.domain()) as [number, number];
|
|
86
|
+
|
|
87
|
+
/** Attributes passed to range <div> element */
|
|
88
|
+
export let range: Partial<HTMLAttributes<HTMLDivElement>> | undefined = undefined;
|
|
89
|
+
|
|
90
|
+
/** Attributes passed to handle <div> elements */
|
|
91
|
+
export let handle: Partial<HTMLAttributes<HTMLDivElement>> | undefined = undefined;
|
|
92
|
+
|
|
93
|
+
export let classes: {
|
|
94
|
+
root?: string;
|
|
95
|
+
frame?: string;
|
|
96
|
+
range?: string;
|
|
97
|
+
handle?: string;
|
|
98
|
+
labels?: string;
|
|
99
|
+
} = {};
|
|
100
|
+
|
|
101
|
+
export let onchange: (detail: { xDomain?: DomainType; yDomain?: DomainType }) => void = () => {};
|
|
102
|
+
export let onbrushstart: (detail: {
|
|
103
|
+
xDomain?: DomainType;
|
|
104
|
+
yDomain?: DomainType;
|
|
105
|
+
}) => void = () => {};
|
|
106
|
+
export let onbrushend: (detail: {
|
|
107
|
+
xDomain?: DomainType;
|
|
108
|
+
yDomain?: DomainType;
|
|
109
|
+
}) => void = () => {};
|
|
110
|
+
export let onreset: (detail: { xDomain?: DomainType; yDomain?: DomainType }) => void = () => {};
|
|
111
|
+
|
|
112
|
+
/** Exposed to allow binding in Chart */
|
|
113
|
+
export let brush = writable<BrushContextValue>({
|
|
114
|
+
xDomain: null,
|
|
115
|
+
yDomain: null,
|
|
116
|
+
isActive: false,
|
|
117
|
+
range: {
|
|
118
|
+
x: 0,
|
|
119
|
+
y: 0,
|
|
120
|
+
width: 0,
|
|
121
|
+
height: 0,
|
|
122
|
+
},
|
|
123
|
+
handleSize: 0,
|
|
124
|
+
});
|
|
125
|
+
setBrushContext(brush);
|
|
126
|
+
|
|
127
|
+
let rootEl: HTMLDivElement;
|
|
128
|
+
|
|
129
|
+
const logger = new Logger('BrushContext');
|
|
130
|
+
const RESET_THRESHOLD = 1; // size of pointer delta to ignore
|
|
131
|
+
|
|
132
|
+
function handler(
|
|
133
|
+
fn: (
|
|
134
|
+
start: {
|
|
135
|
+
xDomain: [number, number];
|
|
136
|
+
yDomain: [number, number];
|
|
137
|
+
value: { x: number; y: number };
|
|
138
|
+
},
|
|
139
|
+
value: { x: number; y: number }
|
|
140
|
+
) => void
|
|
141
|
+
) {
|
|
142
|
+
return (e: PointerEvent) => {
|
|
143
|
+
logger.debug('drag start');
|
|
144
|
+
e.stopPropagation();
|
|
145
|
+
|
|
146
|
+
const startPoint = localPoint(rootEl, e);
|
|
147
|
+
const start = {
|
|
148
|
+
xDomain: [xDomain?.[0] ?? xDomainMin, xDomain?.[1] ?? xDomainMax] as [number, number],
|
|
149
|
+
yDomain: [yDomain?.[0] ?? yDomainMin, yDomain?.[1] ?? yDomainMax] as [number, number],
|
|
150
|
+
value: {
|
|
151
|
+
x: $xScale.invert?.(startPoint?.x ?? 0),
|
|
152
|
+
y: $yScale.invert?.(startPoint?.y ?? 0),
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
onbrushstart({ xDomain, yDomain });
|
|
157
|
+
|
|
158
|
+
const onPointerMove = (e: PointerEvent) => {
|
|
159
|
+
const currentPoint = localPoint(rootEl, e);
|
|
160
|
+
fn(start, {
|
|
161
|
+
x: $xScale.invert?.(currentPoint?.x ?? 0),
|
|
162
|
+
y: $yScale.invert?.(currentPoint?.y ?? 0),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
onchange({ xDomain, yDomain });
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const onPointerUp = (e: PointerEvent) => {
|
|
169
|
+
const currentPoint = localPoint(rootEl, e);
|
|
170
|
+
const xPointDelta = Math.abs((startPoint?.x ?? 0) - (currentPoint?.x ?? 0));
|
|
171
|
+
const yPointDelta = Math.abs((startPoint?.y ?? 0) - (currentPoint?.y ?? 0));
|
|
172
|
+
|
|
173
|
+
// Is click on frame (i.e. not on the `.range` or `.handle`)
|
|
174
|
+
const isClickOutside = !Array.from((e.target as Element).classList).some((cls) =>
|
|
175
|
+
['range', 'handle'].includes(cls)
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
(isClickOutside && xPointDelta < RESET_THRESHOLD && yPointDelta < RESET_THRESHOLD) ||
|
|
180
|
+
_range.width < RESET_THRESHOLD ||
|
|
181
|
+
_range.height < RESET_THRESHOLD
|
|
182
|
+
) {
|
|
183
|
+
// Clicked on frame, or pointer delta was <1
|
|
184
|
+
logger.debug('resetting due to frame click');
|
|
185
|
+
reset();
|
|
186
|
+
onchange({ xDomain, yDomain });
|
|
187
|
+
} else {
|
|
188
|
+
logger.debug('drag end', {
|
|
189
|
+
target: e.target,
|
|
190
|
+
xPointDelta,
|
|
191
|
+
yPointDelta,
|
|
192
|
+
rangeWidth: _range.width,
|
|
193
|
+
rangeHeight: _range.height,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
onbrushend({ xDomain, yDomain });
|
|
198
|
+
|
|
199
|
+
if (resetOnEnd) {
|
|
200
|
+
reset();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
204
|
+
window.removeEventListener('pointerup', onPointerUp);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
208
|
+
window.addEventListener('pointerup', onPointerUp);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const createRange = handler((start, value) => {
|
|
213
|
+
logger.debug('createRange');
|
|
214
|
+
isActive = true;
|
|
215
|
+
|
|
216
|
+
xDomain = [
|
|
217
|
+
// @ts-expect-error
|
|
218
|
+
clamp(min([start.value.x, value.x]), xDomainMin, xDomainMax),
|
|
219
|
+
// @ts-expect-error
|
|
220
|
+
clamp(max([start.value.x, value.x]), xDomainMin, xDomainMax),
|
|
221
|
+
];
|
|
222
|
+
// xDomain = [start.value.x, value.x];
|
|
223
|
+
|
|
224
|
+
yDomain = [
|
|
225
|
+
// @ts-expect-error
|
|
226
|
+
clamp(min([start.value.y, value.y]), yDomainMin, yDomainMax),
|
|
227
|
+
// @ts-expect-error
|
|
228
|
+
clamp(max([start.value.y, value.y]), yDomainMin, yDomainMax),
|
|
229
|
+
];
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const adjustRange = handler((start, value) => {
|
|
233
|
+
logger.debug('adjustRange');
|
|
234
|
+
const dx = clamp(
|
|
235
|
+
value.x - start.value.x,
|
|
236
|
+
xDomainMin - start.xDomain[0],
|
|
237
|
+
xDomainMax - start.xDomain[1]
|
|
238
|
+
);
|
|
239
|
+
xDomain = [add(start.xDomain[0], dx), add(start.xDomain[1], dx)];
|
|
240
|
+
|
|
241
|
+
const dy = clamp(
|
|
242
|
+
value.y - start.value.y,
|
|
243
|
+
yDomainMin - start.yDomain[0],
|
|
244
|
+
yDomainMax - start.yDomain[1]
|
|
245
|
+
);
|
|
246
|
+
yDomain = [add(start.yDomain[0], dy), add(start.yDomain[1], dy)];
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const adjustTop = handler((start, value) => {
|
|
250
|
+
logger.debug('adjustTop');
|
|
251
|
+
yDomain = [
|
|
252
|
+
clamp(value.y < start.yDomain[0] ? value.y : start.yDomain[0], yDomainMin, yDomainMax),
|
|
253
|
+
clamp(value.y < start.yDomain[0] ? start.yDomain[0] : value.y, yDomainMin, yDomainMax),
|
|
254
|
+
];
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const adjustBottom = handler((start, value) => {
|
|
258
|
+
logger.debug('adjustBottom');
|
|
259
|
+
yDomain = [
|
|
260
|
+
clamp(value.y > start.yDomain[1] ? start.yDomain[1] : value.y, yDomainMin, yDomainMax),
|
|
261
|
+
clamp(value.y > start.yDomain[1] ? value.y : start.yDomain[1], yDomainMin, yDomainMax),
|
|
262
|
+
];
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const adjustLeft = handler((start, value) => {
|
|
266
|
+
logger.debug('adjustLeft');
|
|
267
|
+
xDomain = [
|
|
268
|
+
clamp(value.x > start.xDomain[1] ? start.xDomain[1] : value.x, xDomainMin, xDomainMax),
|
|
269
|
+
clamp(value.x > start.xDomain[1] ? value.x : start.xDomain[1], xDomainMin, xDomainMax),
|
|
270
|
+
];
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const adjustRight = handler((start, value) => {
|
|
274
|
+
logger.debug('adjustRight');
|
|
275
|
+
xDomain = [
|
|
276
|
+
clamp(value.x < start.xDomain[0] ? value.x : start.xDomain[0], xDomainMin, xDomainMax),
|
|
277
|
+
clamp(value.x < start.xDomain[0] ? start.xDomain[0] : value.x, xDomainMin, xDomainMax),
|
|
278
|
+
];
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
function reset() {
|
|
282
|
+
logger.debug('reset');
|
|
283
|
+
isActive = false;
|
|
284
|
+
|
|
285
|
+
xDomain = originalXDomain;
|
|
286
|
+
yDomain = originalYDomain;
|
|
287
|
+
|
|
288
|
+
onreset({ xDomain, yDomain });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function selectAll() {
|
|
292
|
+
logger.debug('selectedAll');
|
|
293
|
+
xDomain = [xDomainMin, xDomainMax];
|
|
294
|
+
yDomain = [yDomainMin, yDomainMax];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
$: top = $yScale(yDomain?.[1]);
|
|
298
|
+
$: bottom = $yScale(yDomain?.[0]);
|
|
299
|
+
$: left = $xScale(xDomain?.[0]);
|
|
300
|
+
$: right = $xScale(xDomain?.[1]);
|
|
301
|
+
|
|
302
|
+
$: _range = {
|
|
303
|
+
x: axis === 'both' || axis === 'x' ? left : 0,
|
|
304
|
+
y: axis === 'both' || axis === 'y' ? top : 0,
|
|
305
|
+
width: axis === 'both' || axis === 'x' ? right - left : $width,
|
|
306
|
+
height: axis === 'both' || axis === 'y' ? bottom - top : $height,
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
let isActive = false;
|
|
310
|
+
$: if (mode === 'separated') {
|
|
311
|
+
// Set reactively to handle cases where xDomain/yDomain are set externally (ex. `bind:xDomain`)
|
|
312
|
+
const isXAxisActive =
|
|
313
|
+
xDomain?.[0]?.valueOf() !== originalXDomain?.[0]?.valueOf() ||
|
|
314
|
+
xDomain?.[1]?.valueOf() !== originalXDomain?.[1]?.valueOf();
|
|
315
|
+
|
|
316
|
+
const isYAxisActive =
|
|
317
|
+
yDomain?.[0]?.valueOf() !== originalYDomain?.[0]?.valueOf() ||
|
|
318
|
+
yDomain?.[1]?.valueOf() !== originalYDomain?.[1]?.valueOf();
|
|
319
|
+
|
|
320
|
+
isActive =
|
|
321
|
+
axis === 'x' ? isXAxisActive : axis == 'y' ? isYAxisActive : isXAxisActive || isYAxisActive;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
$: $brush = {
|
|
325
|
+
xDomain,
|
|
326
|
+
yDomain,
|
|
327
|
+
isActive,
|
|
328
|
+
range: _range,
|
|
329
|
+
handleSize,
|
|
330
|
+
};
|
|
331
|
+
</script>
|
|
332
|
+
|
|
333
|
+
{#if disabled}
|
|
334
|
+
<slot />
|
|
335
|
+
{:else}
|
|
336
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
337
|
+
<div
|
|
338
|
+
style:top="{$padding.top}px"
|
|
339
|
+
style:left="{$padding.left}px"
|
|
340
|
+
style:width="{$width}px"
|
|
341
|
+
style:height="{$height}px"
|
|
342
|
+
class={cls('BrushContext absolute touch-none')}
|
|
343
|
+
on:pointerdown={createRange}
|
|
344
|
+
on:dblclick={() => selectAll()}
|
|
345
|
+
bind:this={rootEl}
|
|
346
|
+
>
|
|
347
|
+
<div
|
|
348
|
+
class="absolute"
|
|
349
|
+
style:top="-{$padding.top ?? 0}px"
|
|
350
|
+
style:left="-{$padding.left ?? 0}px"
|
|
351
|
+
style:width="{$containerWidth}px"
|
|
352
|
+
style:height="{$containerHeight}px"
|
|
353
|
+
>
|
|
354
|
+
<slot brush={$brush} />
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
{#if isActive}
|
|
358
|
+
<div
|
|
359
|
+
{...range}
|
|
360
|
+
style:left="{_range.x}px"
|
|
361
|
+
style:top="{_range.y}px"
|
|
362
|
+
style:width="{_range.width}px"
|
|
363
|
+
style:height="{_range.height}px"
|
|
364
|
+
class={cls(
|
|
365
|
+
'range',
|
|
366
|
+
'absolute bg-surface-content/10 cursor-move select-none',
|
|
367
|
+
'z-10',
|
|
368
|
+
classes.range,
|
|
369
|
+
range?.class
|
|
370
|
+
)}
|
|
371
|
+
on:pointerdown={adjustRange}
|
|
372
|
+
on:dblclick={() => reset()}
|
|
373
|
+
></div>
|
|
374
|
+
|
|
375
|
+
{#if axis === 'both' || axis === 'y'}
|
|
376
|
+
<div
|
|
377
|
+
{...handle}
|
|
378
|
+
style:left="{_range.x}px"
|
|
379
|
+
style:top="{_range.y}px"
|
|
380
|
+
style:width="{_range.width}px"
|
|
381
|
+
style:height="{handleSize}px"
|
|
382
|
+
class={cls(
|
|
383
|
+
'handle top',
|
|
384
|
+
'cursor-ns-resize select-none',
|
|
385
|
+
'range absolute',
|
|
386
|
+
'z-10',
|
|
387
|
+
classes.handle,
|
|
388
|
+
handle?.class
|
|
389
|
+
)}
|
|
390
|
+
on:pointerdown={adjustTop}
|
|
391
|
+
on:dblclick={(e) => {
|
|
392
|
+
e.stopPropagation();
|
|
393
|
+
if (yDomain) {
|
|
394
|
+
yDomain[0] = yDomainMin;
|
|
395
|
+
onchange({ xDomain, yDomain });
|
|
396
|
+
}
|
|
397
|
+
}}
|
|
398
|
+
></div>
|
|
399
|
+
|
|
400
|
+
<div
|
|
401
|
+
{...handle}
|
|
402
|
+
style:left="{_range.x}px"
|
|
403
|
+
style:top="{bottom - handleSize}px"
|
|
404
|
+
style:width="{_range.width}px"
|
|
405
|
+
style:height="{handleSize}px"
|
|
406
|
+
class={cls(
|
|
407
|
+
'handle bottom',
|
|
408
|
+
'cursor-ns-resize select-none',
|
|
409
|
+
'range absolute',
|
|
410
|
+
'z-10',
|
|
411
|
+
classes.handle,
|
|
412
|
+
handle?.class
|
|
413
|
+
)}
|
|
414
|
+
on:pointerdown={adjustBottom}
|
|
415
|
+
on:dblclick={(e) => {
|
|
416
|
+
e.stopPropagation();
|
|
417
|
+
if (yDomain) {
|
|
418
|
+
yDomain[1] = yDomainMax;
|
|
419
|
+
onchange({ xDomain, yDomain });
|
|
420
|
+
}
|
|
421
|
+
}}
|
|
422
|
+
></div>
|
|
423
|
+
{/if}
|
|
424
|
+
|
|
425
|
+
{#if axis === 'both' || axis === 'x'}
|
|
426
|
+
<div
|
|
427
|
+
{...handle}
|
|
428
|
+
style:left="{_range.x}px"
|
|
429
|
+
style:top="{_range.y}px"
|
|
430
|
+
style:width="{handleSize}px"
|
|
431
|
+
style:height="{_range.height}px"
|
|
432
|
+
class={cls(
|
|
433
|
+
'handle left',
|
|
434
|
+
'cursor-ew-resize select-none',
|
|
435
|
+
'range absolute',
|
|
436
|
+
'z-10',
|
|
437
|
+
classes.handle,
|
|
438
|
+
handle?.class
|
|
439
|
+
)}
|
|
440
|
+
on:pointerdown={adjustLeft}
|
|
441
|
+
on:dblclick={(e) => {
|
|
442
|
+
e.stopPropagation();
|
|
443
|
+
if (xDomain) {
|
|
444
|
+
xDomain[0] = xDomainMin;
|
|
445
|
+
onchange({ xDomain, yDomain });
|
|
446
|
+
}
|
|
447
|
+
}}
|
|
448
|
+
></div>
|
|
449
|
+
|
|
450
|
+
<div
|
|
451
|
+
{...handle}
|
|
452
|
+
style:left="{right - handleSize + 1}px"
|
|
453
|
+
style:top="{_range.y}px"
|
|
454
|
+
style:width="{handleSize}px"
|
|
455
|
+
style:height="{_range.height}px"
|
|
456
|
+
class={cls(
|
|
457
|
+
'handle right',
|
|
458
|
+
'cursor-ew-resize select-none',
|
|
459
|
+
'range absolute',
|
|
460
|
+
'z-10',
|
|
461
|
+
classes.handle,
|
|
462
|
+
handle?.class
|
|
463
|
+
)}
|
|
464
|
+
on:pointerdown={adjustRight}
|
|
465
|
+
on:dblclick={(e) => {
|
|
466
|
+
e.stopPropagation();
|
|
467
|
+
if (xDomain) {
|
|
468
|
+
xDomain[1] = xDomainMax;
|
|
469
|
+
onchange({ xDomain, yDomain });
|
|
470
|
+
}
|
|
471
|
+
}}
|
|
472
|
+
></div>
|
|
473
|
+
{/if}
|
|
474
|
+
{/if}
|
|
475
|
+
</div>
|
|
476
|
+
{/if}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import { type Readable } from 'svelte/store';
|
|
3
|
+
export declare const brushContextKey: unique symbol;
|
|
4
|
+
export type BrushContextValue = {
|
|
5
|
+
xDomain: DomainType;
|
|
6
|
+
yDomain: DomainType;
|
|
7
|
+
isActive: boolean;
|
|
8
|
+
range: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
handleSize: number;
|
|
15
|
+
};
|
|
16
|
+
export type BrushContext = Readable<BrushContextValue>;
|
|
17
|
+
export declare function brushContext(): BrushContext;
|
|
18
|
+
import type { DomainType } from '../utils/scales.js';
|
|
19
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
20
|
+
declare const __propDef: {
|
|
21
|
+
props: {
|
|
22
|
+
/** Axis to apply brushing */ axis?: "x" | "y" | "both";
|
|
23
|
+
/** Size of draggable handles (width/height) */ handleSize?: number;
|
|
24
|
+
/** Only show range while actively brushing. Useful with `brushEnd` event */ resetOnEnd?: boolean;
|
|
25
|
+
xDomain?: DomainType;
|
|
26
|
+
yDomain?: DomainType;
|
|
27
|
+
/** Mode of operation
|
|
28
|
+
* `integrated`: use with single chart
|
|
29
|
+
* `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
|
|
30
|
+
*/ mode?: "integrated" | "separated";
|
|
31
|
+
/** Disable brush */ disabled?: boolean;
|
|
32
|
+
/** Attributes passed to range <div> element */ range?: Partial<HTMLAttributes<HTMLDivElement>> | undefined;
|
|
33
|
+
/** Attributes passed to handle <div> elements */ handle?: Partial<HTMLAttributes<HTMLDivElement>> | undefined;
|
|
34
|
+
classes?: {
|
|
35
|
+
root?: string;
|
|
36
|
+
frame?: string;
|
|
37
|
+
range?: string;
|
|
38
|
+
handle?: string;
|
|
39
|
+
labels?: string;
|
|
40
|
+
};
|
|
41
|
+
onchange?: (detail: {
|
|
42
|
+
xDomain?: DomainType;
|
|
43
|
+
yDomain?: DomainType;
|
|
44
|
+
}) => void;
|
|
45
|
+
onbrushstart?: (detail: {
|
|
46
|
+
xDomain?: DomainType;
|
|
47
|
+
yDomain?: DomainType;
|
|
48
|
+
}) => void;
|
|
49
|
+
onbrushend?: (detail: {
|
|
50
|
+
xDomain?: DomainType;
|
|
51
|
+
yDomain?: DomainType;
|
|
52
|
+
}) => void;
|
|
53
|
+
onreset?: (detail: {
|
|
54
|
+
xDomain?: DomainType;
|
|
55
|
+
yDomain?: DomainType;
|
|
56
|
+
}) => void;
|
|
57
|
+
/** Exposed to allow binding in Chart */ brush?: import("svelte/store").Writable<BrushContextValue>;
|
|
58
|
+
};
|
|
59
|
+
events: {
|
|
60
|
+
[evt: string]: CustomEvent<any>;
|
|
61
|
+
};
|
|
62
|
+
slots: {
|
|
63
|
+
default: {
|
|
64
|
+
brush: BrushContextValue;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export type BrushContextProps = typeof __propDef.props;
|
|
69
|
+
export type BrushContextEvents = typeof __propDef.events;
|
|
70
|
+
export type BrushContextSlots = typeof __propDef.slots;
|
|
71
|
+
export default class BrushContext extends SvelteComponentTyped<BrushContextProps, BrushContextEvents, BrushContextSlots> {
|
|
72
|
+
}
|
|
73
|
+
export {};
|