layerchart 0.75.0 → 0.76.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/Chart.svelte.d.ts +1 -0
- package/dist/components/charts/AreaChart.svelte +5 -4
- package/dist/components/charts/BarChart.svelte +9 -5
- package/dist/components/charts/LineChart.svelte +2 -2
- package/dist/components/charts/PieChart.svelte.d.ts +1 -0
- package/dist/components/charts/ScatterChart.svelte +6 -4
- package/dist/components/tooltip/Tooltip.svelte +4 -1
- package/dist/components/tooltip/Tooltip.svelte.d.ts +1 -0
- package/dist/components/tooltip/TooltipContext.svelte +33 -20
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +1 -0
- package/dist/components/tooltip/TooltipHeader.svelte +4 -1
- package/dist/components/tooltip/TooltipHeader.svelte.d.ts +3 -0
- package/package.json +1 -1
|
@@ -187,6 +187,7 @@ declare class __sveltets_Render<TData> {
|
|
|
187
187
|
mode?: "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree" | "manual";
|
|
188
188
|
findTooltipData?: "closest" | "left" | "right";
|
|
189
189
|
raiseTarget?: boolean;
|
|
190
|
+
locked?: boolean;
|
|
190
191
|
radius?: number;
|
|
191
192
|
debug?: boolean;
|
|
192
193
|
onClick?: ({ data }: {
|
|
@@ -214,8 +214,8 @@
|
|
|
214
214
|
yNice
|
|
215
215
|
{radial}
|
|
216
216
|
padding={radial ? undefined : defaultChartPadding(axis, legend)}
|
|
217
|
-
tooltip={{ mode: 'bisect-x', onClick: onTooltipClick }}
|
|
218
217
|
{...$$restProps}
|
|
218
|
+
tooltip={{ mode: 'bisect-x', onClick: onTooltipClick, ...$$props.tooltip, ...props.tooltip }}
|
|
219
219
|
let:x
|
|
220
220
|
let:xScale
|
|
221
221
|
let:y
|
|
@@ -356,7 +356,8 @@
|
|
|
356
356
|
|
|
357
357
|
<slot name="tooltip" {...slotProps}>
|
|
358
358
|
<Tooltip.Root {...props.tooltip?.root} let:data>
|
|
359
|
-
<Tooltip.Header {...props.tooltip?.header}
|
|
359
|
+
<Tooltip.Header value={x(data)} {format} {...props.tooltip?.header} />
|
|
360
|
+
|
|
360
361
|
<Tooltip.List {...props.tooltip?.list}>
|
|
361
362
|
<!-- Reverse series order so tooltip items match stacks -->
|
|
362
363
|
{@const seriesItems = stackSeries ? [...visibleSeries].reverse() : visibleSeries}
|
|
@@ -374,12 +375,12 @@
|
|
|
374
375
|
/>
|
|
375
376
|
{/each}
|
|
376
377
|
|
|
377
|
-
{#if stackSeries}
|
|
378
|
+
{#if stackSeries && visibleSeries.length > 1}
|
|
378
379
|
<Tooltip.Separator {...props.tooltip?.separator} />
|
|
379
380
|
|
|
380
381
|
<Tooltip.Item
|
|
381
382
|
label="total"
|
|
382
|
-
value={sum(
|
|
383
|
+
value={sum(visibleSeries, (s) => {
|
|
383
384
|
const seriesTooltipData = s.data ? s.data.find((d) => x(d) === x(data)) : data;
|
|
384
385
|
const valueAccessor = accessor(s.value ?? (s.data ? asAny(y) : s.key));
|
|
385
386
|
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
list?: Partial<ComponentProps<Tooltip.List>>;
|
|
141
141
|
item?: Partial<ComponentProps<Tooltip.Item>>;
|
|
142
142
|
separator?: Partial<ComponentProps<Tooltip.Separator>>;
|
|
143
|
+
hideTotal?: boolean;
|
|
143
144
|
};
|
|
144
145
|
} = {};
|
|
145
146
|
|
|
@@ -279,8 +280,8 @@
|
|
|
279
280
|
c={isVertical ? y : x}
|
|
280
281
|
cRange={['hsl(var(--color-primary))']}
|
|
281
282
|
padding={defaultChartPadding(axis, legend)}
|
|
282
|
-
tooltip={{ mode: 'band', onClick: onTooltipClick }}
|
|
283
283
|
{...$$restProps}
|
|
284
|
+
tooltip={{ mode: 'band', onClick: onTooltipClick, ...$$props.tooltip, ...props.tooltip }}
|
|
284
285
|
let:x
|
|
285
286
|
let:xScale
|
|
286
287
|
let:y
|
|
@@ -410,9 +411,12 @@
|
|
|
410
411
|
|
|
411
412
|
<slot name="tooltip" {...slotProps}>
|
|
412
413
|
<Tooltip.Root {...props.tooltip?.root} let:data>
|
|
413
|
-
<Tooltip.Header
|
|
414
|
-
|
|
415
|
-
|
|
414
|
+
<Tooltip.Header
|
|
415
|
+
value={isVertical ? x(data) : y(data)}
|
|
416
|
+
{format}
|
|
417
|
+
{...props.tooltip?.header}
|
|
418
|
+
/>
|
|
419
|
+
|
|
416
420
|
<Tooltip.List {...props.tooltip?.list}>
|
|
417
421
|
<!-- Reverse series order so tooltip items match stacks -->
|
|
418
422
|
{@const seriesItems = stackSeries ? [...visibleSeries].reverse() : visibleSeries}
|
|
@@ -429,7 +433,7 @@
|
|
|
429
433
|
/>
|
|
430
434
|
{/each}
|
|
431
435
|
|
|
432
|
-
{#if (stackSeries || groupSeries) && visibleSeries.length > 1}
|
|
436
|
+
{#if (stackSeries || groupSeries) && visibleSeries.length > 1 && !props.tooltip?.hideTotal}
|
|
433
437
|
<Tooltip.Separator {...props.tooltip?.separator} />
|
|
434
438
|
|
|
435
439
|
<Tooltip.Item
|
|
@@ -156,8 +156,8 @@
|
|
|
156
156
|
yNice
|
|
157
157
|
{radial}
|
|
158
158
|
padding={radial ? undefined : defaultChartPadding(axis, legend)}
|
|
159
|
-
tooltip={{ mode: 'bisect-x', onClick: onTooltipClick }}
|
|
160
159
|
{...$$restProps}
|
|
160
|
+
tooltip={{ mode: 'bisect-x', onClick: onTooltipClick, ...$$props.tooltip, ...props.tooltip }}
|
|
161
161
|
let:x
|
|
162
162
|
let:xScale
|
|
163
163
|
let:y
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
|
|
291
291
|
<slot name="tooltip" {...slotProps}>
|
|
292
292
|
<Tooltip.Root {...props.tooltip?.root} let:data>
|
|
293
|
-
<Tooltip.Header {...props.tooltip?.header}
|
|
293
|
+
<Tooltip.Header value={x(data)} {format} {...props.tooltip?.header} />
|
|
294
294
|
<Tooltip.List {...props.tooltip?.list}>
|
|
295
295
|
{#each visibleSeries as s}
|
|
296
296
|
{@const seriesTooltipData = s.data ? findRelatedData(s.data, data, x) : data}
|
|
@@ -124,6 +124,7 @@ declare class __sveltets_Render<TData> {
|
|
|
124
124
|
mode?: "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree" | "manual";
|
|
125
125
|
findTooltipData?: "closest" | "left" | "right";
|
|
126
126
|
raiseTarget?: boolean;
|
|
127
|
+
locked?: boolean;
|
|
127
128
|
radius?: number;
|
|
128
129
|
debug?: boolean;
|
|
129
130
|
onClick?: ({ data }: {
|
|
@@ -139,8 +139,8 @@
|
|
|
139
139
|
{yScale}
|
|
140
140
|
yNice
|
|
141
141
|
padding={defaultChartPadding(axis, legend)}
|
|
142
|
-
tooltip={{ mode: 'voronoi', onClick: onTooltipClick }}
|
|
143
142
|
{...$$restProps}
|
|
143
|
+
tooltip={{ mode: 'voronoi', onClick: onTooltipClick, ...$$props.tooltip, ...props.tooltip }}
|
|
144
144
|
let:x
|
|
145
145
|
let:xScale
|
|
146
146
|
let:y
|
|
@@ -246,9 +246,11 @@
|
|
|
246
246
|
<slot name="tooltip" {...slotProps}>
|
|
247
247
|
<Tooltip.Root {...props.tooltip?.root} let:data>
|
|
248
248
|
{#if activeSeries?.key !== 'default'}
|
|
249
|
-
<Tooltip.Header
|
|
250
|
-
{activeSeries?.label ?? activeSeries?.key}
|
|
251
|
-
|
|
249
|
+
<Tooltip.Header
|
|
250
|
+
value={activeSeries?.label ?? activeSeries?.key}
|
|
251
|
+
color={activeSeries?.color}
|
|
252
|
+
{...props.tooltip?.header}
|
|
253
|
+
/>
|
|
252
254
|
{/if}
|
|
253
255
|
<Tooltip.List {...props.tooltip?.list}>
|
|
254
256
|
<Tooltip.Item
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
/** Set to `false` to disable spring transitions */
|
|
38
38
|
export let motion = true;
|
|
39
39
|
|
|
40
|
+
/** Allow pointer events. Disabled by default to reduce accidental selection, but useful to enable to allow interactdive tooltips (using `locked`) */
|
|
41
|
+
export let pointerEvents = false;
|
|
42
|
+
|
|
40
43
|
export let classes: {
|
|
41
44
|
root?: string;
|
|
42
45
|
container?: string;
|
|
@@ -203,7 +206,7 @@
|
|
|
203
206
|
|
|
204
207
|
{#if $tooltip.data}
|
|
205
208
|
<div
|
|
206
|
-
class={cls('absolute
|
|
209
|
+
class={cls('absolute z-50 select-none', !pointerEvents && 'pointer-events-none', classes.root)}
|
|
207
210
|
style:top="{$yPos}px"
|
|
208
211
|
style:left="{$xPos}px"
|
|
209
212
|
transition:fade={{ duration: 100 }}
|
|
@@ -10,6 +10,7 @@ declare const __propDef: {
|
|
|
10
10
|
contained?: "container" | "window" | false | undefined;
|
|
11
11
|
variant?: "default" | "invert" | "none" | undefined;
|
|
12
12
|
motion?: boolean | undefined;
|
|
13
|
+
pointerEvents?: boolean | undefined;
|
|
13
14
|
classes?: {
|
|
14
15
|
root?: string;
|
|
15
16
|
container?: string;
|
|
@@ -97,6 +97,9 @@
|
|
|
97
97
|
/** Similar to d3-selection's raise, re-insert the e.target as the last child of its parent, so to be the top-most element */
|
|
98
98
|
export let raiseTarget = false;
|
|
99
99
|
|
|
100
|
+
/** Lock tooltip (keep open, do not update on mouse movement). Allows for kicking on tooltip */
|
|
101
|
+
export let locked = false;
|
|
102
|
+
|
|
100
103
|
/** quadtree search radius
|
|
101
104
|
* @type {number}
|
|
102
105
|
*/
|
|
@@ -169,20 +172,25 @@
|
|
|
169
172
|
// Cancel hiding tooltip if from previous event loop
|
|
170
173
|
clearTimeout(hideTimeoutId);
|
|
171
174
|
|
|
175
|
+
if (locked) {
|
|
176
|
+
// Ignore (keep current position / data)
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
172
180
|
const referenceNode = (e.target as Element).closest('.layercake-container')!;
|
|
173
181
|
const point = localPoint(referenceNode, e);
|
|
174
|
-
const
|
|
175
|
-
const
|
|
182
|
+
const pointerX = point?.x ?? 0;
|
|
183
|
+
const pointerY = point?.y ?? 0;
|
|
176
184
|
|
|
177
185
|
if (
|
|
178
186
|
// @ts-expect-error
|
|
179
|
-
|
|
187
|
+
pointerX < e.currentTarget?.offsetLeft ||
|
|
180
188
|
// @ts-expect-error
|
|
181
|
-
|
|
189
|
+
pointerX > e.currentTarget?.offsetLeft + e.currentTarget?.offsetWidth ||
|
|
182
190
|
// @ts-expect-error
|
|
183
|
-
|
|
191
|
+
pointerY < e.currentTarget?.offsetTop ||
|
|
184
192
|
// @ts-expect-error
|
|
185
|
-
|
|
193
|
+
pointerY > e.currentTarget?.offsetTop + e.currentTarget?.offsetHeight
|
|
186
194
|
) {
|
|
187
195
|
// Ignore if within padding of chart
|
|
188
196
|
hideTooltip();
|
|
@@ -197,10 +205,10 @@
|
|
|
197
205
|
let xValueAtPoint: any;
|
|
198
206
|
if ($radial) {
|
|
199
207
|
// Assume radial is always centered
|
|
200
|
-
const { radians } = cartesianToPolar(
|
|
208
|
+
const { radians } = cartesianToPolar(pointerX - $width / 2, pointerY - $height / 2);
|
|
201
209
|
xValueAtPoint = scaleInvert($xScale, radians);
|
|
202
210
|
} else {
|
|
203
|
-
xValueAtPoint = scaleInvert($xScale,
|
|
211
|
+
xValueAtPoint = scaleInvert($xScale, pointerX - $padding.left);
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
const index = bisectX($flatData, xValueAtPoint, 1);
|
|
@@ -212,7 +220,7 @@
|
|
|
212
220
|
|
|
213
221
|
case 'bisect-y': {
|
|
214
222
|
// `y` value at pointer coordinate
|
|
215
|
-
const yValueAtPoint = scaleInvert($yScale,
|
|
223
|
+
const yValueAtPoint = scaleInvert($yScale, pointerY - $padding.top);
|
|
216
224
|
|
|
217
225
|
const index = bisectY($flatData, yValueAtPoint, 1);
|
|
218
226
|
const previousValue = $flatData[index - 1];
|
|
@@ -223,8 +231,8 @@
|
|
|
223
231
|
|
|
224
232
|
case 'bisect-band': {
|
|
225
233
|
// `x` and `y` values at pointer coordinate
|
|
226
|
-
const xValueAtPoint = scaleInvert($xScale,
|
|
227
|
-
const yValueAtPoint = scaleInvert($yScale,
|
|
234
|
+
const xValueAtPoint = scaleInvert($xScale, pointerX);
|
|
235
|
+
const yValueAtPoint = scaleInvert($yScale, pointerY);
|
|
228
236
|
|
|
229
237
|
if (isScaleBand($xScale)) {
|
|
230
238
|
// Find point closest to pointer within the x band
|
|
@@ -251,7 +259,7 @@
|
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
case 'quadtree': {
|
|
254
|
-
tooltipData = quadtree.find(
|
|
262
|
+
tooltipData = quadtree.find(pointerX, pointerY, radius);
|
|
255
263
|
break;
|
|
256
264
|
}
|
|
257
265
|
}
|
|
@@ -264,8 +272,8 @@
|
|
|
264
272
|
|
|
265
273
|
$tooltip = {
|
|
266
274
|
...$tooltip,
|
|
267
|
-
x:
|
|
268
|
-
y:
|
|
275
|
+
x: pointerX,
|
|
276
|
+
y: pointerY,
|
|
269
277
|
data: tooltipData,
|
|
270
278
|
};
|
|
271
279
|
} else {
|
|
@@ -275,6 +283,11 @@
|
|
|
275
283
|
}
|
|
276
284
|
|
|
277
285
|
function hideTooltip() {
|
|
286
|
+
if (locked) {
|
|
287
|
+
// Ignore (keep open)
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
278
291
|
// Wait an event loop tick in case `showTooltip` is called immediately on another element, to allow tweeneing (ex. moving between bands/bars)
|
|
279
292
|
hideTimeoutId = setTimeout(() => {
|
|
280
293
|
$tooltip = { ...$tooltip, data: null };
|
|
@@ -369,7 +382,7 @@
|
|
|
369
382
|
.sort(sortFunc('x'));
|
|
370
383
|
}
|
|
371
384
|
|
|
372
|
-
$:
|
|
385
|
+
$: triggerPointerEvents = ['bisect-x', 'bisect-y', 'bisect-band', 'quadtree'].includes(mode);
|
|
373
386
|
</script>
|
|
374
387
|
|
|
375
388
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
@@ -381,13 +394,13 @@
|
|
|
381
394
|
style:left="{$padding.left}px"
|
|
382
395
|
class={cls(
|
|
383
396
|
'tooltip-trigger absolute touch-none',
|
|
384
|
-
debug &&
|
|
397
|
+
debug && triggerPointerEvents && 'bg-danger/10 outline outline-danger'
|
|
385
398
|
)}
|
|
386
|
-
on:pointerenter={
|
|
387
|
-
on:pointermove={
|
|
388
|
-
on:pointerleave={
|
|
399
|
+
on:pointerenter={triggerPointerEvents ? showTooltip : undefined}
|
|
400
|
+
on:pointermove={triggerPointerEvents ? showTooltip : undefined}
|
|
401
|
+
on:pointerleave={triggerPointerEvents ? hideTooltip : undefined}
|
|
389
402
|
on:click={(e) => {
|
|
390
|
-
if (
|
|
403
|
+
if (triggerPointerEvents) {
|
|
391
404
|
onClick({ data: $tooltip?.data });
|
|
392
405
|
}
|
|
393
406
|
}}
|
|
@@ -19,6 +19,7 @@ declare const __propDef: {
|
|
|
19
19
|
* @type {'closest' | 'left' | 'right'}
|
|
20
20
|
*/ findTooltipData?: "closest" | "left" | "right";
|
|
21
21
|
/** Similar to d3-selection's raise, re-insert the e.target as the last child of its parent, so to be the top-most element */ raiseTarget?: boolean;
|
|
22
|
+
/** Lock tooltip (keep open, do not update on mouse movement). Allows for kicking on tooltip */ locked?: boolean;
|
|
22
23
|
/** quadtree search radius
|
|
23
24
|
* @type {number}
|
|
24
25
|
*/ radius?: number;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { format as formatUtil, type FormatType } from '@layerstack/utils';
|
|
2
3
|
import { cls } from '@layerstack/tailwind';
|
|
3
4
|
|
|
5
|
+
export let value: any = undefined;
|
|
6
|
+
export let format: FormatType | undefined = undefined;
|
|
4
7
|
export let color: string | undefined = undefined;
|
|
5
8
|
|
|
6
9
|
export let classes: {
|
|
@@ -23,5 +26,5 @@
|
|
|
23
26
|
style:--color={color}
|
|
24
27
|
></div>
|
|
25
28
|
{/if}
|
|
26
|
-
<slot
|
|
29
|
+
<slot>{format ? formatUtil(value, format) : value}</slot>
|
|
27
30
|
</div>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import { type FormatType } from '@layerstack/utils';
|
|
2
3
|
declare const __propDef: {
|
|
3
4
|
props: {
|
|
4
5
|
[x: string]: any;
|
|
6
|
+
value?: any;
|
|
7
|
+
format?: FormatType | undefined;
|
|
5
8
|
color?: string | undefined | undefined;
|
|
6
9
|
classes?: {
|
|
7
10
|
root?: string;
|