layerchart 0.40.2 → 0.41.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 +1 -1
- package/dist/components/Highlight.svelte +6 -4
- package/dist/components/Highlight.svelte.d.ts +1 -0
- package/dist/components/Tooltip.svelte +5 -5
- package/dist/components/Tooltip.svelte.d.ts +1 -1
- package/dist/components/TooltipContext.svelte +93 -94
- package/package.json +1 -1
|
@@ -113,7 +113,7 @@ onMount(() => {
|
|
|
113
113
|
let:data
|
|
114
114
|
let:flatData
|
|
115
115
|
>
|
|
116
|
-
<!-- Apply fitGeojson using TransformContext instead of GeoContext if `applyTransform` is used -->
|
|
116
|
+
<!-- Apply `fitGeojson` using TransformContext instead of GeoContext if `applyTransform` is used -->
|
|
117
117
|
{@const initialTransform =
|
|
118
118
|
geo?.applyTransform && geo?.fitGeojson && geo?.projection
|
|
119
119
|
? geoFitObjectTransform(geo.projection(), [width, height], geo.fitGeojson)
|
|
@@ -20,6 +20,8 @@ export let lines = false;
|
|
|
20
20
|
export let area = false;
|
|
21
21
|
/** Show bar and pass props to Rect */
|
|
22
22
|
export let bar = false;
|
|
23
|
+
/** Set to false to disable spring transitions */
|
|
24
|
+
export let motion = true;
|
|
23
25
|
// TODO: Fix circle points being backwards for stack (see AreaStack)
|
|
24
26
|
let _points = [];
|
|
25
27
|
let _lines = [];
|
|
@@ -167,7 +169,7 @@ $: if (highlightData) {
|
|
|
167
169
|
{#if area}
|
|
168
170
|
<slot name="area" area={_area}>
|
|
169
171
|
<Rect
|
|
170
|
-
spring
|
|
172
|
+
spring={motion}
|
|
171
173
|
{..._area}
|
|
172
174
|
{...typeof area === 'object' ? area : null}
|
|
173
175
|
class={cls(
|
|
@@ -182,7 +184,7 @@ $: if (highlightData) {
|
|
|
182
184
|
{#if bar}
|
|
183
185
|
<slot name="bar" {bar}>
|
|
184
186
|
<Bar
|
|
185
|
-
spring
|
|
187
|
+
spring={motion}
|
|
186
188
|
x={typeof bar === 'object' ? bar.x : null}
|
|
187
189
|
y={typeof bar === 'object' ? bar.y : null}
|
|
188
190
|
inset={typeof bar === 'object' ? bar.inset : null}
|
|
@@ -200,7 +202,7 @@ $: if (highlightData) {
|
|
|
200
202
|
<slot name="lines" lines={_lines}>
|
|
201
203
|
{#each _lines as line}
|
|
202
204
|
<Line
|
|
203
|
-
spring
|
|
205
|
+
spring={motion}
|
|
204
206
|
x1={line.x1}
|
|
205
207
|
y1={line.y1}
|
|
206
208
|
x2={line.x2}
|
|
@@ -221,7 +223,7 @@ $: if (highlightData) {
|
|
|
221
223
|
<!-- TODO: Improve color with stacked data -->
|
|
222
224
|
{@const fill = $config.r ? $rGet(highlightData) : null}
|
|
223
225
|
<Circle
|
|
224
|
-
spring
|
|
226
|
+
spring={motion}
|
|
225
227
|
cx={point.x}
|
|
226
228
|
cy={point.y}
|
|
227
229
|
r={4}
|
|
@@ -61,6 +61,7 @@ declare const __propDef: {
|
|
|
61
61
|
[prop: string]: import("svelte/motion").TweenedOptions<unknown> | undefined;
|
|
62
62
|
} | undefined;
|
|
63
63
|
}> | undefined;
|
|
64
|
+
/** Set to false to disable spring transitions */ motion?: boolean | undefined;
|
|
64
65
|
};
|
|
65
66
|
events: {
|
|
66
67
|
click: MouseEvent;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<script>import { getContext } from 'svelte';
|
|
2
|
-
import { spring } from 'svelte/motion';
|
|
3
2
|
import { fade } from 'svelte/transition';
|
|
4
|
-
import { writable } from 'svelte/store';
|
|
5
3
|
import { cls } from 'svelte-ux';
|
|
6
4
|
import { tooltipContext } from './TooltipContext.svelte';
|
|
5
|
+
import { motionStore } from '../stores/motionStore.js';
|
|
7
6
|
/** `x` position of tooltip. By default uses the pointer/mouse, can also snap to data or an explicit fixed position. */
|
|
8
7
|
export let x = 'pointer';
|
|
9
8
|
/** `y` position of tooltip. By default uses the pointer/mouse, can also snap to data or an explicit fixed position. */
|
|
@@ -14,16 +13,17 @@ export let xOffset = typeof x === 'number' || typeof y === 'number' ? 0 : 10;
|
|
|
14
13
|
export let yOffset = typeof x === 'number' || typeof y === 'number' ? 0 : 10;
|
|
15
14
|
export let anchor = 'top-left';
|
|
16
15
|
export let contained = 'container'; // TODO: Support 'window' using getBoundingClientRect()
|
|
17
|
-
export let animate = true;
|
|
18
16
|
export let variant = 'default';
|
|
17
|
+
/** Set to `false` to disable spring transitions */
|
|
18
|
+
export let motion = true;
|
|
19
19
|
export let header = undefined;
|
|
20
20
|
export let classes = {};
|
|
21
21
|
const { padding, xGet, yGet, containerWidth, containerHeight } = getContext('LayerCake');
|
|
22
22
|
const tooltip = tooltipContext();
|
|
23
23
|
let tooltipWidth = 0;
|
|
24
24
|
let tooltipHeight = 0;
|
|
25
|
-
const xPos =
|
|
26
|
-
const yPos =
|
|
25
|
+
const xPos = motionStore($tooltip.x, { spring: motion });
|
|
26
|
+
const yPos = motionStore($tooltip.y, { spring: motion });
|
|
27
27
|
function alignValue(value, align, addlOffset, tooltipSize) {
|
|
28
28
|
const alignOffset = align === 'center' ? tooltipSize / 2 : align === 'end' ? tooltipSize : 0;
|
|
29
29
|
return value + (align === 'end' ? -addlOffset : addlOffset) - alignOffset;
|
|
@@ -8,8 +8,8 @@ declare const __propDef: {
|
|
|
8
8
|
yOffset?: number | undefined;
|
|
9
9
|
anchor?: ("center" | "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
|
|
10
10
|
contained?: false | "container" | undefined;
|
|
11
|
-
animate?: boolean | undefined;
|
|
12
11
|
variant?: "default" | "none" | "invert" | undefined;
|
|
12
|
+
motion?: boolean | undefined;
|
|
13
13
|
header?: ((data: any) => any) | undefined;
|
|
14
14
|
classes?: {
|
|
15
15
|
root?: string | undefined;
|
|
@@ -26,7 +26,7 @@ import Voronoi from './Voronoi.svelte';
|
|
|
26
26
|
import { localPoint } from '../utils/event.js';
|
|
27
27
|
import { isScaleBand, scaleInvert } from '../utils/scales.js';
|
|
28
28
|
import { quadtreeRects } from '../utils/quadtree.js';
|
|
29
|
-
const { flatData, x, xScale, xGet, xRange, y, yScale, yGet, yRange, width, height, padding } = getContext('LayerCake');
|
|
29
|
+
const { flatData, x, xScale, xGet, xRange, y, yScale, yGet, yRange, width, height, containerWidth, containerHeight, padding, } = getContext('LayerCake');
|
|
30
30
|
/*
|
|
31
31
|
TODO: Defaults to consider (if possible to detect scale type, which might not be possible)
|
|
32
32
|
- scaleTime / scaleLinear: bisect
|
|
@@ -124,8 +124,22 @@ function showTooltip(e, tooltipData) {
|
|
|
124
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)
|
|
125
125
|
if (tooltipData == null) {
|
|
126
126
|
switch (mode) {
|
|
127
|
-
case '
|
|
128
|
-
|
|
127
|
+
case 'bisect-x': {
|
|
128
|
+
// `x` value at pointer coordinate
|
|
129
|
+
const xValueAtPoint = scaleInvert($xScale, localX - $padding.left);
|
|
130
|
+
const index = bisectX($flatData, xValueAtPoint, 1);
|
|
131
|
+
const previousValue = $flatData[index - 1];
|
|
132
|
+
const currentValue = $flatData[index];
|
|
133
|
+
tooltipData = findData(previousValue, currentValue, xValueAtPoint, $x);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'bisect-y': {
|
|
137
|
+
// `y` value at pointer coordinate
|
|
138
|
+
const yValueAtPoint = scaleInvert($yScale, localY - $padding.top);
|
|
139
|
+
const index = bisectY($flatData, yValueAtPoint, 1);
|
|
140
|
+
const previousValue = $flatData[index - 1];
|
|
141
|
+
const currentValue = $flatData[index];
|
|
142
|
+
tooltipData = findData(previousValue, currentValue, yValueAtPoint, $y);
|
|
129
143
|
break;
|
|
130
144
|
}
|
|
131
145
|
case 'bisect-band': {
|
|
@@ -153,22 +167,8 @@ function showTooltip(e, tooltipData) {
|
|
|
153
167
|
}
|
|
154
168
|
break;
|
|
155
169
|
}
|
|
156
|
-
case '
|
|
157
|
-
|
|
158
|
-
const xValueAtPoint = scaleInvert($xScale, localX - $padding.left);
|
|
159
|
-
const index = bisectX($flatData, xValueAtPoint, 1);
|
|
160
|
-
const previousValue = $flatData[index - 1];
|
|
161
|
-
const currentValue = $flatData[index];
|
|
162
|
-
tooltipData = findData(previousValue, currentValue, xValueAtPoint, $x);
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
case 'bisect-y': {
|
|
166
|
-
// `y` value at pointer coordinate
|
|
167
|
-
const yValueAtPoint = scaleInvert($yScale, localY - $padding.top);
|
|
168
|
-
const index = bisectY($flatData, yValueAtPoint, 1);
|
|
169
|
-
const previousValue = $flatData[index - 1];
|
|
170
|
-
const currentValue = $flatData[index];
|
|
171
|
-
tooltipData = findData(previousValue, currentValue, yValueAtPoint, $y);
|
|
170
|
+
case 'quadtree': {
|
|
171
|
+
tooltipData = quadtree.find(localX, localY, radius);
|
|
172
172
|
break;
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -273,86 +273,85 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
273
273
|
})
|
|
274
274
|
.sort(sortFunc('x'));
|
|
275
275
|
}
|
|
276
|
+
$: triggerPointEvents = ['bisect-x', 'bisect-y', 'bisect-band', 'quadtree'].includes(mode);
|
|
276
277
|
</script>
|
|
277
278
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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 && triggerPointEvents && 'bg-danger/10 outline outline-danger'
|
|
287
|
+
)}
|
|
288
|
+
on:pointerenter={triggerPointEvents ? showTooltip : undefined}
|
|
289
|
+
on:pointermove={triggerPointEvents ? showTooltip : undefined}
|
|
290
|
+
on:pointerleave={triggerPointEvents ? hideTooltip : undefined}
|
|
291
|
+
on:click={(e) => {
|
|
292
|
+
if (triggerPointEvents) {
|
|
292
293
|
onClick({ data: $tooltip?.data });
|
|
293
|
-
}
|
|
294
|
+
}
|
|
295
|
+
}}
|
|
296
|
+
>
|
|
297
|
+
<!-- Rendering slot within tooltip-trigger allows pointer events to bubble up (ex. Brush) -->
|
|
298
|
+
<div
|
|
299
|
+
class="absolute"
|
|
300
|
+
style:width="{$containerWidth}px"
|
|
301
|
+
style:height="{$containerHeight}px"
|
|
302
|
+
style:top="{-$padding.top}px"
|
|
303
|
+
style:left="{-$padding.left}px"
|
|
294
304
|
>
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
</div>
|
|
303
|
-
</div>
|
|
304
|
-
{:else if mode === 'voronoi'}
|
|
305
|
-
<slot tooltip={$tooltip} />
|
|
306
|
-
<Svg>
|
|
307
|
-
<Voronoi
|
|
308
|
-
on:pointerenter={(e) => showTooltip(e.detail.event, e.detail.data)}
|
|
309
|
-
on:pointermove={(e) => showTooltip(e.detail.event, e.detail.data)}
|
|
310
|
-
on:pointerleave={hideTooltip}
|
|
311
|
-
on:click={(e) => {
|
|
312
|
-
onClick({ data: e.detail.data });
|
|
313
|
-
}}
|
|
314
|
-
classes={{ path: cls(debug && 'fill-danger/10 stroke-danger') }}
|
|
315
|
-
/>
|
|
316
|
-
</Svg>
|
|
317
|
-
{:else if mode === 'bounds' || mode === 'band'}
|
|
318
|
-
<slot tooltip={$tooltip} />
|
|
319
|
-
<Svg>
|
|
320
|
-
<g class="tooltip-rects">
|
|
321
|
-
{#each rects as rect}
|
|
322
|
-
<rect
|
|
323
|
-
x={rect.x}
|
|
324
|
-
y={rect.y}
|
|
325
|
-
width={rect.width}
|
|
326
|
-
height={rect.height}
|
|
327
|
-
class={cls(debug ? 'fill-danger/10 stroke-danger' : 'fill-transparent')}
|
|
328
|
-
on:pointerenter={(e) => showTooltip(e, rect.data)}
|
|
329
|
-
on:pointermove={(e) => showTooltip(e, rect.data)}
|
|
305
|
+
<slot tooltip={$tooltip} />
|
|
306
|
+
|
|
307
|
+
{#if mode === 'voronoi'}
|
|
308
|
+
<Svg>
|
|
309
|
+
<Voronoi
|
|
310
|
+
on:pointerenter={(e) => showTooltip(e.detail.event, e.detail.data)}
|
|
311
|
+
on:pointermove={(e) => showTooltip(e.detail.event, e.detail.data)}
|
|
330
312
|
on:pointerleave={hideTooltip}
|
|
331
313
|
on:click={(e) => {
|
|
332
|
-
onClick({ data:
|
|
314
|
+
onClick({ data: e.detail.data });
|
|
333
315
|
}}
|
|
316
|
+
classes={{ path: cls(debug && 'fill-danger/10 stroke-danger') }}
|
|
334
317
|
/>
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
{
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
</
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
318
|
+
</Svg>
|
|
319
|
+
{:else if mode === 'bounds' || mode === 'band'}
|
|
320
|
+
<Svg>
|
|
321
|
+
<g class="tooltip-rects">
|
|
322
|
+
{#each rects as rect}
|
|
323
|
+
<rect
|
|
324
|
+
x={rect.x}
|
|
325
|
+
y={rect.y}
|
|
326
|
+
width={rect.width}
|
|
327
|
+
height={rect.height}
|
|
328
|
+
class={cls(debug ? 'fill-danger/10 stroke-danger' : 'fill-transparent')}
|
|
329
|
+
on:pointerenter={(e) => showTooltip(e, rect.data)}
|
|
330
|
+
on:pointermove={(e) => showTooltip(e, rect.data)}
|
|
331
|
+
on:pointerleave={hideTooltip}
|
|
332
|
+
on:click={(e) => {
|
|
333
|
+
onClick({ data: rect.data });
|
|
334
|
+
}}
|
|
335
|
+
/>
|
|
336
|
+
{/each}
|
|
337
|
+
</g>
|
|
338
|
+
</Svg>
|
|
339
|
+
{:else if mode === 'quadtree' && debug}
|
|
340
|
+
<Svg pointerEvents={false}>
|
|
341
|
+
<ChartClipPath>
|
|
342
|
+
<g class="tooltip-quadtree">
|
|
343
|
+
{#each quadtreeRects(quadtree, false) as rect}
|
|
344
|
+
<rect
|
|
345
|
+
x={rect.x}
|
|
346
|
+
y={rect.y}
|
|
347
|
+
width={rect.width}
|
|
348
|
+
height={rect.height}
|
|
349
|
+
class={cls(debug ? 'fill-danger/10 stroke-danger' : 'fill-transparent')}
|
|
350
|
+
/>
|
|
351
|
+
{/each}
|
|
352
|
+
</g>
|
|
353
|
+
</ChartClipPath>
|
|
354
|
+
</Svg>
|
|
355
|
+
{/if}
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|