svelteplot 0.11.0 → 0.11.1-pr-520.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/Mark.svelte +6 -1
- package/dist/Mark.svelte.d.ts +1 -1
- package/dist/constants.js +2 -0
- package/dist/core/Plot.svelte +32 -3
- package/dist/helpers/arrowPath.js +10 -5
- package/dist/helpers/autoScales.js +7 -3
- package/dist/helpers/autoTicks.js +4 -4
- package/dist/helpers/autoTimeFormat.js +22 -12
- package/dist/helpers/colors.d.ts +4 -4
- package/dist/helpers/facets.d.ts +42 -1
- package/dist/helpers/facets.js +83 -0
- package/dist/helpers/math.js +1 -1
- package/dist/helpers/noise.js +1 -1
- package/dist/helpers/rasterInterpolate.d.ts +26 -0
- package/dist/helpers/rasterInterpolate.js +220 -0
- package/dist/helpers/roundedRect.js +1 -1
- package/dist/helpers/scales.d.ts +1 -0
- package/dist/helpers/scales.js +8 -5
- package/dist/helpers/time.js +1 -1
- package/dist/helpers/typeChecks.d.ts +1 -0
- package/dist/helpers/typeChecks.js +3 -0
- package/dist/marks/Area.svelte.d.ts +1 -1
- package/dist/marks/AreaX.svelte.d.ts +1 -1
- package/dist/marks/AreaY.svelte.d.ts +1 -1
- package/dist/marks/Arrow.svelte.d.ts +1 -1
- package/dist/marks/AxisX.svelte +8 -3
- package/dist/marks/AxisX.svelte.d.ts +1 -1
- package/dist/marks/AxisY.svelte +8 -3
- package/dist/marks/AxisY.svelte.d.ts +1 -1
- package/dist/marks/BarX.svelte.d.ts +1 -1
- package/dist/marks/BarY.svelte.d.ts +1 -1
- package/dist/marks/BollingerX.svelte.d.ts +1 -1
- package/dist/marks/BollingerY.svelte.d.ts +1 -1
- package/dist/marks/BoxY.svelte.d.ts +1 -1
- package/dist/marks/Brush.svelte.d.ts +1 -1
- package/dist/marks/Cell.svelte.d.ts +1 -1
- package/dist/marks/CellX.svelte.d.ts +1 -1
- package/dist/marks/CellY.svelte.d.ts +1 -1
- package/dist/marks/CustomMark.svelte.d.ts +1 -1
- package/dist/marks/DifferenceY.svelte.d.ts +1 -1
- package/dist/marks/Dot.svelte.d.ts +1 -1
- package/dist/marks/DotX.svelte.d.ts +1 -1
- package/dist/marks/DotY.svelte.d.ts +1 -1
- package/dist/marks/Frame.svelte.d.ts +1 -1
- package/dist/marks/Geo.svelte.d.ts +1 -1
- package/dist/marks/GridX.svelte.d.ts +1 -1
- package/dist/marks/GridY.svelte.d.ts +1 -1
- package/dist/marks/HTMLTooltip.svelte +28 -25
- package/dist/marks/Image.svelte.d.ts +1 -1
- package/dist/marks/Line.svelte +52 -15
- package/dist/marks/Line.svelte.d.ts +1 -1
- package/dist/marks/LineX.svelte.d.ts +1 -1
- package/dist/marks/LineY.svelte.d.ts +1 -1
- package/dist/marks/Link.svelte.d.ts +1 -1
- package/dist/marks/Pointer.svelte +31 -29
- package/dist/marks/Raster.svelte +414 -0
- package/dist/marks/Raster.svelte.d.ts +94 -0
- package/dist/marks/Rect.svelte.d.ts +1 -1
- package/dist/marks/RectX.svelte.d.ts +1 -1
- package/dist/marks/RectY.svelte.d.ts +1 -1
- package/dist/marks/RuleX.svelte.d.ts +1 -1
- package/dist/marks/RuleY.svelte.d.ts +1 -1
- package/dist/marks/Spike.svelte.d.ts +1 -1
- package/dist/marks/Text.svelte +7 -5
- package/dist/marks/Text.svelte.d.ts +2 -2
- package/dist/marks/TickX.svelte.d.ts +1 -1
- package/dist/marks/TickY.svelte.d.ts +1 -1
- package/dist/marks/Trail.svelte.d.ts +1 -1
- package/dist/marks/Vector.svelte.d.ts +1 -1
- package/dist/marks/WaffleX.svelte.d.ts +1 -1
- package/dist/marks/WaffleY.svelte.d.ts +1 -1
- package/dist/marks/helpers/Box.svelte.d.ts +1 -1
- package/dist/marks/helpers/MarkerPath.svelte.d.ts +1 -1
- package/dist/marks/helpers/Regression.svelte +2 -1
- package/dist/marks/helpers/trail.js +1 -1
- package/dist/marks/helpers/waffle.js +1 -1
- package/dist/marks/index.d.ts +1 -0
- package/dist/marks/index.js +1 -0
- package/dist/regression/polynomial.js +2 -2
- package/dist/transforms/bollinger.js +6 -3
- package/dist/transforms/density.js +3 -3
- package/dist/transforms/group.d.ts +1 -1
- package/dist/transforms/interval.d.ts +2 -2
- package/dist/transforms/jitter.d.ts +3 -3
- package/dist/transforms/map.d.ts +3 -3
- package/dist/transforms/map.js +2 -2
- package/dist/transforms/normalize.d.ts +2 -2
- package/dist/transforms/normalize.js +1 -1
- package/dist/transforms/select.d.ts +7 -7
- package/dist/transforms/window.d.ts +2 -2
- package/dist/types/mark.d.ts +3 -3
- package/dist/types/plot.d.ts +8 -1
- package/dist/types/scale.d.ts +2 -2
- package/package.json +183 -179
|
@@ -12,7 +12,7 @@ declare function $$render<Datum = RawValue>(): {
|
|
|
12
12
|
fill: ChannelAccessor<Datum>;
|
|
13
13
|
fillOpacity: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
14
14
|
fontFamily: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
15
|
-
fontSize: import("../types/index.js").ConstantAccessor<
|
|
15
|
+
fontSize: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
16
16
|
fontStyle: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
17
17
|
fontVariant: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
18
18
|
fontWeight: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
|
@@ -12,7 +12,7 @@ declare function $$render<Datum = RawValue>(): {
|
|
|
12
12
|
fill: ChannelAccessor<Datum>;
|
|
13
13
|
fillOpacity: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
14
14
|
fontFamily: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
15
|
-
fontSize: import("../types/index.js").ConstantAccessor<
|
|
15
|
+
fontSize: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
16
16
|
fontStyle: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
17
17
|
fontVariant: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
18
18
|
fontWeight: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
import { quadtree } from 'd3-quadtree';
|
|
28
28
|
import { projectX, projectY } from '../helpers/scales.js';
|
|
29
29
|
import { groupFacetsAndZ } from '../helpers/group.js';
|
|
30
|
+
import { detectFacet, facetKey } from '../helpers/facets.js';
|
|
31
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
30
32
|
|
|
31
33
|
const plot = usePlot();
|
|
32
34
|
|
|
@@ -40,21 +42,19 @@
|
|
|
40
42
|
let facetOffsetY = $state(0);
|
|
41
43
|
|
|
42
44
|
function onPointerMove(evt: MouseEvent) {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const facetIndex = +((facetEl as HTMLElement)?.dataset?.facet ?? 0);
|
|
49
|
-
const facetRect = ((facetEl?.firstChild as Element) ?? plot.body).getBoundingClientRect();
|
|
45
|
+
const { fxValue, fyValue, offsetX, offsetY } = detectFacet(evt, plot);
|
|
46
|
+
const bodyRect = plot.body.getBoundingClientRect();
|
|
47
|
+
|
|
48
|
+
facetOffsetX = offsetX;
|
|
49
|
+
facetOffsetY = offsetY;
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const relativeX = evt.clientX - bodyRect.left - offsetX;
|
|
52
|
+
const relativeY = evt.clientY - bodyRect.top - offsetY;
|
|
53
53
|
|
|
54
|
-
const
|
|
55
|
-
const
|
|
54
|
+
const key = facetKey(fxValue, fyValue);
|
|
55
|
+
const facetTrees = treeMap.get(key) ?? [];
|
|
56
|
+
const pt = facetTrees.length > 0 ? facetTrees[0].find(relativeX, relativeY, 25) : null;
|
|
56
57
|
|
|
57
|
-
const pt = trees[facetIndex].find(relativeX, relativeY, 25);
|
|
58
58
|
if (pt) {
|
|
59
59
|
tooltipX = resolveChannel('x', pt, { x, y, r });
|
|
60
60
|
tooltipY = resolveChannel('y', pt, { x, y, r });
|
|
@@ -73,25 +73,28 @@
|
|
|
73
73
|
plot.body?.addEventListener('pointermove', onPointerMove);
|
|
74
74
|
|
|
75
75
|
return () => {
|
|
76
|
-
plot.body?.removeEventListener('
|
|
76
|
+
plot.body?.removeEventListener('pointerleave', onPointerLeave);
|
|
77
77
|
plot.body?.removeEventListener('pointermove', onPointerMove);
|
|
78
78
|
};
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
groupFacetsAndZ(data, { fx, fy }, (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
quadtree<Datum>()
|
|
81
|
+
const treeMap = $derived.by(() => {
|
|
82
|
+
const map = new SvelteMap<string, ReturnType<typeof quadtree<Datum>>[]>();
|
|
83
|
+
groupFacetsAndZ(data, { fx, fy }, (items) => {
|
|
84
|
+
if (!items.length) return;
|
|
85
|
+
const fxVal = fx ? resolveChannel('fx', items[0], { fx }) : true;
|
|
86
|
+
const fyVal = fy ? resolveChannel('fy', items[0], { fy }) : true;
|
|
87
|
+
const key = facetKey(fxVal, fyVal);
|
|
88
|
+
const tree = quadtree<Datum>()
|
|
90
89
|
.x((d) => projectX('x', plot.scales, resolveChannel('x', d, { x, y, r })))
|
|
91
90
|
.y((d) => projectY('y', plot.scales, resolveChannel('y', d, { x, y, r })))
|
|
92
|
-
.addAll(items)
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
.addAll(items);
|
|
92
|
+
const existing = map.get(key) ?? [];
|
|
93
|
+
existing.push(tree);
|
|
94
|
+
map.set(key, existing);
|
|
95
|
+
});
|
|
96
|
+
return map;
|
|
97
|
+
});
|
|
95
98
|
</script>
|
|
96
99
|
|
|
97
100
|
<div
|
|
@@ -12,7 +12,7 @@ declare function $$render<Datum extends DataRecord>(): {
|
|
|
12
12
|
fill: ChannelAccessor<Datum>;
|
|
13
13
|
fillOpacity: ConstantAccessor<number, Datum>;
|
|
14
14
|
fontFamily: ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
15
|
-
fontSize: ConstantAccessor<
|
|
15
|
+
fontSize: ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
16
16
|
fontStyle: ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
17
17
|
fontVariant: ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
18
18
|
fontWeight: ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
package/dist/marks/Line.svelte
CHANGED
|
@@ -94,28 +94,65 @@
|
|
|
94
94
|
const args = $derived(sort(recordizeXY({ data, ...options })));
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Groups the data by the specified key
|
|
97
|
+
* Groups the data by the specified key (and optionally a secondary key).
|
|
98
|
+
* When a secondary key is provided, each primary group is further split by
|
|
99
|
+
* the secondary key, with each sub-segment extended to include the first point
|
|
100
|
+
* of the next sub-segment so consecutive segments share an endpoint (enabling
|
|
101
|
+
* multi-colored lines without gaps).
|
|
98
102
|
*/
|
|
99
|
-
function groupIndex(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
function groupIndex(
|
|
104
|
+
data: ScaledDataRecord[],
|
|
105
|
+
groupByKey: ChannelAccessor<Datum> | null,
|
|
106
|
+
secondaryKey: ChannelAccessor<Datum> | null = null
|
|
107
|
+
) {
|
|
108
|
+
if (!groupByKey && !secondaryKey) return [data];
|
|
109
|
+
|
|
110
|
+
// Group by the primary key
|
|
111
|
+
const primaryGroups: ScaledDataRecord[][] = [];
|
|
112
|
+
let primaryGroup: ScaledDataRecord[] = [];
|
|
113
|
+
let lastPrimaryValue: unknown;
|
|
104
114
|
for (const d of data) {
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
115
|
+
const primaryValue = resolveProp(groupByKey!, d.datum);
|
|
116
|
+
if (primaryValue === lastPrimaryValue) {
|
|
117
|
+
primaryGroup.push(d);
|
|
108
118
|
} else {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
primaryGroup = [d];
|
|
120
|
+
primaryGroups.push(primaryGroup);
|
|
121
|
+
lastPrimaryValue = primaryValue;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!secondaryKey) return primaryGroups;
|
|
126
|
+
|
|
127
|
+
// Further split each primary group by the secondary key. Each sub-segment is
|
|
128
|
+
// extended to include the first point of the next sub-segment so that
|
|
129
|
+
// consecutive segments share an endpoint (no gaps in multi-colored lines).
|
|
130
|
+
const result: ScaledDataRecord[][] = [];
|
|
131
|
+
for (const pGroup of primaryGroups) {
|
|
132
|
+
if (pGroup.length === 0) continue;
|
|
133
|
+
let subGroup: ScaledDataRecord[] = [pGroup[0]];
|
|
134
|
+
let lastSecondaryValue = resolveProp(secondaryKey, pGroup[0].datum);
|
|
135
|
+
for (let i = 1; i < pGroup.length; i++) {
|
|
136
|
+
const d = pGroup[i];
|
|
137
|
+
const secondaryValue = resolveProp(secondaryKey, d.datum);
|
|
138
|
+
if (secondaryValue === lastSecondaryValue) {
|
|
139
|
+
subGroup.push(d);
|
|
140
|
+
} else {
|
|
141
|
+
subGroup.push(d); // extend to connect to next sub-segment
|
|
142
|
+
result.push(subGroup);
|
|
143
|
+
subGroup = [d]; // new sub-segment begins here
|
|
144
|
+
lastSecondaryValue = secondaryValue;
|
|
145
|
+
}
|
|
113
146
|
}
|
|
147
|
+
result.push(subGroup);
|
|
114
148
|
}
|
|
115
|
-
return
|
|
149
|
+
return result;
|
|
116
150
|
}
|
|
117
151
|
|
|
118
152
|
const groupByKey = $derived(args.z || args.stroke) as ChannelAccessor<Datum> | null;
|
|
153
|
+
const secondaryKey = $derived(
|
|
154
|
+
args.z && args.stroke ? args.stroke : null
|
|
155
|
+
) as ChannelAccessor<Datum> | null;
|
|
119
156
|
|
|
120
157
|
const plot = usePlot();
|
|
121
158
|
|
|
@@ -155,7 +192,7 @@
|
|
|
155
192
|
{...args}>
|
|
156
193
|
{#snippet children({ mark, usedScales, scaledData })}
|
|
157
194
|
{#if scaledData.length > 0}
|
|
158
|
-
{@const groupedLineData = groupIndex(scaledData, groupByKey)}
|
|
195
|
+
{@const groupedLineData = groupIndex(scaledData, groupByKey, secondaryKey)}
|
|
159
196
|
{#if canvas}
|
|
160
197
|
<LineCanvas {groupedLineData} {mark} {usedScales} {linePath} {groupByKey} />
|
|
161
198
|
{:else}
|
|
@@ -14,7 +14,7 @@ declare function $$render<Datum extends DataRecord>(): {
|
|
|
14
14
|
fill: ChannelAccessor<Datum>;
|
|
15
15
|
fillOpacity: ConstantAccessor<number, Datum>;
|
|
16
16
|
fontFamily: ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
17
|
-
fontSize: ConstantAccessor<
|
|
17
|
+
fontSize: ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
18
18
|
fontStyle: ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
19
19
|
fontVariant: ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
20
20
|
fontWeight: ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
|
@@ -12,7 +12,7 @@ declare function $$render<Datum extends DataRow>(): {
|
|
|
12
12
|
fill: import("../types/index.js").ChannelAccessor<Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
13
13
|
fillOpacity: import("../types/index.js").ConstantAccessor<number, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
14
14
|
fontFamily: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontFamily, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
15
|
-
fontSize: import("../types/index.js").ConstantAccessor<
|
|
15
|
+
fontSize: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontSize<number>, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
16
16
|
fontStyle: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontStyle, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
17
17
|
fontVariant: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontVariant, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
18
18
|
fontWeight: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontWeight, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
@@ -12,7 +12,7 @@ declare function $$render<Datum extends DataRow>(): {
|
|
|
12
12
|
fill: import("../types/index.js").ChannelAccessor<Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
13
13
|
fillOpacity: import("../types/index.js").ConstantAccessor<number, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
14
14
|
fontFamily: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontFamily, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
15
|
-
fontSize: import("../types/index.js").ConstantAccessor<
|
|
15
|
+
fontSize: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontSize<number>, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
16
16
|
fontStyle: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontStyle, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
17
17
|
fontVariant: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontVariant, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
18
18
|
fontWeight: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontWeight, Record<string | symbol, import("../types/index.js").RawValue>>;
|
|
@@ -13,7 +13,7 @@ declare function $$render<Datum = DataRecord | GeoJSON.GeoJsonObject>(): {
|
|
|
13
13
|
fill: ChannelAccessor<Datum>;
|
|
14
14
|
fillOpacity: ConstantAccessor<number, Datum>;
|
|
15
15
|
fontFamily: ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
16
|
-
fontSize: ConstantAccessor<
|
|
16
|
+
fontSize: ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
17
17
|
fontStyle: ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
18
18
|
fontVariant: ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
19
19
|
fontWeight: ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
import { groupFacetsAndZ } from '../helpers/group.js';
|
|
41
41
|
import { getPlotDefaults } from '../hooks/plotDefaults.js';
|
|
42
42
|
import { usePlot } from '../hooks/usePlot.svelte.js';
|
|
43
|
+
import { detectFacet, facetKey } from '../helpers/facets.js';
|
|
44
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
43
45
|
|
|
44
46
|
const plot = usePlot();
|
|
45
47
|
|
|
@@ -71,17 +73,14 @@
|
|
|
71
73
|
let selectedData = $state<any[]>([]);
|
|
72
74
|
|
|
73
75
|
function onPointerMove(evt: MouseEvent) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
facetEl = facetEl.parentElement as Element | null;
|
|
77
|
-
}
|
|
78
|
-
const facetRect = ((facetEl?.firstChild as Element) ?? plot.body).getBoundingClientRect();
|
|
76
|
+
const { fxValue, fyValue, offsetX, offsetY } = detectFacet(evt, plot);
|
|
77
|
+
const bodyRect = plot.body.getBoundingClientRect();
|
|
79
78
|
|
|
80
|
-
const relativeX = evt.clientX -
|
|
81
|
-
const relativeY = evt.clientY -
|
|
79
|
+
const relativeX = evt.clientX - bodyRect.left - offsetX;
|
|
80
|
+
const relativeY = evt.clientY - bodyRect.top - offsetY;
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
updateSelection(relativeX, relativeY);
|
|
82
|
+
const key = facetKey(fxValue, fyValue);
|
|
83
|
+
updateSelection(relativeX, relativeY, key);
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
function onPointerLeave() {
|
|
@@ -89,13 +88,14 @@
|
|
|
89
88
|
if (onupdate) onupdate(selectedData);
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
function updateSelection(ex: number, ey: number) {
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
function updateSelection(ex: number, ey: number, key: string) {
|
|
92
|
+
const facetTrees = treeMap.get(key) ?? [];
|
|
93
|
+
// find data row with minimum distance to cursor
|
|
94
|
+
const points = facetTrees.map((tree) =>
|
|
95
95
|
tree.find(x != null ? ex : 0, y != null ? ey : 0, maxDistance)
|
|
96
96
|
);
|
|
97
97
|
// also include other points that share the same x or y value
|
|
98
|
-
const otherPoints =
|
|
98
|
+
const otherPoints = facetTrees.flatMap((tree, i) => {
|
|
99
99
|
return tree
|
|
100
100
|
.data()
|
|
101
101
|
.filter((d) => d !== points[i])
|
|
@@ -121,21 +121,19 @@
|
|
|
121
121
|
};
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
groupFacetsAndZ(indexData(data as object[]) as any, { x, y, z, fx, fy }, (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
groups.map((items) =>
|
|
134
|
-
quadtree<any>()
|
|
124
|
+
const treeMap = $derived.by(() => {
|
|
125
|
+
const map = new SvelteMap<string, ReturnType<typeof quadtree<any>>[]>();
|
|
126
|
+
groupFacetsAndZ(indexData(data as object[]) as any, { x, y, z, fx, fy }, (items) => {
|
|
127
|
+
if (!items.length) return;
|
|
128
|
+
// Recover fx/fy values from the first datum in the group
|
|
129
|
+
const fxVal = fx ? resolveChannel('fx', items[0], { fx }) : true;
|
|
130
|
+
const fyVal = fy ? resolveChannel('fy', items[0], { fy }) : true;
|
|
131
|
+
const key = facetKey(fxVal, fyVal);
|
|
132
|
+
const tree = quadtree<any>()
|
|
135
133
|
.x(x != null ? (d: any) => d[POINTER_X] : () => 0)
|
|
136
134
|
.y(y != null ? (d: any) => d[POINTER_Y] : () => 0)
|
|
137
135
|
.addAll(
|
|
138
|
-
items
|
|
136
|
+
items.map((d: any) => {
|
|
139
137
|
const [px, py] = projectXY(
|
|
140
138
|
plot.scales,
|
|
141
139
|
resolveChannel('x', d, { x }),
|
|
@@ -148,10 +146,14 @@
|
|
|
148
146
|
[POINTER_X]: px,
|
|
149
147
|
[POINTER_Y]: py
|
|
150
148
|
};
|
|
151
|
-
})
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
const existing = map.get(key) ?? [];
|
|
152
|
+
existing.push(tree);
|
|
153
|
+
map.set(key, existing);
|
|
154
|
+
});
|
|
155
|
+
return map;
|
|
156
|
+
});
|
|
155
157
|
</script>
|
|
156
158
|
|
|
157
159
|
{#if children}
|