layerchart 0.81.2 → 0.90.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/Arc.svelte +49 -14
- package/dist/components/Area.svelte +35 -11
- package/dist/components/Bar.svelte +15 -10
- package/dist/components/Bars.svelte +3 -3
- package/dist/components/Brush.svelte +20 -21
- package/dist/components/Calendar.svelte +2 -2
- package/dist/components/Chart.svelte +17 -4
- package/dist/components/Chart.svelte.d.ts +21 -10
- package/dist/components/ChartClipPath.svelte +0 -1
- package/dist/components/ChartClipPath.svelte.d.ts +0 -2
- package/dist/components/ChartContext.svelte +4 -11
- package/dist/components/ChartContext.svelte.d.ts +1 -1
- package/dist/components/Circle.svelte +35 -11
- package/dist/components/ClipPath.svelte +1 -1
- package/dist/components/ClipPath.svelte.d.ts +0 -5
- package/dist/components/ForceSimulation.svelte +8 -12
- package/dist/components/ForceSimulation.svelte.d.ts +6 -8
- package/dist/components/Frame.svelte +4 -7
- package/dist/components/Frame.svelte.d.ts +1 -5
- package/dist/components/GeoCircle.svelte +7 -1
- package/dist/components/GeoCircle.svelte.d.ts +6 -7
- package/dist/components/GeoPath.svelte +68 -39
- package/dist/components/GeoPath.svelte.d.ts +6 -12
- package/dist/components/GeoPoint.svelte +3 -24
- package/dist/components/GeoPoint.svelte.d.ts +4 -5
- package/dist/components/Graticule.svelte.d.ts +12 -6
- package/dist/components/Group.svelte +26 -6
- package/dist/components/Highlight.svelte +22 -12
- package/dist/components/Hull.svelte +20 -15
- package/dist/components/Hull.svelte.d.ts +7 -9
- package/dist/components/Legend.svelte +7 -7
- package/dist/components/Legend.svelte.d.ts +3 -3
- package/dist/components/Line.svelte +35 -10
- package/dist/components/Link.svelte +16 -9
- package/dist/components/Points.svelte +24 -57
- package/dist/components/Points.svelte.d.ts +0 -1
- package/dist/components/Rect.svelte +46 -15
- package/dist/components/Sankey.svelte +3 -4
- package/dist/components/Sankey.svelte.d.ts +1 -2
- package/dist/components/Spline.svelte +47 -11
- package/dist/components/Text.svelte +12 -6
- package/dist/components/TransformContext.svelte +8 -10
- package/dist/components/TransformContext.svelte.d.ts +9 -9
- package/dist/components/Voronoi.svelte +62 -40
- package/dist/components/Voronoi.svelte.d.ts +14 -13
- package/dist/components/charts/AreaChart.svelte +23 -15
- package/dist/components/charts/BarChart.svelte +24 -11
- package/dist/components/charts/LineChart.svelte +23 -15
- package/dist/components/charts/PieChart.svelte +24 -19
- package/dist/components/charts/PieChart.svelte.d.ts +29 -7
- package/dist/components/charts/ScatterChart.svelte +13 -7
- package/dist/components/index.d.ts +0 -1
- package/dist/components/index.js +0 -1
- package/dist/components/layout/Canvas.svelte +148 -7
- package/dist/components/layout/Canvas.svelte.d.ts +15 -2
- package/dist/components/tooltip/TooltipContext.svelte +25 -20
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +6 -2
- package/dist/utils/canvas.js +39 -33
- package/dist/utils/color.d.ts +15 -0
- package/dist/utils/color.js +15 -0
- package/package.json +1 -1
- package/dist/components/Brush.svelte.d.ts +0 -65
- package/dist/components/HitCanvas.svelte +0 -118
- package/dist/components/HitCanvas.svelte.d.ts +0 -32
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
interface $$Props extends ComponentProps<Chart<TData>> {
|
|
33
33
|
axis?: typeof axis;
|
|
34
34
|
brush?: typeof brush;
|
|
35
|
+
debug?: typeof debug;
|
|
35
36
|
grid?: typeof grid;
|
|
36
37
|
labels?: typeof labels;
|
|
37
38
|
legend?: typeof legend;
|
|
@@ -41,8 +42,8 @@
|
|
|
41
42
|
rule?: typeof rule;
|
|
42
43
|
series?: typeof series;
|
|
43
44
|
renderContext?: typeof renderContext;
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
onpointclick?: typeof onpointclick;
|
|
46
|
+
ontooltipclick?: typeof ontooltipclick;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export let data: $$Props['data'] = [];
|
|
@@ -75,13 +76,16 @@
|
|
|
75
76
|
export let rule: ComponentProps<Rule> | boolean = true;
|
|
76
77
|
|
|
77
78
|
/** Event dispatched with current tooltip data */
|
|
78
|
-
export let
|
|
79
|
+
export let ontooltipclick: (e: MouseEvent, details: { data: any }) => void = () => {};
|
|
79
80
|
|
|
80
81
|
/** Event dispatched when Highlight point is clicked (useful with multiple series) */
|
|
81
|
-
export let
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
export let onpointclick: (
|
|
83
|
+
e: MouseEvent,
|
|
84
|
+
details: {
|
|
85
|
+
data: HighlightPointData;
|
|
86
|
+
series: (typeof series)[number];
|
|
87
|
+
}
|
|
88
|
+
) => void = () => {};
|
|
85
89
|
|
|
86
90
|
export let props: {
|
|
87
91
|
brush?: Partial<ComponentProps<Brush>>;
|
|
@@ -109,6 +113,9 @@
|
|
|
109
113
|
/** Log initial render performance using `console.time` */
|
|
110
114
|
export let profile = false;
|
|
111
115
|
|
|
116
|
+
/** Enable debug mode */
|
|
117
|
+
export let debug = false;
|
|
118
|
+
|
|
112
119
|
$: allSeriesData = series
|
|
113
120
|
.flatMap((s) => s.data?.map((d) => ({ seriesKey: s.key, ...d })))
|
|
114
121
|
.filter((d) => d) as Array<TData & { stackData?: any }>;
|
|
@@ -208,7 +215,8 @@
|
|
|
208
215
|
? false
|
|
209
216
|
: {
|
|
210
217
|
mode: 'bisect-x',
|
|
211
|
-
|
|
218
|
+
onclick: ontooltipclick,
|
|
219
|
+
debug,
|
|
212
220
|
...props.tooltip?.context,
|
|
213
221
|
...$$props.tooltip,
|
|
214
222
|
}}
|
|
@@ -241,7 +249,7 @@
|
|
|
241
249
|
getSplineProps,
|
|
242
250
|
}}
|
|
243
251
|
<slot {...slotProps}>
|
|
244
|
-
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg} center={radial}>
|
|
252
|
+
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg} center={radial} {debug}>
|
|
245
253
|
<slot name="grid" {...slotProps}>
|
|
246
254
|
{#if grid}
|
|
247
255
|
<Grid x={radial} y {...typeof grid === 'object' ? grid : null} {...props.grid} />
|
|
@@ -313,9 +321,9 @@
|
|
|
313
321
|
),
|
|
314
322
|
}}
|
|
315
323
|
lines={i === 0}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
324
|
+
onpointclick={(e, detail) => onpointclick(e, { ...detail, series: s })}
|
|
325
|
+
onpointenter={() => (highlightSeriesKey = s.key)}
|
|
326
|
+
onpointleave={() => (highlightSeriesKey = null)}
|
|
319
327
|
{...props.highlight}
|
|
320
328
|
/>
|
|
321
329
|
{/each}
|
|
@@ -350,9 +358,9 @@
|
|
|
350
358
|
tickFormat={(key) => series.find((s) => s.key === key)?.label ?? key}
|
|
351
359
|
placement="bottom"
|
|
352
360
|
variant="swatches"
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
361
|
+
onclick={(e, item) => $selectedSeries.toggleSelected(item.value)}
|
|
362
|
+
onpointerenter={(e, item) => (highlightSeriesKey = item.value)}
|
|
363
|
+
onpointerleave={(e) => (highlightSeriesKey = null)}
|
|
356
364
|
{...props.legend}
|
|
357
365
|
{...typeof legend === 'object' ? legend : null}
|
|
358
366
|
classes={{
|
|
@@ -16,9 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { accessor, chartDataArray, type Accessor } from '../../utils/common.js';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
interface $$Props extends ChartProps {
|
|
19
|
+
interface $$Props extends ComponentProps<Chart<TData>> {
|
|
22
20
|
cornerRadius?: typeof cornerRadius;
|
|
23
21
|
innerRadius?: typeof innerRadius;
|
|
24
22
|
key?: typeof key;
|
|
@@ -30,16 +28,17 @@
|
|
|
30
28
|
center?: typeof center;
|
|
31
29
|
placement?: typeof placement;
|
|
32
30
|
profile?: typeof profile;
|
|
31
|
+
debug?: typeof debug;
|
|
33
32
|
props?: typeof props;
|
|
34
33
|
range?: typeof range;
|
|
35
34
|
series?: typeof series;
|
|
36
35
|
value?: typeof value;
|
|
37
36
|
renderContext?: typeof renderContext;
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
onarcclick?: typeof onarcclick;
|
|
38
|
+
ontooltipclick?: typeof ontooltipclick;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
export let data:
|
|
41
|
+
export let data: $$Props['data'] = [];
|
|
43
42
|
|
|
44
43
|
/** Key accessor */
|
|
45
44
|
export let key: Accessor<TData> = 'key';
|
|
@@ -98,12 +97,15 @@
|
|
|
98
97
|
/** Center chart. Override and use `props.group` for more control */
|
|
99
98
|
export let center = placement === 'center';
|
|
100
99
|
|
|
101
|
-
// TODO: Not usable with manual tooltip / arc path. Use `
|
|
100
|
+
// TODO: Not usable with manual tooltip / arc path. Use `onarcclick`?
|
|
102
101
|
/** Event dispatched with current tooltip data */
|
|
103
|
-
export let
|
|
102
|
+
export let ontooltipclick: (e: MouseEvent, detail: { data: any }) => void = () => {};
|
|
104
103
|
|
|
105
104
|
/** Event dispatched when individual Arc is clicked (useful with multiple series) */
|
|
106
|
-
export let
|
|
105
|
+
export let onarcclick: (
|
|
106
|
+
e: MouseEvent,
|
|
107
|
+
detail: { data: any; series: (typeof series)[number] }
|
|
108
|
+
) => void = () => {};
|
|
107
109
|
|
|
108
110
|
export let props: {
|
|
109
111
|
pie?: Partial<ComponentProps<Pie>>;
|
|
@@ -125,6 +127,9 @@
|
|
|
125
127
|
/** Log initial render performance using `console.time` */
|
|
126
128
|
export let profile = false;
|
|
127
129
|
|
|
130
|
+
/** Enable debug mode */
|
|
131
|
+
export let debug = false;
|
|
132
|
+
|
|
128
133
|
$: allSeriesData = series
|
|
129
134
|
.flatMap((s) => s.data?.map((d) => ({ seriesKey: s.key, ...d })))
|
|
130
135
|
.filter((d) => d) as Array<TData>;
|
|
@@ -201,7 +206,7 @@
|
|
|
201
206
|
visibleData,
|
|
202
207
|
}}
|
|
203
208
|
<slot {...slotProps}>
|
|
204
|
-
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg} {center}>
|
|
209
|
+
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg} {center} {debug}>
|
|
205
210
|
<slot name="belowMarks" {...slotProps} />
|
|
206
211
|
|
|
207
212
|
<slot name="marks" {...slotProps}>
|
|
@@ -230,10 +235,10 @@
|
|
|
230
235
|
track={{ fill: s.color ?? cScale?.(c(d)), 'fill-opacity': 0.1 }}
|
|
231
236
|
{tooltip}
|
|
232
237
|
data={d}
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
onclick={(e) => {
|
|
239
|
+
onarcclick(e, { data: d, series: s });
|
|
235
240
|
// Workaround for `tooltip={{ mode: 'manual' }}
|
|
236
|
-
|
|
241
|
+
ontooltipclick(e, { data: d });
|
|
237
242
|
}}
|
|
238
243
|
{...props.arc}
|
|
239
244
|
{...s.props}
|
|
@@ -266,10 +271,10 @@
|
|
|
266
271
|
fill={cScale?.(c(arc.data))}
|
|
267
272
|
data={arc.data}
|
|
268
273
|
{tooltip}
|
|
269
|
-
|
|
270
|
-
|
|
274
|
+
onclick={(e) => {
|
|
275
|
+
onarcclick(e, { data: arc.data, series: s });
|
|
271
276
|
// Workaround for `tooltip={{ mode: 'manual' }}
|
|
272
|
-
|
|
277
|
+
ontooltipclick(e, { data: arc.data });
|
|
273
278
|
}}
|
|
274
279
|
class={cls(
|
|
275
280
|
'transition-opacity',
|
|
@@ -297,9 +302,9 @@
|
|
|
297
302
|
}}
|
|
298
303
|
placement="bottom"
|
|
299
304
|
variant="swatches"
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
onclick={(e, item) => $selectedKeys.toggleSelected(item.value)}
|
|
306
|
+
onpointerenter={(e, item) => (highlightKey = item.value)}
|
|
307
|
+
onpointerleave={(e) => (highlightKey = null)}
|
|
303
308
|
{...props.legend}
|
|
304
309
|
{...typeof legend === 'object' ? legend : null}
|
|
305
310
|
classes={{
|
|
@@ -121,13 +121,13 @@ declare class __sveltets_Render<TData> {
|
|
|
121
121
|
geo?: import("svelte/store").Writable<import("d3-geo").GeoProjection>;
|
|
122
122
|
}> | undefined;
|
|
123
123
|
tooltip?: boolean | Partial<{
|
|
124
|
-
mode?: "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree"
|
|
124
|
+
mode?: "manual" | "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree";
|
|
125
125
|
findTooltipData?: "closest" | "left" | "right";
|
|
126
126
|
raiseTarget?: boolean;
|
|
127
127
|
locked?: boolean;
|
|
128
128
|
radius?: number;
|
|
129
129
|
debug?: boolean;
|
|
130
|
-
|
|
130
|
+
onclick?: ({ data }: {
|
|
131
131
|
data: any;
|
|
132
132
|
}) => any;
|
|
133
133
|
tooltip?: import("svelte/store").Writable<{
|
|
@@ -136,6 +136,7 @@ declare class __sveltets_Render<TData> {
|
|
|
136
136
|
data: any;
|
|
137
137
|
show: (e: PointerEvent, tooltipData?: any) => void;
|
|
138
138
|
hide: () => void;
|
|
139
|
+
mode: "manual" | "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree";
|
|
139
140
|
}>;
|
|
140
141
|
}> | undefined;
|
|
141
142
|
transform?: Partial<{
|
|
@@ -150,6 +151,15 @@ declare class __sveltets_Render<TData> {
|
|
|
150
151
|
disablePointer?: boolean;
|
|
151
152
|
initialScrollMode?: "none" | "scale" | "translate";
|
|
152
153
|
clickDistance?: number;
|
|
154
|
+
ondragstart?: (() => void) | undefined;
|
|
155
|
+
ondragend?: (() => void) | undefined;
|
|
156
|
+
ontransform?: ((e: {
|
|
157
|
+
scale: number;
|
|
158
|
+
translate: {
|
|
159
|
+
x: number;
|
|
160
|
+
y: number;
|
|
161
|
+
};
|
|
162
|
+
}) => void) | undefined;
|
|
153
163
|
initialTranslate?: {
|
|
154
164
|
x: number;
|
|
155
165
|
y: number;
|
|
@@ -192,7 +202,18 @@ declare class __sveltets_Render<TData> {
|
|
|
192
202
|
data: any;
|
|
193
203
|
show: (e: PointerEvent, tooltipData?: any) => void;
|
|
194
204
|
hide: () => void;
|
|
205
|
+
mode: "manual" | "bisect-x" | "bisect-y" | "band" | "bisect-band" | "bounds" | "voronoi" | "quadtree";
|
|
195
206
|
}> | undefined;
|
|
207
|
+
onresize?: ((e: import("../ChartContext.svelte").ChartResizeDetail) => void) | undefined;
|
|
208
|
+
ondragstart?: (() => void) | undefined;
|
|
209
|
+
ondragend?: (() => void) | undefined;
|
|
210
|
+
ontransform?: ((e: {
|
|
211
|
+
scale: number;
|
|
212
|
+
translate: {
|
|
213
|
+
x: number;
|
|
214
|
+
y: number;
|
|
215
|
+
};
|
|
216
|
+
}) => void) | undefined;
|
|
196
217
|
} & {
|
|
197
218
|
cornerRadius?: number;
|
|
198
219
|
innerRadius?: number | undefined;
|
|
@@ -211,9 +232,9 @@ declare class __sveltets_Render<TData> {
|
|
|
211
232
|
tickLength?: number | undefined;
|
|
212
233
|
placement?: ("center" | "bottom" | "left" | "right" | "top" | "top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
|
|
213
234
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
235
|
+
onclick?: ((e: MouseEvent, detail: any) => any) | undefined | undefined;
|
|
236
|
+
onpointerenter?: ((e: MouseEvent, detail: any) => any) | undefined | undefined;
|
|
237
|
+
onpointerleave?: ((e: MouseEvent, detail: any) => any) | undefined | undefined;
|
|
217
238
|
variant?: "ramp" | "swatches" | undefined;
|
|
218
239
|
classes?: {
|
|
219
240
|
root?: string;
|
|
@@ -231,6 +252,7 @@ declare class __sveltets_Render<TData> {
|
|
|
231
252
|
center?: boolean;
|
|
232
253
|
placement?: "center" | "left" | "right";
|
|
233
254
|
profile?: boolean;
|
|
255
|
+
debug?: boolean;
|
|
234
256
|
props?: {
|
|
235
257
|
pie?: Partial<ComponentProps<Pie>>;
|
|
236
258
|
group?: Partial<ComponentProps<Group>>;
|
|
@@ -259,7 +281,7 @@ declare class __sveltets_Render<TData> {
|
|
|
259
281
|
}[] | undefined;
|
|
260
282
|
value?: Accessor<TData>;
|
|
261
283
|
renderContext?: "canvas" | "svg";
|
|
262
|
-
|
|
284
|
+
onarcclick?: ((e: MouseEvent, detail: {
|
|
263
285
|
data: any;
|
|
264
286
|
series: {
|
|
265
287
|
key: string | number;
|
|
@@ -273,7 +295,7 @@ declare class __sveltets_Render<TData> {
|
|
|
273
295
|
props?: Partial<ComponentProps<Arc>>;
|
|
274
296
|
};
|
|
275
297
|
}) => void) | undefined;
|
|
276
|
-
|
|
298
|
+
ontooltipclick?: ((e: MouseEvent, detail: {
|
|
277
299
|
data: any;
|
|
278
300
|
}) => void) | undefined;
|
|
279
301
|
};
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
props?: typeof props;
|
|
37
37
|
series?: typeof series;
|
|
38
38
|
renderContext?: typeof renderContext;
|
|
39
|
-
|
|
39
|
+
ontooltipclick?: typeof ontooltipclick;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export let data: $$Props['data'] = [];
|
|
@@ -65,15 +65,17 @@
|
|
|
65
65
|
export let rule: ComponentProps<Rule> | boolean = true;
|
|
66
66
|
|
|
67
67
|
/** Event dispatched with current tooltip data */
|
|
68
|
-
export let
|
|
68
|
+
export let ontooltipclick: (e: MouseEvent, detail: { data: any }) => void = () => {};
|
|
69
69
|
|
|
70
70
|
export let props: {
|
|
71
71
|
brush?: Partial<ComponentProps<Brush>>;
|
|
72
|
+
debug?: typeof debug;
|
|
72
73
|
grid?: Partial<ComponentProps<Grid>>;
|
|
73
74
|
highlight?: Partial<ComponentProps<Highlight>>;
|
|
74
75
|
labels?: Partial<ComponentProps<Labels>>;
|
|
75
76
|
legend?: Partial<ComponentProps<Legend>>;
|
|
76
77
|
points?: Partial<ComponentProps<Points>>;
|
|
78
|
+
profile?: typeof profile;
|
|
77
79
|
rule?: Partial<ComponentProps<Rule>>;
|
|
78
80
|
tooltip?: {
|
|
79
81
|
context?: Partial<ComponentProps<Tooltip.Context>>;
|
|
@@ -92,6 +94,9 @@
|
|
|
92
94
|
/** Log initial render performance using `console.time` */
|
|
93
95
|
export let profile = false;
|
|
94
96
|
|
|
97
|
+
/** Enable debug mode */
|
|
98
|
+
export let debug = false;
|
|
99
|
+
|
|
95
100
|
// Default xScale based on first data's `x` value
|
|
96
101
|
$: xScale =
|
|
97
102
|
$$props.xScale ??
|
|
@@ -175,7 +180,8 @@
|
|
|
175
180
|
? false
|
|
176
181
|
: {
|
|
177
182
|
mode: 'voronoi',
|
|
178
|
-
|
|
183
|
+
onclick: ontooltipclick,
|
|
184
|
+
debug,
|
|
179
185
|
...props.tooltip?.context,
|
|
180
186
|
...$$props.tooltip,
|
|
181
187
|
}}
|
|
@@ -213,7 +219,7 @@
|
|
|
213
219
|
: null}
|
|
214
220
|
|
|
215
221
|
<slot {...slotProps}>
|
|
216
|
-
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg}>
|
|
222
|
+
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg} {debug}>
|
|
217
223
|
<slot name="grid" {...slotProps}>
|
|
218
224
|
{#if grid}
|
|
219
225
|
<Grid x y {...typeof grid === 'object' ? grid : null} {...props.grid} />
|
|
@@ -300,9 +306,9 @@
|
|
|
300
306
|
tickFormat={(key) => series.find((s) => s.key === key)?.label ?? key}
|
|
301
307
|
placement="bottom"
|
|
302
308
|
variant="swatches"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
309
|
+
onclick={(e, item) => $selectedSeries.toggleSelected(item.value)}
|
|
310
|
+
onpointerenter={(e, item) => (highlightSeriesKey = item.value)}
|
|
311
|
+
onpointerleave={(e) => (highlightSeriesKey = null)}
|
|
306
312
|
{...props.legend}
|
|
307
313
|
{...typeof legend === 'object' ? legend : null}
|
|
308
314
|
classes={{
|
|
@@ -31,7 +31,6 @@ export { default as Graticule } from './Graticule.svelte';
|
|
|
31
31
|
export { default as Grid } from './Grid.svelte';
|
|
32
32
|
export { default as Group } from './Group.svelte';
|
|
33
33
|
export { default as Highlight } from './Highlight.svelte';
|
|
34
|
-
export { default as HitCanvas } from './HitCanvas.svelte';
|
|
35
34
|
export { default as Hull } from './Hull.svelte';
|
|
36
35
|
export { default as Labels } from './Labels.svelte';
|
|
37
36
|
export { default as Legend } from './Legend.svelte';
|
package/dist/components/index.js
CHANGED
|
@@ -32,7 +32,6 @@ export { default as Graticule } from './Graticule.svelte';
|
|
|
32
32
|
export { default as Grid } from './Grid.svelte';
|
|
33
33
|
export { default as Group } from './Group.svelte';
|
|
34
34
|
export { default as Highlight } from './Highlight.svelte';
|
|
35
|
-
export { default as HitCanvas } from './HitCanvas.svelte';
|
|
36
35
|
export { default as Hull } from './Hull.svelte';
|
|
37
36
|
export { default as Labels } from './Labels.svelte';
|
|
38
37
|
export { default as Legend } from './Legend.svelte';
|
|
@@ -3,8 +3,19 @@
|
|
|
3
3
|
|
|
4
4
|
type ComponentRender = {
|
|
5
5
|
name: string;
|
|
6
|
-
render: (ctx: CanvasRenderingContext2D) => any;
|
|
6
|
+
render: (ctx: CanvasRenderingContext2D, styleOverrides?: ComputedStylesOptions) => any;
|
|
7
7
|
retainState?: boolean;
|
|
8
|
+
events?: {
|
|
9
|
+
click?: (e: MouseEvent) => void;
|
|
10
|
+
dblclick?: (e: MouseEvent) => void;
|
|
11
|
+
pointerenter?: (e: PointerEvent) => void;
|
|
12
|
+
pointerover?: (e: PointerEvent) => void;
|
|
13
|
+
pointermove?: (e: PointerEvent) => void;
|
|
14
|
+
pointerleave?: (e: PointerEvent) => void;
|
|
15
|
+
pointerout?: (e: PointerEvent) => void;
|
|
16
|
+
pointerdown?: (e: PointerEvent) => void;
|
|
17
|
+
touchmove?: (e: TouchEvent) => void;
|
|
18
|
+
};
|
|
8
19
|
};
|
|
9
20
|
|
|
10
21
|
export type CanvasContext = {
|
|
@@ -30,7 +41,10 @@
|
|
|
30
41
|
|
|
31
42
|
import { chartContext } from '../ChartContext.svelte';
|
|
32
43
|
import { transformContext } from '../TransformContext.svelte';
|
|
33
|
-
import { scaleCanvas } from '../../utils/canvas.js';
|
|
44
|
+
import { getPixelColor, scaleCanvas, type ComputedStylesOptions } from '../../utils/canvas.js';
|
|
45
|
+
import { getColorStr, rgbColorGenerator } from '../../utils/color.js';
|
|
46
|
+
import { localPoint } from '../../utils/event.js';
|
|
47
|
+
import { tooltipContext } from '../tooltip/TooltipContext.svelte';
|
|
34
48
|
|
|
35
49
|
const { width, height, containerWidth, containerHeight, padding } = chartContext();
|
|
36
50
|
|
|
@@ -68,14 +82,78 @@
|
|
|
68
82
|
*/
|
|
69
83
|
export let center: boolean | 'x' | 'y' = false;
|
|
70
84
|
|
|
85
|
+
/** Show hit canvas for debugging */
|
|
86
|
+
export let debug = false;
|
|
87
|
+
|
|
71
88
|
let components = new Map<Symbol, ComponentRender>();
|
|
72
89
|
let pendingInvalidation = false;
|
|
73
90
|
let frameId: number | undefined;
|
|
74
91
|
|
|
75
|
-
const { mode, scale, translate } = transformContext();
|
|
92
|
+
const { mode, scale, translate, dragging, moving } = transformContext();
|
|
93
|
+
const tooltip = tooltipContext();
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* HitCanvas
|
|
97
|
+
*/
|
|
98
|
+
let hitCanvasElement: HTMLCanvasElement | undefined = undefined;
|
|
99
|
+
let hitCanvasContext: CanvasRenderingContext2D | undefined = undefined;
|
|
100
|
+
let colorGenerator = rgbColorGenerator();
|
|
101
|
+
let activeCanvas = false;
|
|
102
|
+
let lastActiveComponent: ComponentRender | undefined | null;
|
|
103
|
+
const componentByColor = new Map<string, ComponentRender>();
|
|
104
|
+
|
|
105
|
+
function getPointerComponent(e: PointerEvent | MouseEvent | TouchEvent) {
|
|
106
|
+
const { x, y } = localPoint(e.target as HTMLCanvasElement, e) ?? { x: 0, y: 0 };
|
|
107
|
+
const color = getPixelColor(hitCanvasContext!, x, y);
|
|
108
|
+
const colorKey = getColorStr(color);
|
|
109
|
+
return componentByColor.get(colorKey);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function onPointerMove(e: PointerEvent) {
|
|
113
|
+
activeCanvas = true;
|
|
114
|
+
const component = getPointerComponent(e);
|
|
115
|
+
|
|
116
|
+
if (lastActiveComponent == null) {
|
|
117
|
+
// TODO: Should these be handled differently
|
|
118
|
+
component?.events?.pointerenter?.(e);
|
|
119
|
+
component?.events?.pointerover?.(e);
|
|
120
|
+
} else if (lastActiveComponent != component) {
|
|
121
|
+
// TODO: Should these be handled differently
|
|
122
|
+
lastActiveComponent?.events?.pointerleave?.(e);
|
|
123
|
+
lastActiveComponent?.events?.pointerout?.(e);
|
|
124
|
+
|
|
125
|
+
component?.events?.pointermove?.(e);
|
|
126
|
+
} else {
|
|
127
|
+
component?.events?.pointermove?.(e);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (e.buttons === 1) {
|
|
131
|
+
component?.events?.pointerdown?.(e);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
lastActiveComponent = component;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function onPointerLeave(e: PointerEvent) {
|
|
138
|
+
// Pointer outside of canvas
|
|
139
|
+
|
|
140
|
+
// Call last active component `pointerleave` event in case it was not triggered by hit canvas (quickly exiting canvas element before `pointermove` is triggered)
|
|
141
|
+
lastActiveComponent?.events?.pointerleave?.(e);
|
|
142
|
+
lastActiveComponent?.events?.pointerout?.(e);
|
|
143
|
+
|
|
144
|
+
lastActiveComponent = null;
|
|
145
|
+
activeCanvas = false;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* end HitCanvas
|
|
149
|
+
*/
|
|
76
150
|
|
|
77
151
|
onMount(() => {
|
|
78
152
|
context = element?.getContext('2d', { willReadFrequently }) as CanvasRenderingContext2D;
|
|
153
|
+
|
|
154
|
+
hitCanvasContext = hitCanvasElement?.getContext('2d', {
|
|
155
|
+
willReadFrequently: true,
|
|
156
|
+
}) as CanvasRenderingContext2D;
|
|
79
157
|
});
|
|
80
158
|
|
|
81
159
|
onDestroy(() => {
|
|
@@ -110,6 +188,16 @@
|
|
|
110
188
|
context.scale($scale, $scale);
|
|
111
189
|
}
|
|
112
190
|
|
|
191
|
+
// Sync hit canvas transform with main canvas
|
|
192
|
+
if (hitCanvasContext) {
|
|
193
|
+
scaleCanvas(hitCanvasContext, $containerWidth, $containerHeight);
|
|
194
|
+
hitCanvasContext.clearRect(0, 0, $containerWidth, $containerHeight);
|
|
195
|
+
hitCanvasContext.setTransform(context.getTransform());
|
|
196
|
+
|
|
197
|
+
// Reset color generator whenever updated so always reusing same colors (and not exhausting)
|
|
198
|
+
colorGenerator = rgbColorGenerator();
|
|
199
|
+
}
|
|
200
|
+
|
|
113
201
|
components.forEach((c) => {
|
|
114
202
|
if (c.retainState) {
|
|
115
203
|
// Do not call save/restore canvas draw state (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save) (ex. Group ctx.translate() affecting children)
|
|
@@ -119,6 +207,27 @@
|
|
|
119
207
|
c.render(context);
|
|
120
208
|
context.restore();
|
|
121
209
|
}
|
|
210
|
+
|
|
211
|
+
// Delayed rendering using `activeCanvas` can cause a delay for tooltip interactivity for complex canvases (ex. country choropleth) so only ignore while moving/animating programmatically (ex. clicking on countries on Animated Globe)
|
|
212
|
+
const inactiveMoving = !activeCanvas && $moving;
|
|
213
|
+
|
|
214
|
+
const componentHasEvents = c.events && Object.values(c.events).filter((d) => d).length > 0;
|
|
215
|
+
|
|
216
|
+
if (hitCanvasContext && componentHasEvents && !inactiveMoving && !$dragging) {
|
|
217
|
+
const color = getColorStr(colorGenerator.next().value);
|
|
218
|
+
// Stroking shape seems to help with dark border, but there is still antialising and thus gaps
|
|
219
|
+
const styleOverrides = { styles: { fill: color, stroke: color, _fillOpacity: 0.1 } };
|
|
220
|
+
|
|
221
|
+
if (c.retainState) {
|
|
222
|
+
c.render(hitCanvasContext, styleOverrides);
|
|
223
|
+
} else {
|
|
224
|
+
hitCanvasContext.save();
|
|
225
|
+
c.render(hitCanvasContext, styleOverrides);
|
|
226
|
+
hitCanvasContext.restore();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
componentByColor.set(color, c);
|
|
230
|
+
}
|
|
122
231
|
});
|
|
123
232
|
|
|
124
233
|
pendingInvalidation = false;
|
|
@@ -144,8 +253,8 @@
|
|
|
144
253
|
};
|
|
145
254
|
|
|
146
255
|
$: {
|
|
147
|
-
// Redraw when resized
|
|
148
|
-
$containerWidth, $containerHeight;
|
|
256
|
+
// Redraw when resized or transform dragging changes. Note: adding `activeCanvas` (pointer enters/exits canvas) causes initial interactivity issues while canvas is rendering and is not needed
|
|
257
|
+
$containerWidth, $containerHeight && $dragging;
|
|
149
258
|
canvasContext.invalidate();
|
|
150
259
|
}
|
|
151
260
|
|
|
@@ -164,16 +273,48 @@
|
|
|
164
273
|
aria-label={label}
|
|
165
274
|
aria-labelledby={labelledBy}
|
|
166
275
|
aria-describedby={describedBy}
|
|
276
|
+
on:click={(e) => {
|
|
277
|
+
const component = getPointerComponent(e);
|
|
278
|
+
component?.events?.click?.(e);
|
|
279
|
+
}}
|
|
280
|
+
on:click
|
|
281
|
+
on:dblclick={(e) => {
|
|
282
|
+
const component = getPointerComponent(e);
|
|
283
|
+
component?.events?.dblclick?.(e);
|
|
284
|
+
}}
|
|
285
|
+
on:pointerenter={onPointerMove}
|
|
167
286
|
on:pointerenter
|
|
287
|
+
on:pointermove={onPointerMove}
|
|
168
288
|
on:pointermove
|
|
289
|
+
on:pointerleave={onPointerLeave}
|
|
169
290
|
on:pointerleave
|
|
170
|
-
on:
|
|
291
|
+
on:touchmove={(e) => {
|
|
292
|
+
// Prevent touch from interfering with pointer if over data
|
|
293
|
+
if (lastActiveComponent) {
|
|
294
|
+
e.preventDefault();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const component = getPointerComponent(e);
|
|
298
|
+
component?.events?.touchmove?.(e);
|
|
299
|
+
}}
|
|
171
300
|
on:touchmove
|
|
172
|
-
on:click
|
|
173
301
|
>
|
|
174
302
|
<slot name="fallback">
|
|
175
303
|
{fallback || ''}
|
|
176
304
|
</slot>
|
|
177
305
|
</canvas>
|
|
178
306
|
|
|
307
|
+
<!-- Hit canvas used for hidden context -->
|
|
308
|
+
<canvas
|
|
309
|
+
bind:this={hitCanvasElement}
|
|
310
|
+
class={cls(
|
|
311
|
+
'layerchart-hitcanvas',
|
|
312
|
+
'absolute top-0 left-0 w-full h-full',
|
|
313
|
+
'pointer-events-none', // events all handled by main canvas
|
|
314
|
+
// '[image-rendering:pixelated]', // https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering
|
|
315
|
+
'border border-danger',
|
|
316
|
+
!debug && 'opacity-0'
|
|
317
|
+
)}
|
|
318
|
+
></canvas>
|
|
319
|
+
|
|
179
320
|
<slot {element} {context}></slot>
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
type ComponentRender = {
|
|
3
3
|
name: string;
|
|
4
|
-
render: (ctx: CanvasRenderingContext2D) => any;
|
|
4
|
+
render: (ctx: CanvasRenderingContext2D, styleOverrides?: ComputedStylesOptions) => any;
|
|
5
5
|
retainState?: boolean;
|
|
6
|
+
events?: {
|
|
7
|
+
click?: (e: MouseEvent) => void;
|
|
8
|
+
dblclick?: (e: MouseEvent) => void;
|
|
9
|
+
pointerenter?: (e: PointerEvent) => void;
|
|
10
|
+
pointerover?: (e: PointerEvent) => void;
|
|
11
|
+
pointermove?: (e: PointerEvent) => void;
|
|
12
|
+
pointerleave?: (e: PointerEvent) => void;
|
|
13
|
+
pointerout?: (e: PointerEvent) => void;
|
|
14
|
+
pointerdown?: (e: PointerEvent) => void;
|
|
15
|
+
touchmove?: (e: TouchEvent) => void;
|
|
16
|
+
};
|
|
6
17
|
};
|
|
7
18
|
export type CanvasContext = {
|
|
8
19
|
/** Register component to render. Returns method to unregister on component destory */
|
|
@@ -11,6 +22,7 @@ export type CanvasContext = {
|
|
|
11
22
|
};
|
|
12
23
|
export declare const canvasContextKey: unique symbol;
|
|
13
24
|
export declare function getCanvasContext(): CanvasContext;
|
|
25
|
+
import { type ComputedStylesOptions } from '../../utils/canvas.js';
|
|
14
26
|
declare const __propDef: {
|
|
15
27
|
props: {
|
|
16
28
|
[x: string]: any;
|
|
@@ -24,13 +36,14 @@ declare const __propDef: {
|
|
|
24
36
|
labelledBy?: string | undefined | undefined;
|
|
25
37
|
describedBy?: string | undefined | undefined;
|
|
26
38
|
center?: boolean | "x" | "y" | undefined;
|
|
39
|
+
debug?: boolean | undefined;
|
|
27
40
|
};
|
|
28
41
|
events: {
|
|
42
|
+
click: MouseEvent;
|
|
29
43
|
pointerenter: PointerEvent;
|
|
30
44
|
pointermove: PointerEvent;
|
|
31
45
|
pointerleave: PointerEvent;
|
|
32
46
|
touchmove: TouchEvent;
|
|
33
|
-
click: MouseEvent;
|
|
34
47
|
} & {
|
|
35
48
|
[evt: string]: CustomEvent<any>;
|
|
36
49
|
};
|