svelteplot 0.13.0 → 0.14.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/helpers/group.d.ts +1 -1
- package/dist/helpers/group.js +3 -3
- package/dist/marks/ColorLegend.svelte +5 -1
- package/dist/marks/Contour.svelte +21 -30
- package/dist/marks/Contour.svelte.d.ts +2 -0
- package/dist/marks/DelaunayLink.svelte +127 -0
- package/dist/marks/DelaunayLink.svelte.d.ts +175 -0
- package/dist/marks/DelaunayMesh.svelte +102 -0
- package/dist/marks/DelaunayMesh.svelte.d.ts +172 -0
- package/dist/marks/Density.svelte +461 -0
- package/dist/marks/Density.svelte.d.ts +87 -0
- package/dist/marks/Hull.svelte +103 -0
- package/dist/marks/Hull.svelte.d.ts +175 -0
- package/dist/marks/Voronoi.svelte +118 -0
- package/dist/marks/Voronoi.svelte.d.ts +172 -0
- package/dist/marks/VoronoiMesh.svelte +109 -0
- package/dist/marks/VoronoiMesh.svelte.d.ts +172 -0
- package/dist/marks/helpers/DensityCanvas.svelte +118 -0
- package/dist/marks/helpers/DensityCanvas.svelte.d.ts +18 -0
- package/dist/marks/helpers/GeoPathCanvas.svelte +125 -0
- package/dist/marks/helpers/GeoPathCanvas.svelte.d.ts +24 -0
- package/dist/marks/helpers/GeoPathGroup.svelte +103 -0
- package/dist/marks/helpers/GeoPathGroup.svelte.d.ts +37 -0
- package/dist/marks/helpers/PathGroup.svelte +100 -0
- package/dist/marks/helpers/PathGroup.svelte.d.ts +16 -0
- package/dist/marks/helpers/PathItems.svelte +112 -0
- package/dist/marks/helpers/PathItems.svelte.d.ts +16 -0
- package/dist/marks/index.d.ts +7 -1
- package/dist/marks/index.js +7 -1
- package/dist/types/mark.d.ts +1 -1
- package/dist/types/plot.d.ts +25 -1
- package/package.json +1 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { DataRecord, ChannelAccessor } from '../types/index.js';
|
|
2
|
+
declare function $$render<Datum extends DataRecord>(): {
|
|
3
|
+
props: {
|
|
4
|
+
/** Input data — an array of records with x/y positions. */
|
|
5
|
+
data?: Datum[] | null;
|
|
6
|
+
/** x position channel (data space). */
|
|
7
|
+
x?: ChannelAccessor<Datum>;
|
|
8
|
+
/** y position channel (data space). */
|
|
9
|
+
y?: ChannelAccessor<Datum>;
|
|
10
|
+
/** Optional weight channel; defaults to 1 for each point. */
|
|
11
|
+
weight?: ChannelAccessor<Datum>;
|
|
12
|
+
/**
|
|
13
|
+
* Gaussian kernel bandwidth in screen pixels (default 20).
|
|
14
|
+
* Larger values produce smoother, more blurred density estimates.
|
|
15
|
+
*/
|
|
16
|
+
bandwidth?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Density threshold levels. Can be:
|
|
19
|
+
* - a **count** (number): that many evenly-spaced levels from 0 to the
|
|
20
|
+
* maximum density (default 20)
|
|
21
|
+
* - an explicit **array** of threshold values in k-scaled density units
|
|
22
|
+
* (where k = 100; values from 0 to roughly 100× the peak density)
|
|
23
|
+
*/
|
|
24
|
+
thresholds?: number | number[];
|
|
25
|
+
/**
|
|
26
|
+
* Fill color for density bands. Use `"density"` to map each band's
|
|
27
|
+
* estimated density through the plot's color scale. Default `"none"`.
|
|
28
|
+
*/
|
|
29
|
+
fill?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Stroke color for density isolines. Use `"density"` to map each
|
|
32
|
+
* isoline's estimated density through the plot's color scale.
|
|
33
|
+
* Default `"currentColor"` when fill is `"none"`, otherwise `"none"`.
|
|
34
|
+
*/
|
|
35
|
+
stroke?: string;
|
|
36
|
+
strokeWidth?: number;
|
|
37
|
+
strokeOpacity?: number;
|
|
38
|
+
fillOpacity?: number;
|
|
39
|
+
opacity?: number;
|
|
40
|
+
strokeMiterlimit?: number;
|
|
41
|
+
clipPath?: string;
|
|
42
|
+
class?: string;
|
|
43
|
+
/** Render using a canvas element instead of SVG paths. */
|
|
44
|
+
canvas?: boolean;
|
|
45
|
+
/** the horizontal facet channel */
|
|
46
|
+
fx?: ChannelAccessor<Datum>;
|
|
47
|
+
/** the vertical facet channel */
|
|
48
|
+
fy?: ChannelAccessor<Datum>;
|
|
49
|
+
};
|
|
50
|
+
exports: {};
|
|
51
|
+
bindings: "";
|
|
52
|
+
slots: {};
|
|
53
|
+
events: {};
|
|
54
|
+
};
|
|
55
|
+
declare class __sveltets_Render<Datum extends DataRecord> {
|
|
56
|
+
props(): ReturnType<typeof $$render<Datum>>['props'];
|
|
57
|
+
events(): ReturnType<typeof $$render<Datum>>['events'];
|
|
58
|
+
slots(): ReturnType<typeof $$render<Datum>>['slots'];
|
|
59
|
+
bindings(): "";
|
|
60
|
+
exports(): {};
|
|
61
|
+
}
|
|
62
|
+
interface $$IsomorphicComponent {
|
|
63
|
+
new <Datum extends DataRecord>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Datum>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Datum>['props']>, ReturnType<__sveltets_Render<Datum>['events']>, ReturnType<__sveltets_Render<Datum>['slots']>> & {
|
|
64
|
+
$$bindings?: ReturnType<__sveltets_Render<Datum>['bindings']>;
|
|
65
|
+
} & ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
66
|
+
<Datum extends DataRecord>(internal: unknown, props: ReturnType<__sveltets_Render<Datum>['props']> & {}): ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
67
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Renders two-dimensional kernel density estimation as filled or stroked
|
|
71
|
+
* contour paths.
|
|
72
|
+
*
|
|
73
|
+
* Data points with `x` and `y` channels are projected into pixel space and
|
|
74
|
+
* passed to d3's `contourDensity` estimator, which uses a Gaussian kernel to
|
|
75
|
+
* produce a density grid. Iso-density contour bands are then drawn using the
|
|
76
|
+
* marching-squares algorithm.
|
|
77
|
+
*
|
|
78
|
+
* Styling: `fill` and `stroke` accept ordinary CSS color strings **or** the
|
|
79
|
+
* special keyword `"density"`, which maps each contour level's estimated
|
|
80
|
+
* density through the plot's color scale. Defaults: `fill="none"`,
|
|
81
|
+
* `stroke="currentColor"`.
|
|
82
|
+
*
|
|
83
|
+
* Supports faceting via `fx`/`fy`.
|
|
84
|
+
*/
|
|
85
|
+
declare const Density: $$IsomorphicComponent;
|
|
86
|
+
type Density<Datum extends DataRecord> = InstanceType<typeof Density<Datum>>;
|
|
87
|
+
export default Density;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
Renders the convex hull of data points. Supports grouping by z/fill/stroke
|
|
3
|
+
to draw separate hulls per group.
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts" generics="Datum = DataRecord">
|
|
6
|
+
interface HullMarkProps extends BaseMarkProps<Datum> {
|
|
7
|
+
/** the input data array */
|
|
8
|
+
data?: Datum[];
|
|
9
|
+
/** the horizontal position channel */
|
|
10
|
+
x?: ChannelAccessor<Datum>;
|
|
11
|
+
/** the vertical position channel */
|
|
12
|
+
y?: ChannelAccessor<Datum>;
|
|
13
|
+
/** the grouping channel; separate hulls per group */
|
|
14
|
+
z?: ChannelAccessor<Datum>;
|
|
15
|
+
/** Render using a canvas element instead of SVG paths. */
|
|
16
|
+
canvas?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
import { Delaunay } from 'd3-delaunay';
|
|
20
|
+
import type {
|
|
21
|
+
DataRecord,
|
|
22
|
+
BaseMarkProps,
|
|
23
|
+
ChannelAccessor,
|
|
24
|
+
MarkType,
|
|
25
|
+
ScaledDataRecord
|
|
26
|
+
} from '../types/index.js';
|
|
27
|
+
import { groupFacetsAndZ } from '../helpers/group.js';
|
|
28
|
+
import { recordizeXY } from '../transforms/recordize.js';
|
|
29
|
+
import Mark from '../Mark.svelte';
|
|
30
|
+
import PathGroup from './helpers/PathGroup.svelte';
|
|
31
|
+
import { usePlot } from '../hooks/usePlot.svelte.js';
|
|
32
|
+
import { getPlotDefaults } from '../hooks/plotDefaults.js';
|
|
33
|
+
|
|
34
|
+
const DEFAULTS = {
|
|
35
|
+
...getPlotDefaults().hull
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
let markProps: HullMarkProps = $props();
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
data = [] as Datum[],
|
|
42
|
+
class: className = 'hull',
|
|
43
|
+
canvas = false,
|
|
44
|
+
...options
|
|
45
|
+
}: HullMarkProps = $derived({ ...DEFAULTS, ...markProps });
|
|
46
|
+
|
|
47
|
+
const args = $derived(
|
|
48
|
+
recordizeXY({
|
|
49
|
+
data: data as any[],
|
|
50
|
+
...options
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const plot = usePlot();
|
|
55
|
+
|
|
56
|
+
function computeHulls(scaledData: ScaledDataRecord[]) {
|
|
57
|
+
const scaledByDatum = new Map(scaledData.map((d) => [d.datum, d]));
|
|
58
|
+
const hulls: { path: string; datum: ScaledDataRecord }[] = [];
|
|
59
|
+
|
|
60
|
+
groupFacetsAndZ(
|
|
61
|
+
scaledData.map((d) => d.datum),
|
|
62
|
+
args,
|
|
63
|
+
(groupItems) => {
|
|
64
|
+
const groupScaled = groupItems
|
|
65
|
+
.map((d) => scaledByDatum.get(d))
|
|
66
|
+
.filter(
|
|
67
|
+
(d): d is ScaledDataRecord =>
|
|
68
|
+
d !== undefined &&
|
|
69
|
+
d.valid &&
|
|
70
|
+
Number.isFinite(d.x as number) &&
|
|
71
|
+
Number.isFinite(d.y as number)
|
|
72
|
+
);
|
|
73
|
+
if (groupScaled.length < 2) return;
|
|
74
|
+
const delaunay = Delaunay.from(
|
|
75
|
+
groupScaled,
|
|
76
|
+
(d) => d.x as number,
|
|
77
|
+
(d) => d.y as number
|
|
78
|
+
);
|
|
79
|
+
const path = delaunay.renderHull();
|
|
80
|
+
if (path) hulls.push({ path, datum: groupScaled[0] });
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return hulls;
|
|
85
|
+
}
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<Mark
|
|
89
|
+
type={'hull' as MarkType}
|
|
90
|
+
channels={['x', 'y', 'fill', 'opacity', 'stroke', 'fillOpacity', 'strokeOpacity']}
|
|
91
|
+
defaults={{ fill: 'none', stroke: 'currentColor' }}
|
|
92
|
+
{...args}>
|
|
93
|
+
{#snippet children({ scaledData, usedScales })}
|
|
94
|
+
<PathGroup
|
|
95
|
+
paths={computeHulls(scaledData)}
|
|
96
|
+
{args}
|
|
97
|
+
{className}
|
|
98
|
+
{usedScales}
|
|
99
|
+
{plot}
|
|
100
|
+
defaultStrokeWidth={1.5}
|
|
101
|
+
{canvas} />
|
|
102
|
+
{/snippet}
|
|
103
|
+
</Mark>
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { DataRecord, ChannelAccessor } from '../types/index.js';
|
|
2
|
+
declare function $$render<Datum = DataRecord>(): {
|
|
3
|
+
props: Partial<{
|
|
4
|
+
filter: import("../types/index.js").ConstantAccessor<boolean, Datum>;
|
|
5
|
+
facet: "auto" | "include" | "exclude";
|
|
6
|
+
fx: ChannelAccessor<Datum>;
|
|
7
|
+
fy: ChannelAccessor<Datum>;
|
|
8
|
+
dx: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
9
|
+
dy: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
10
|
+
dodgeX: import("../transforms/dodge.js").DodgeXOptions;
|
|
11
|
+
dodgeY: import("../transforms/dodge.js").DodgeYOptions;
|
|
12
|
+
fill: ChannelAccessor<Datum>;
|
|
13
|
+
fillOpacity: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
14
|
+
fontFamily: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
15
|
+
fontSize: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
16
|
+
fontStyle: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
17
|
+
fontVariant: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
18
|
+
fontWeight: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
|
19
|
+
letterSpacing: import("../types/index.js").ConstantAccessor<import("csstype").Property.LetterSpacing<0 | (string & {})>, Datum>;
|
|
20
|
+
wordSpacing: import("../types/index.js").ConstantAccessor<import("csstype").Property.WordSpacing<0 | (string & {})>, Datum>;
|
|
21
|
+
textAnchor: import("../types/index.js").ConstantAccessor<import("csstype").Property.TextAnchor, Datum>;
|
|
22
|
+
textTransform: import("../types/index.js").ConstantAccessor<import("csstype").Property.TextTransform, Datum>;
|
|
23
|
+
textDecoration: import("../types/index.js").ConstantAccessor<import("csstype").Property.TextDecoration<0 | (string & {})>, Datum>;
|
|
24
|
+
sort: ((a: import("../types/data.js").RawValue, b: import("../types/data.js").RawValue) => number) | {
|
|
25
|
+
channel: string;
|
|
26
|
+
order?: "ascending" | "descending";
|
|
27
|
+
} | import("../types/index.js").ConstantAccessor<import("../types/data.js").RawValue, Datum>;
|
|
28
|
+
stroke: ChannelAccessor<Datum>;
|
|
29
|
+
strokeWidth: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
30
|
+
strokeOpacity: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
31
|
+
strokeLinejoin: import("../types/index.js").ConstantAccessor<import("csstype").Property.StrokeLinejoin, Datum>;
|
|
32
|
+
strokeLinecap: import("../types/index.js").ConstantAccessor<import("csstype").Property.StrokeLinecap, Datum>;
|
|
33
|
+
strokeMiterlimit: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
34
|
+
opacity: ChannelAccessor<Datum>;
|
|
35
|
+
strokeDasharray: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
36
|
+
strokeDashoffset: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
37
|
+
blend: import("../types/index.js").ConstantAccessor<import("csstype").Property.MixBlendMode, Datum>;
|
|
38
|
+
mixBlendMode: import("../types/index.js").ConstantAccessor<import("csstype").Property.MixBlendMode, Datum>;
|
|
39
|
+
clipPath: string;
|
|
40
|
+
mask: string;
|
|
41
|
+
imageFilter: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
42
|
+
shapeRendering: import("../types/index.js").ConstantAccessor<import("csstype").Property.ShapeRendering, Datum>;
|
|
43
|
+
paintOrder: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
44
|
+
onclick: (event: Event & {
|
|
45
|
+
currentTarget: SVGPathElement;
|
|
46
|
+
}, datum: Datum, index: number) => void;
|
|
47
|
+
ondblclick: (event: Event & {
|
|
48
|
+
currentTarget: SVGPathElement;
|
|
49
|
+
}, datum: Datum, index: number) => void;
|
|
50
|
+
onmouseup: (event: Event & {
|
|
51
|
+
currentTarget: SVGPathElement;
|
|
52
|
+
}, datum: Datum, index: number) => void;
|
|
53
|
+
onmousedown: (event: Event & {
|
|
54
|
+
currentTarget: SVGPathElement;
|
|
55
|
+
}, datum: Datum, index: number) => void;
|
|
56
|
+
onmouseenter: (event: Event & {
|
|
57
|
+
currentTarget: SVGPathElement;
|
|
58
|
+
}, datum: Datum, index: number) => void;
|
|
59
|
+
onmousemove: (event: Event & {
|
|
60
|
+
currentTarget: SVGPathElement;
|
|
61
|
+
}, datum: Datum, index: number) => void;
|
|
62
|
+
onmouseleave: (event: Event & {
|
|
63
|
+
currentTarget: SVGPathElement;
|
|
64
|
+
}, datum: Datum, index: number) => void;
|
|
65
|
+
onmouseout: (event: Event & {
|
|
66
|
+
currentTarget: SVGPathElement;
|
|
67
|
+
}, datum: Datum, index: number) => void;
|
|
68
|
+
onmouseover: (event: Event & {
|
|
69
|
+
currentTarget: SVGPathElement;
|
|
70
|
+
}, datum: Datum, index: number) => void;
|
|
71
|
+
onpointercancel: (event: Event & {
|
|
72
|
+
currentTarget: SVGPathElement;
|
|
73
|
+
}, datum: Datum, index: number) => void;
|
|
74
|
+
onpointerdown: (event: Event & {
|
|
75
|
+
currentTarget: SVGPathElement;
|
|
76
|
+
}, datum: Datum, index: number) => void;
|
|
77
|
+
onpointerup: (event: Event & {
|
|
78
|
+
currentTarget: SVGPathElement;
|
|
79
|
+
}, datum: Datum, index: number) => void;
|
|
80
|
+
onpointerenter: (event: Event & {
|
|
81
|
+
currentTarget: SVGPathElement;
|
|
82
|
+
}, datum: Datum, index: number) => void;
|
|
83
|
+
onpointerleave: (event: Event & {
|
|
84
|
+
currentTarget: SVGPathElement;
|
|
85
|
+
}, datum: Datum, index: number) => void;
|
|
86
|
+
onpointermove: (event: Event & {
|
|
87
|
+
currentTarget: SVGPathElement;
|
|
88
|
+
}, datum: Datum, index: number) => void;
|
|
89
|
+
onpointerover: (event: Event & {
|
|
90
|
+
currentTarget: SVGPathElement;
|
|
91
|
+
}, datum: Datum, index: number) => void;
|
|
92
|
+
onpointerout: (event: Event & {
|
|
93
|
+
currentTarget: SVGPathElement;
|
|
94
|
+
}, datum: Datum, index: number) => void;
|
|
95
|
+
ondrag: (event: Event & {
|
|
96
|
+
currentTarget: SVGPathElement;
|
|
97
|
+
}, datum: Datum, index: number) => void;
|
|
98
|
+
ondrop: (event: Event & {
|
|
99
|
+
currentTarget: SVGPathElement;
|
|
100
|
+
}, datum: Datum, index: number) => void;
|
|
101
|
+
ondragstart: (event: Event & {
|
|
102
|
+
currentTarget: SVGPathElement;
|
|
103
|
+
}, datum: Datum, index: number) => void;
|
|
104
|
+
ondragenter: (event: Event & {
|
|
105
|
+
currentTarget: SVGPathElement;
|
|
106
|
+
}, datum: Datum, index: number) => void;
|
|
107
|
+
ondragleave: (event: Event & {
|
|
108
|
+
currentTarget: SVGPathElement;
|
|
109
|
+
}, datum: Datum, index: number) => void;
|
|
110
|
+
ondragover: (event: Event & {
|
|
111
|
+
currentTarget: SVGPathElement;
|
|
112
|
+
}, datum: Datum, index: number) => void;
|
|
113
|
+
ondragend: (event: Event & {
|
|
114
|
+
currentTarget: SVGPathElement;
|
|
115
|
+
}, datum: Datum, index: number) => void;
|
|
116
|
+
ontouchstart: (event: Event & {
|
|
117
|
+
currentTarget: SVGPathElement;
|
|
118
|
+
}, datum: Datum, index: number) => void;
|
|
119
|
+
ontouchmove: (event: Event & {
|
|
120
|
+
currentTarget: SVGPathElement;
|
|
121
|
+
}, datum: Datum, index: number) => void;
|
|
122
|
+
ontouchend: (event: Event & {
|
|
123
|
+
currentTarget: SVGPathElement;
|
|
124
|
+
}, datum: Datum, index: number) => void;
|
|
125
|
+
ontouchcancel: (event: Event & {
|
|
126
|
+
currentTarget: SVGPathElement;
|
|
127
|
+
}, datum: Datum, index: number) => void;
|
|
128
|
+
oncontextmenu: (event: Event & {
|
|
129
|
+
currentTarget: SVGPathElement;
|
|
130
|
+
}, datum: Datum, index: number) => void;
|
|
131
|
+
onwheel: (event: Event & {
|
|
132
|
+
currentTarget: SVGPathElement;
|
|
133
|
+
}, datum: Datum, index: number) => void;
|
|
134
|
+
class: string;
|
|
135
|
+
style: string;
|
|
136
|
+
cursor: import("../types/index.js").ConstantAccessor<import("csstype").Property.Cursor, Datum>;
|
|
137
|
+
title: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
138
|
+
}> & {
|
|
139
|
+
/** the input data array */
|
|
140
|
+
data?: Datum[];
|
|
141
|
+
/** the horizontal position channel */
|
|
142
|
+
x?: ChannelAccessor<Datum>;
|
|
143
|
+
/** the vertical position channel */
|
|
144
|
+
y?: ChannelAccessor<Datum>;
|
|
145
|
+
/** the grouping channel; separate hulls per group */
|
|
146
|
+
z?: ChannelAccessor<Datum>;
|
|
147
|
+
/** Render using a canvas element instead of SVG paths. */
|
|
148
|
+
canvas?: boolean;
|
|
149
|
+
};
|
|
150
|
+
exports: {};
|
|
151
|
+
bindings: "";
|
|
152
|
+
slots: {};
|
|
153
|
+
events: {};
|
|
154
|
+
};
|
|
155
|
+
declare class __sveltets_Render<Datum = DataRecord> {
|
|
156
|
+
props(): ReturnType<typeof $$render<Datum>>['props'];
|
|
157
|
+
events(): ReturnType<typeof $$render<Datum>>['events'];
|
|
158
|
+
slots(): ReturnType<typeof $$render<Datum>>['slots'];
|
|
159
|
+
bindings(): "";
|
|
160
|
+
exports(): {};
|
|
161
|
+
}
|
|
162
|
+
interface $$IsomorphicComponent {
|
|
163
|
+
new <Datum = DataRecord>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Datum>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Datum>['props']>, ReturnType<__sveltets_Render<Datum>['events']>, ReturnType<__sveltets_Render<Datum>['slots']>> & {
|
|
164
|
+
$$bindings?: ReturnType<__sveltets_Render<Datum>['bindings']>;
|
|
165
|
+
} & ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
166
|
+
<Datum = DataRecord>(internal: unknown, props: ReturnType<__sveltets_Render<Datum>['props']> & {}): ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
167
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Renders the convex hull of data points. Supports grouping by z/fill/stroke
|
|
171
|
+
* to draw separate hulls per group.
|
|
172
|
+
*/
|
|
173
|
+
declare const Hull: $$IsomorphicComponent;
|
|
174
|
+
type Hull<Datum = DataRecord> = InstanceType<typeof Hull<Datum>>;
|
|
175
|
+
export default Hull;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
Renders individual Voronoi cells, one per data point, allowing per-cell styling.
|
|
3
|
+
-->
|
|
4
|
+
<script lang="ts" generics="Datum = DataRecord">
|
|
5
|
+
interface VoronoiMarkProps extends BaseMarkProps<Datum>, LinkableMarkProps<Datum> {
|
|
6
|
+
/** the input data array */
|
|
7
|
+
data?: Datum[];
|
|
8
|
+
/** the horizontal position channel */
|
|
9
|
+
x?: ChannelAccessor<Datum>;
|
|
10
|
+
/** the vertical position channel */
|
|
11
|
+
y?: ChannelAccessor<Datum>;
|
|
12
|
+
/** the grouping channel; separate Voronoi diagrams per group */
|
|
13
|
+
z?: ChannelAccessor<Datum>;
|
|
14
|
+
/** Render using a canvas element instead of SVG paths. */
|
|
15
|
+
canvas?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
import { Delaunay } from 'd3-delaunay';
|
|
19
|
+
import type {
|
|
20
|
+
DataRecord,
|
|
21
|
+
BaseMarkProps,
|
|
22
|
+
ChannelAccessor,
|
|
23
|
+
LinkableMarkProps,
|
|
24
|
+
MarkType,
|
|
25
|
+
ScaledDataRecord
|
|
26
|
+
} from '../types/index.js';
|
|
27
|
+
import { groupFacetsAndZ } from '../helpers/group.js';
|
|
28
|
+
import { recordizeXY } from '../transforms/recordize.js';
|
|
29
|
+
import { sort } from '../index.js';
|
|
30
|
+
import Mark from '../Mark.svelte';
|
|
31
|
+
import PathItems from './helpers/PathItems.svelte';
|
|
32
|
+
import { usePlot } from '../hooks/usePlot.svelte.js';
|
|
33
|
+
import { getPlotDefaults } from '../hooks/plotDefaults.js';
|
|
34
|
+
|
|
35
|
+
const DEFAULTS = {
|
|
36
|
+
...getPlotDefaults().voronoi
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
let markProps: VoronoiMarkProps = $props();
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
data = [] as Datum[],
|
|
43
|
+
class: className = 'voronoi',
|
|
44
|
+
canvas = false,
|
|
45
|
+
...options
|
|
46
|
+
}: VoronoiMarkProps = $derived({ ...DEFAULTS, ...markProps });
|
|
47
|
+
|
|
48
|
+
const args = $derived(
|
|
49
|
+
sort(
|
|
50
|
+
recordizeXY({
|
|
51
|
+
data: data as any[],
|
|
52
|
+
...options
|
|
53
|
+
})
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const plot = usePlot();
|
|
58
|
+
|
|
59
|
+
function computeVoronoi(scaledData: ScaledDataRecord[]) {
|
|
60
|
+
const x0 = plot.options.marginLeft;
|
|
61
|
+
const y0 = plot.options.marginTop;
|
|
62
|
+
const x1 = x0 + plot.facetWidth;
|
|
63
|
+
const y1 = y0 + plot.facetHeight;
|
|
64
|
+
if (!(x1 > x0) || !(y1 > y0)) return [];
|
|
65
|
+
|
|
66
|
+
const scaledByDatum = new Map(scaledData.map((d) => [d.datum, d]));
|
|
67
|
+
const results: { path: string; datum: ScaledDataRecord }[] = [];
|
|
68
|
+
|
|
69
|
+
groupFacetsAndZ(
|
|
70
|
+
scaledData.map((d) => d.datum),
|
|
71
|
+
args,
|
|
72
|
+
(groupItems) => {
|
|
73
|
+
const groupScaled = groupItems
|
|
74
|
+
.map((d) => scaledByDatum.get(d))
|
|
75
|
+
.filter(
|
|
76
|
+
(d): d is ScaledDataRecord =>
|
|
77
|
+
d !== undefined &&
|
|
78
|
+
d.valid &&
|
|
79
|
+
Number.isFinite(d.x as number) &&
|
|
80
|
+
Number.isFinite(d.y as number)
|
|
81
|
+
);
|
|
82
|
+
if (groupScaled.length < 2) return;
|
|
83
|
+
|
|
84
|
+
const delaunay = Delaunay.from(
|
|
85
|
+
groupScaled,
|
|
86
|
+
(d) => d.x as number,
|
|
87
|
+
(d) => d.y as number
|
|
88
|
+
);
|
|
89
|
+
const voronoi = delaunay.voronoi([x0, y0, x1, y1]);
|
|
90
|
+
|
|
91
|
+
groupScaled.forEach((d, cellIndex) => {
|
|
92
|
+
const path = voronoi.renderCell(cellIndex);
|
|
93
|
+
if (path) results.push({ path, datum: d });
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
false
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return results;
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<Mark
|
|
104
|
+
type={'voronoi' as MarkType}
|
|
105
|
+
channels={['x', 'y', 'fill', 'opacity', 'stroke', 'fillOpacity', 'strokeOpacity']}
|
|
106
|
+
defaults={{ fill: 'none', stroke: 'currentColor' }}
|
|
107
|
+
{...args}>
|
|
108
|
+
{#snippet children({ mark, usedScales, scaledData })}
|
|
109
|
+
<PathItems
|
|
110
|
+
paths={computeVoronoi(scaledData)}
|
|
111
|
+
{args}
|
|
112
|
+
{options}
|
|
113
|
+
{className}
|
|
114
|
+
{usedScales}
|
|
115
|
+
{plot}
|
|
116
|
+
{canvas} />
|
|
117
|
+
{/snippet}
|
|
118
|
+
</Mark>
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { DataRecord, ChannelAccessor, LinkableMarkProps } from '../types/index.js';
|
|
2
|
+
declare function $$render<Datum = DataRecord>(): {
|
|
3
|
+
props: Partial<{
|
|
4
|
+
filter: import("../types/index.js").ConstantAccessor<boolean, Datum>;
|
|
5
|
+
facet: "auto" | "include" | "exclude";
|
|
6
|
+
fx: ChannelAccessor<Datum>;
|
|
7
|
+
fy: ChannelAccessor<Datum>;
|
|
8
|
+
dx: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
9
|
+
dy: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
10
|
+
dodgeX: import("../transforms/dodge.js").DodgeXOptions;
|
|
11
|
+
dodgeY: import("../transforms/dodge.js").DodgeYOptions;
|
|
12
|
+
fill: ChannelAccessor<Datum>;
|
|
13
|
+
fillOpacity: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
14
|
+
fontFamily: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontFamily, Datum>;
|
|
15
|
+
fontSize: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontSize<number>, Datum>;
|
|
16
|
+
fontStyle: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontStyle, Datum>;
|
|
17
|
+
fontVariant: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontVariant, Datum>;
|
|
18
|
+
fontWeight: import("../types/index.js").ConstantAccessor<import("csstype").Property.FontWeight, Datum>;
|
|
19
|
+
letterSpacing: import("../types/index.js").ConstantAccessor<import("csstype").Property.LetterSpacing<0 | (string & {})>, Datum>;
|
|
20
|
+
wordSpacing: import("../types/index.js").ConstantAccessor<import("csstype").Property.WordSpacing<0 | (string & {})>, Datum>;
|
|
21
|
+
textAnchor: import("../types/index.js").ConstantAccessor<import("csstype").Property.TextAnchor, Datum>;
|
|
22
|
+
textTransform: import("../types/index.js").ConstantAccessor<import("csstype").Property.TextTransform, Datum>;
|
|
23
|
+
textDecoration: import("../types/index.js").ConstantAccessor<import("csstype").Property.TextDecoration<0 | (string & {})>, Datum>;
|
|
24
|
+
sort: ((a: import("../types/data.js").RawValue, b: import("../types/data.js").RawValue) => number) | {
|
|
25
|
+
channel: string;
|
|
26
|
+
order?: "ascending" | "descending";
|
|
27
|
+
} | import("../types/index.js").ConstantAccessor<import("../types/data.js").RawValue, Datum>;
|
|
28
|
+
stroke: ChannelAccessor<Datum>;
|
|
29
|
+
strokeWidth: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
30
|
+
strokeOpacity: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
31
|
+
strokeLinejoin: import("../types/index.js").ConstantAccessor<import("csstype").Property.StrokeLinejoin, Datum>;
|
|
32
|
+
strokeLinecap: import("../types/index.js").ConstantAccessor<import("csstype").Property.StrokeLinecap, Datum>;
|
|
33
|
+
strokeMiterlimit: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
34
|
+
opacity: ChannelAccessor<Datum>;
|
|
35
|
+
strokeDasharray: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
36
|
+
strokeDashoffset: import("../types/index.js").ConstantAccessor<number, Datum>;
|
|
37
|
+
blend: import("../types/index.js").ConstantAccessor<import("csstype").Property.MixBlendMode, Datum>;
|
|
38
|
+
mixBlendMode: import("../types/index.js").ConstantAccessor<import("csstype").Property.MixBlendMode, Datum>;
|
|
39
|
+
clipPath: string;
|
|
40
|
+
mask: string;
|
|
41
|
+
imageFilter: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
42
|
+
shapeRendering: import("../types/index.js").ConstantAccessor<import("csstype").Property.ShapeRendering, Datum>;
|
|
43
|
+
paintOrder: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
44
|
+
onclick: (event: Event & {
|
|
45
|
+
currentTarget: SVGPathElement;
|
|
46
|
+
}, datum: Datum, index: number) => void;
|
|
47
|
+
ondblclick: (event: Event & {
|
|
48
|
+
currentTarget: SVGPathElement;
|
|
49
|
+
}, datum: Datum, index: number) => void;
|
|
50
|
+
onmouseup: (event: Event & {
|
|
51
|
+
currentTarget: SVGPathElement;
|
|
52
|
+
}, datum: Datum, index: number) => void;
|
|
53
|
+
onmousedown: (event: Event & {
|
|
54
|
+
currentTarget: SVGPathElement;
|
|
55
|
+
}, datum: Datum, index: number) => void;
|
|
56
|
+
onmouseenter: (event: Event & {
|
|
57
|
+
currentTarget: SVGPathElement;
|
|
58
|
+
}, datum: Datum, index: number) => void;
|
|
59
|
+
onmousemove: (event: Event & {
|
|
60
|
+
currentTarget: SVGPathElement;
|
|
61
|
+
}, datum: Datum, index: number) => void;
|
|
62
|
+
onmouseleave: (event: Event & {
|
|
63
|
+
currentTarget: SVGPathElement;
|
|
64
|
+
}, datum: Datum, index: number) => void;
|
|
65
|
+
onmouseout: (event: Event & {
|
|
66
|
+
currentTarget: SVGPathElement;
|
|
67
|
+
}, datum: Datum, index: number) => void;
|
|
68
|
+
onmouseover: (event: Event & {
|
|
69
|
+
currentTarget: SVGPathElement;
|
|
70
|
+
}, datum: Datum, index: number) => void;
|
|
71
|
+
onpointercancel: (event: Event & {
|
|
72
|
+
currentTarget: SVGPathElement;
|
|
73
|
+
}, datum: Datum, index: number) => void;
|
|
74
|
+
onpointerdown: (event: Event & {
|
|
75
|
+
currentTarget: SVGPathElement;
|
|
76
|
+
}, datum: Datum, index: number) => void;
|
|
77
|
+
onpointerup: (event: Event & {
|
|
78
|
+
currentTarget: SVGPathElement;
|
|
79
|
+
}, datum: Datum, index: number) => void;
|
|
80
|
+
onpointerenter: (event: Event & {
|
|
81
|
+
currentTarget: SVGPathElement;
|
|
82
|
+
}, datum: Datum, index: number) => void;
|
|
83
|
+
onpointerleave: (event: Event & {
|
|
84
|
+
currentTarget: SVGPathElement;
|
|
85
|
+
}, datum: Datum, index: number) => void;
|
|
86
|
+
onpointermove: (event: Event & {
|
|
87
|
+
currentTarget: SVGPathElement;
|
|
88
|
+
}, datum: Datum, index: number) => void;
|
|
89
|
+
onpointerover: (event: Event & {
|
|
90
|
+
currentTarget: SVGPathElement;
|
|
91
|
+
}, datum: Datum, index: number) => void;
|
|
92
|
+
onpointerout: (event: Event & {
|
|
93
|
+
currentTarget: SVGPathElement;
|
|
94
|
+
}, datum: Datum, index: number) => void;
|
|
95
|
+
ondrag: (event: Event & {
|
|
96
|
+
currentTarget: SVGPathElement;
|
|
97
|
+
}, datum: Datum, index: number) => void;
|
|
98
|
+
ondrop: (event: Event & {
|
|
99
|
+
currentTarget: SVGPathElement;
|
|
100
|
+
}, datum: Datum, index: number) => void;
|
|
101
|
+
ondragstart: (event: Event & {
|
|
102
|
+
currentTarget: SVGPathElement;
|
|
103
|
+
}, datum: Datum, index: number) => void;
|
|
104
|
+
ondragenter: (event: Event & {
|
|
105
|
+
currentTarget: SVGPathElement;
|
|
106
|
+
}, datum: Datum, index: number) => void;
|
|
107
|
+
ondragleave: (event: Event & {
|
|
108
|
+
currentTarget: SVGPathElement;
|
|
109
|
+
}, datum: Datum, index: number) => void;
|
|
110
|
+
ondragover: (event: Event & {
|
|
111
|
+
currentTarget: SVGPathElement;
|
|
112
|
+
}, datum: Datum, index: number) => void;
|
|
113
|
+
ondragend: (event: Event & {
|
|
114
|
+
currentTarget: SVGPathElement;
|
|
115
|
+
}, datum: Datum, index: number) => void;
|
|
116
|
+
ontouchstart: (event: Event & {
|
|
117
|
+
currentTarget: SVGPathElement;
|
|
118
|
+
}, datum: Datum, index: number) => void;
|
|
119
|
+
ontouchmove: (event: Event & {
|
|
120
|
+
currentTarget: SVGPathElement;
|
|
121
|
+
}, datum: Datum, index: number) => void;
|
|
122
|
+
ontouchend: (event: Event & {
|
|
123
|
+
currentTarget: SVGPathElement;
|
|
124
|
+
}, datum: Datum, index: number) => void;
|
|
125
|
+
ontouchcancel: (event: Event & {
|
|
126
|
+
currentTarget: SVGPathElement;
|
|
127
|
+
}, datum: Datum, index: number) => void;
|
|
128
|
+
oncontextmenu: (event: Event & {
|
|
129
|
+
currentTarget: SVGPathElement;
|
|
130
|
+
}, datum: Datum, index: number) => void;
|
|
131
|
+
onwheel: (event: Event & {
|
|
132
|
+
currentTarget: SVGPathElement;
|
|
133
|
+
}, datum: Datum, index: number) => void;
|
|
134
|
+
class: string;
|
|
135
|
+
style: string;
|
|
136
|
+
cursor: import("../types/index.js").ConstantAccessor<import("csstype").Property.Cursor, Datum>;
|
|
137
|
+
title: import("../types/index.js").ConstantAccessor<string, Datum>;
|
|
138
|
+
}> & LinkableMarkProps<Datum> & {
|
|
139
|
+
/** the input data array */
|
|
140
|
+
data?: Datum[];
|
|
141
|
+
/** the horizontal position channel */
|
|
142
|
+
x?: ChannelAccessor<Datum>;
|
|
143
|
+
/** the vertical position channel */
|
|
144
|
+
y?: ChannelAccessor<Datum>;
|
|
145
|
+
/** the grouping channel; separate Voronoi diagrams per group */
|
|
146
|
+
z?: ChannelAccessor<Datum>;
|
|
147
|
+
/** Render using a canvas element instead of SVG paths. */
|
|
148
|
+
canvas?: boolean;
|
|
149
|
+
};
|
|
150
|
+
exports: {};
|
|
151
|
+
bindings: "";
|
|
152
|
+
slots: {};
|
|
153
|
+
events: {};
|
|
154
|
+
};
|
|
155
|
+
declare class __sveltets_Render<Datum = DataRecord> {
|
|
156
|
+
props(): ReturnType<typeof $$render<Datum>>['props'];
|
|
157
|
+
events(): ReturnType<typeof $$render<Datum>>['events'];
|
|
158
|
+
slots(): ReturnType<typeof $$render<Datum>>['slots'];
|
|
159
|
+
bindings(): "";
|
|
160
|
+
exports(): {};
|
|
161
|
+
}
|
|
162
|
+
interface $$IsomorphicComponent {
|
|
163
|
+
new <Datum = DataRecord>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Datum>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Datum>['props']>, ReturnType<__sveltets_Render<Datum>['events']>, ReturnType<__sveltets_Render<Datum>['slots']>> & {
|
|
164
|
+
$$bindings?: ReturnType<__sveltets_Render<Datum>['bindings']>;
|
|
165
|
+
} & ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
166
|
+
<Datum = DataRecord>(internal: unknown, props: ReturnType<__sveltets_Render<Datum>['props']> & {}): ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
167
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
168
|
+
}
|
|
169
|
+
/** Renders individual Voronoi cells, one per data point, allowing per-cell styling. */
|
|
170
|
+
declare const Voronoi: $$IsomorphicComponent;
|
|
171
|
+
type Voronoi<Datum = DataRecord> = InstanceType<typeof Voronoi<Datum>>;
|
|
172
|
+
export default Voronoi;
|