svelteplot 0.12.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/core/Plot.svelte +3 -6
- package/dist/helpers/group.d.ts +1 -1
- package/dist/helpers/group.js +3 -3
- package/dist/helpers/scales.js +8 -0
- package/dist/helpers/vectorShapes.d.ts +13 -0
- package/dist/helpers/vectorShapes.js +57 -0
- package/dist/marks/Arrow.svelte +70 -59
- package/dist/marks/Arrow.svelte.d.ts +2 -0
- package/dist/marks/ColorLegend.svelte +7 -3
- package/dist/marks/Contour.svelte +684 -0
- package/dist/marks/Contour.svelte.d.ts +152 -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/Image.svelte +37 -27
- package/dist/marks/Image.svelte.d.ts +2 -0
- package/dist/marks/Link.svelte +68 -50
- package/dist/marks/Link.svelte.d.ts +2 -0
- package/dist/marks/Raster.svelte +6 -1
- package/dist/marks/Vector.svelte +12 -81
- package/dist/marks/Vector.svelte.d.ts +2 -4
- 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/ArrowCanvas.svelte +132 -0
- package/dist/marks/helpers/ArrowCanvas.svelte.d.ts +39 -0
- package/dist/marks/helpers/BaseAxisX.svelte +5 -7
- 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/ImageCanvas.svelte +126 -0
- package/dist/marks/helpers/ImageCanvas.svelte.d.ts +34 -0
- package/dist/marks/helpers/LinkCanvas.svelte +103 -0
- package/dist/marks/helpers/LinkCanvas.svelte.d.ts +32 -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/helpers/VectorCanvas.svelte +127 -0
- package/dist/marks/helpers/VectorCanvas.svelte.d.ts +36 -0
- package/dist/marks/index.d.ts +7 -0
- package/dist/marks/index.js +7 -0
- package/dist/types/mark.d.ts +1 -1
- package/dist/types/plot.d.ts +33 -1
- package/package.json +185 -181
|
@@ -0,0 +1,172 @@
|
|
|
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 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 the full Voronoi diagram as a single SVG path. */
|
|
170
|
+
declare const VoronoiMesh: $$IsomorphicComponent;
|
|
171
|
+
type VoronoiMesh<Datum = DataRecord> = InstanceType<typeof VoronoiMesh<Datum>>;
|
|
172
|
+
export default VoronoiMesh;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
Helper component for rendering Arrow marks in canvas
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts" generics="Datum extends DataRecord">
|
|
6
|
+
interface ArrowCanvasProps {
|
|
7
|
+
data: ScaledDataRecord<Datum>[];
|
|
8
|
+
options: BaseMarkProps<Datum> & {
|
|
9
|
+
headAngle?: ConstantAccessor<number, Datum>;
|
|
10
|
+
headLength?: ConstantAccessor<number, Datum>;
|
|
11
|
+
bend?: ConstantAccessor<number, Datum> | true;
|
|
12
|
+
inset?: ConstantAccessor<number, Datum>;
|
|
13
|
+
insetStart?: ConstantAccessor<number, Datum>;
|
|
14
|
+
insetEnd?: ConstantAccessor<number, Datum>;
|
|
15
|
+
sweep?: SweepOption;
|
|
16
|
+
};
|
|
17
|
+
usedScales: UsedScales;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
import type {
|
|
21
|
+
BaseMarkProps,
|
|
22
|
+
ConstantAccessor,
|
|
23
|
+
DataRecord,
|
|
24
|
+
ScaledDataRecord,
|
|
25
|
+
UsedScales
|
|
26
|
+
} from '../../types/index.js';
|
|
27
|
+
import { resolveProp, resolveScaledStyleProps } from '../../helpers/resolve.js';
|
|
28
|
+
import { coalesce, maybeNumber } from '../../helpers/index.js';
|
|
29
|
+
import {
|
|
30
|
+
arrowPath,
|
|
31
|
+
maybeSweep,
|
|
32
|
+
type SweepFunc,
|
|
33
|
+
type SweepOption
|
|
34
|
+
} from '../../helpers/arrowPath.js';
|
|
35
|
+
import type { Attachment } from 'svelte/attachments';
|
|
36
|
+
import { devicePixelRatio } from 'svelte/reactivity/window';
|
|
37
|
+
import CanvasLayer from './CanvasLayer.svelte';
|
|
38
|
+
import { resolveColor } from './canvas.js';
|
|
39
|
+
import { usePlot } from '../../hooks/usePlot.svelte.js';
|
|
40
|
+
|
|
41
|
+
const plot = usePlot();
|
|
42
|
+
|
|
43
|
+
let { data, options, usedScales }: ArrowCanvasProps = $props();
|
|
44
|
+
|
|
45
|
+
const render: Attachment = (canvasEl: Element) => {
|
|
46
|
+
const canvas = canvasEl as HTMLCanvasElement;
|
|
47
|
+
const context = canvas.getContext('2d');
|
|
48
|
+
|
|
49
|
+
$effect(() => {
|
|
50
|
+
if (context) {
|
|
51
|
+
context.resetTransform();
|
|
52
|
+
context.scale(devicePixelRatio.current ?? 1, devicePixelRatio.current ?? 1);
|
|
53
|
+
|
|
54
|
+
const sweep = maybeSweep(options.sweep) as SweepFunc;
|
|
55
|
+
|
|
56
|
+
for (const d of data) {
|
|
57
|
+
if (!d.valid) continue;
|
|
58
|
+
|
|
59
|
+
const datum = d.datum as unknown as Datum;
|
|
60
|
+
|
|
61
|
+
const styleProps = resolveScaledStyleProps(
|
|
62
|
+
d.datum,
|
|
63
|
+
options,
|
|
64
|
+
usedScales,
|
|
65
|
+
plot,
|
|
66
|
+
'stroke'
|
|
67
|
+
) as Record<string, unknown>;
|
|
68
|
+
|
|
69
|
+
const opacity = +(styleProps['opacity'] ?? 1);
|
|
70
|
+
const strokeOpacity = +(styleProps['stroke-opacity'] ?? 1);
|
|
71
|
+
const stroke = resolveColor(
|
|
72
|
+
String(styleProps.stroke || 'currentColor'),
|
|
73
|
+
canvas
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (!stroke || stroke === 'none') continue;
|
|
77
|
+
|
|
78
|
+
const strokeWidth = (resolveProp(options.strokeWidth, datum, 1) ?? 1) as number;
|
|
79
|
+
const inset = resolveProp(options.inset, datum, 0);
|
|
80
|
+
const insetStart = resolveProp(options.insetStart, datum);
|
|
81
|
+
const insetEnd = resolveProp(options.insetEnd, datum);
|
|
82
|
+
const headAngle = (resolveProp(options.headAngle, datum, 60) ?? 60) as number;
|
|
83
|
+
const headLength = (resolveProp(options.headLength, datum, 8) ?? 8) as number;
|
|
84
|
+
const bendVal =
|
|
85
|
+
options.bend === true
|
|
86
|
+
? 22.5
|
|
87
|
+
: ((resolveProp(
|
|
88
|
+
options.bend as ConstantAccessor<number, Datum>,
|
|
89
|
+
datum,
|
|
90
|
+
0
|
|
91
|
+
) ?? 0) as number);
|
|
92
|
+
|
|
93
|
+
const pathStr = arrowPath(
|
|
94
|
+
d.x1 ?? 0,
|
|
95
|
+
d.y1 ?? 0,
|
|
96
|
+
d.x2 ?? 0,
|
|
97
|
+
d.y2 ?? 0,
|
|
98
|
+
maybeNumber(coalesce(insetStart, inset)) ?? 0,
|
|
99
|
+
maybeNumber(coalesce(insetEnd, inset)) ?? 0,
|
|
100
|
+
headAngle,
|
|
101
|
+
headLength,
|
|
102
|
+
bendVal,
|
|
103
|
+
strokeWidth,
|
|
104
|
+
sweep
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (!pathStr) continue;
|
|
108
|
+
|
|
109
|
+
const path = new Path2D(pathStr);
|
|
110
|
+
|
|
111
|
+
context.lineWidth = strokeWidth;
|
|
112
|
+
context.lineCap = 'round';
|
|
113
|
+
context.lineJoin = 'round';
|
|
114
|
+
context.strokeStyle = stroke;
|
|
115
|
+
context.globalAlpha = opacity * strokeOpacity;
|
|
116
|
+
context.stroke(path);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return () => {
|
|
121
|
+
context?.clearRect(
|
|
122
|
+
0,
|
|
123
|
+
0,
|
|
124
|
+
plot.width * (devicePixelRatio.current ?? 1),
|
|
125
|
+
plot.height * (devicePixelRatio.current ?? 1)
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<CanvasLayer {@attach render} />
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BaseMarkProps, ConstantAccessor, DataRecord, ScaledDataRecord, UsedScales } from '../../types/index.js';
|
|
2
|
+
import { type SweepOption } from '../../helpers/arrowPath.js';
|
|
3
|
+
declare function $$render<Datum extends DataRecord>(): {
|
|
4
|
+
props: {
|
|
5
|
+
data: ScaledDataRecord<Datum>[];
|
|
6
|
+
options: BaseMarkProps<Datum> & {
|
|
7
|
+
headAngle?: ConstantAccessor<number, Datum>;
|
|
8
|
+
headLength?: ConstantAccessor<number, Datum>;
|
|
9
|
+
bend?: ConstantAccessor<number, Datum> | true;
|
|
10
|
+
inset?: ConstantAccessor<number, Datum>;
|
|
11
|
+
insetStart?: ConstantAccessor<number, Datum>;
|
|
12
|
+
insetEnd?: ConstantAccessor<number, Datum>;
|
|
13
|
+
sweep?: SweepOption;
|
|
14
|
+
};
|
|
15
|
+
usedScales: UsedScales;
|
|
16
|
+
};
|
|
17
|
+
exports: {};
|
|
18
|
+
bindings: "";
|
|
19
|
+
slots: {};
|
|
20
|
+
events: {};
|
|
21
|
+
};
|
|
22
|
+
declare class __sveltets_Render<Datum extends DataRecord> {
|
|
23
|
+
props(): ReturnType<typeof $$render<Datum>>['props'];
|
|
24
|
+
events(): ReturnType<typeof $$render<Datum>>['events'];
|
|
25
|
+
slots(): ReturnType<typeof $$render<Datum>>['slots'];
|
|
26
|
+
bindings(): "";
|
|
27
|
+
exports(): {};
|
|
28
|
+
}
|
|
29
|
+
interface $$IsomorphicComponent {
|
|
30
|
+
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']>> & {
|
|
31
|
+
$$bindings?: ReturnType<__sveltets_Render<Datum>['bindings']>;
|
|
32
|
+
} & ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
33
|
+
<Datum extends DataRecord>(internal: unknown, props: ReturnType<__sveltets_Render<Datum>['props']> & {}): ReturnType<__sveltets_Render<Datum>['exports']>;
|
|
34
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
35
|
+
}
|
|
36
|
+
/** Helper component for rendering Arrow marks in canvas */
|
|
37
|
+
declare const ArrowCanvas: $$IsomorphicComponent;
|
|
38
|
+
type ArrowCanvas<Datum extends DataRecord> = InstanceType<typeof ArrowCanvas<Datum>>;
|
|
39
|
+
export default ArrowCanvas;
|
|
@@ -206,6 +206,8 @@
|
|
|
206
206
|
{@const moveDown =
|
|
207
207
|
(tickSize + tickPadding + (tickRotate !== 0 ? tickFontSize_ * 0.35 : 0)) *
|
|
208
208
|
(anchor === 'bottom' ? 1 : -1)}
|
|
209
|
+
{@const tickBaseline =
|
|
210
|
+
tickRotate !== 0 ? 'central' : anchor === 'bottom' ? 'hanging' : 'auto'}
|
|
209
211
|
{@const [textStyle, textClass] = resolveStyles(
|
|
210
212
|
plot,
|
|
211
213
|
toScaledDatum(tick),
|
|
@@ -230,22 +232,18 @@
|
|
|
230
232
|
)}
|
|
231
233
|
<text
|
|
232
234
|
bind:this={tickTextElements[t]}
|
|
233
|
-
transform="translate(0, {moveDown})
|
|
235
|
+
transform="translate(0, {moveDown}) rotate({tickRotate})"
|
|
234
236
|
style={textStyle}
|
|
235
237
|
class={textClass}
|
|
236
238
|
x={0}
|
|
237
239
|
y={0}
|
|
238
|
-
dominant-baseline={
|
|
239
|
-
? 'central'
|
|
240
|
-
: anchor === 'bottom'
|
|
241
|
-
? 'hanging'
|
|
242
|
-
: 'auto'}>
|
|
240
|
+
dominant-baseline={tickBaseline}>
|
|
243
241
|
{#if ticks.length > 0 || t === 0 || t === ticks.length - 1}
|
|
244
242
|
{#if textLines.length === 1}
|
|
245
243
|
{textLines[0]}
|
|
246
244
|
{:else}
|
|
247
245
|
{#each textLines as line, i (i)}
|
|
248
|
-
<tspan x="0" dy={i ? 12 : 0}
|
|
246
|
+
<tspan x="0" dy={i ? 12 : 0} dominant-baseline={tickBaseline}
|
|
249
247
|
>{!prevTextLines ||
|
|
250
248
|
prevTextLines[i] !== line ||
|
|
251
249
|
options.removeDuplicateTicks === false
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ScaledDataRecord } from '../../types/index.js';
|
|
3
|
+
import type { GeoPath } from 'd3-geo';
|
|
4
|
+
import type { Attachment } from 'svelte/attachments';
|
|
5
|
+
import { devicePixelRatio } from 'svelte/reactivity/window';
|
|
6
|
+
import { CSS_VAR } from '../../constants.js';
|
|
7
|
+
import CanvasLayer from './CanvasLayer.svelte';
|
|
8
|
+
import { usePlot } from '../../hooks/usePlot.svelte.js';
|
|
9
|
+
import { RAW_VALUE } from '../../transforms/recordize.js';
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
scaledData,
|
|
13
|
+
path,
|
|
14
|
+
geomKey,
|
|
15
|
+
fill,
|
|
16
|
+
stroke,
|
|
17
|
+
strokeWidth,
|
|
18
|
+
strokeOpacity,
|
|
19
|
+
fillOpacity,
|
|
20
|
+
opacity,
|
|
21
|
+
strokeMiterlimit
|
|
22
|
+
}: {
|
|
23
|
+
scaledData: ScaledDataRecord[];
|
|
24
|
+
path: GeoPath;
|
|
25
|
+
/** Symbol key used to retrieve the DensityGeometry from each datum. */
|
|
26
|
+
geomKey: symbol;
|
|
27
|
+
fill: string;
|
|
28
|
+
stroke: string;
|
|
29
|
+
strokeWidth?: number;
|
|
30
|
+
strokeOpacity?: number;
|
|
31
|
+
fillOpacity?: number;
|
|
32
|
+
opacity?: number;
|
|
33
|
+
strokeMiterlimit?: number;
|
|
34
|
+
} = $props();
|
|
35
|
+
|
|
36
|
+
const plot = usePlot();
|
|
37
|
+
|
|
38
|
+
/** Resolve a fill/stroke string that may be the "density" keyword. */
|
|
39
|
+
function resolveColorProp(prop: string, densityValue: number): string {
|
|
40
|
+
if (/^density$/i.test(prop)) {
|
|
41
|
+
return (plot.scales.color?.fn(densityValue) as string) ?? 'currentColor';
|
|
42
|
+
}
|
|
43
|
+
return prop;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const render: Attachment = (canvasEl: Element) => {
|
|
47
|
+
const canvas = canvasEl as HTMLCanvasElement;
|
|
48
|
+
const context = canvas.getContext('2d');
|
|
49
|
+
|
|
50
|
+
$effect(() => {
|
|
51
|
+
if (!context) return;
|
|
52
|
+
|
|
53
|
+
path.context(context);
|
|
54
|
+
context.resetTransform();
|
|
55
|
+
context.scale(devicePixelRatio.current ?? 1, devicePixelRatio.current ?? 1);
|
|
56
|
+
|
|
57
|
+
let currentColor: string | undefined;
|
|
58
|
+
|
|
59
|
+
const resolveCanvasColor = (color: string): string => {
|
|
60
|
+
if (color.toLowerCase() === 'currentcolor') {
|
|
61
|
+
return (
|
|
62
|
+
currentColor ||
|
|
63
|
+
(currentColor = getComputedStyle(
|
|
64
|
+
canvas.parentElement?.parentElement ?? canvas
|
|
65
|
+
).getPropertyValue('color'))
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (CSS_VAR.test(color)) {
|
|
69
|
+
return getComputedStyle(canvas).getPropertyValue(color.slice(4, -1));
|
|
70
|
+
}
|
|
71
|
+
return color;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const globalOpacity = opacity ?? 1;
|
|
75
|
+
if (strokeMiterlimit != null) context.miterLimit = strokeMiterlimit;
|
|
76
|
+
|
|
77
|
+
for (const d of scaledData) {
|
|
78
|
+
const geom = d.datum[geomKey as any] as any;
|
|
79
|
+
if (!geom?.coordinates?.length) continue;
|
|
80
|
+
|
|
81
|
+
const densityValue = (d.datum[RAW_VALUE as any] as number) ?? 0;
|
|
82
|
+
const fillColor = resolveCanvasColor(resolveColorProp(fill, densityValue));
|
|
83
|
+
const strokeColor = resolveCanvasColor(resolveColorProp(stroke, densityValue));
|
|
84
|
+
|
|
85
|
+
context.beginPath();
|
|
86
|
+
path(geom);
|
|
87
|
+
context.closePath();
|
|
88
|
+
|
|
89
|
+
if (fillColor && fillColor !== 'none') {
|
|
90
|
+
context.fillStyle = fillColor;
|
|
91
|
+
context.globalAlpha = globalOpacity * (fillOpacity ?? 1);
|
|
92
|
+
context.fill();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (strokeColor && strokeColor !== 'none') {
|
|
96
|
+
context.strokeStyle = strokeColor;
|
|
97
|
+
context.lineWidth = strokeWidth ?? 1;
|
|
98
|
+
context.globalAlpha = globalOpacity * (strokeOpacity ?? 1);
|
|
99
|
+
context.stroke();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Reset path context in case we switch back to SVG rendering.
|
|
104
|
+
path.context(null);
|
|
105
|
+
|
|
106
|
+
return () => {
|
|
107
|
+
context.clearRect(
|
|
108
|
+
0,
|
|
109
|
+
0,
|
|
110
|
+
plot.width * (devicePixelRatio.current ?? 1),
|
|
111
|
+
plot.height * (devicePixelRatio.current ?? 1)
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<CanvasLayer {@attach render} />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ScaledDataRecord } from '../../types/index.js';
|
|
2
|
+
import type { GeoPath } from 'd3-geo';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
scaledData: ScaledDataRecord[];
|
|
5
|
+
path: GeoPath;
|
|
6
|
+
/** Symbol key used to retrieve the DensityGeometry from each datum. */
|
|
7
|
+
geomKey: symbol;
|
|
8
|
+
fill: string;
|
|
9
|
+
stroke: string;
|
|
10
|
+
strokeWidth?: number;
|
|
11
|
+
strokeOpacity?: number;
|
|
12
|
+
fillOpacity?: number;
|
|
13
|
+
opacity?: number;
|
|
14
|
+
strokeMiterlimit?: number;
|
|
15
|
+
};
|
|
16
|
+
declare const DensityCanvas: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type DensityCanvas = ReturnType<typeof DensityCanvas>;
|
|
18
|
+
export default DensityCanvas;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ScaledDataRecord } from '../../types/index.js';
|
|
3
|
+
import type { GeoPath } from 'd3-geo';
|
|
4
|
+
import type { Attachment } from 'svelte/attachments';
|
|
5
|
+
import { devicePixelRatio } from 'svelte/reactivity/window';
|
|
6
|
+
import { CSS_VAR } from '../../constants.js';
|
|
7
|
+
import CanvasLayer from './CanvasLayer.svelte';
|
|
8
|
+
import { usePlot } from '../../hooks/usePlot.svelte.js';
|
|
9
|
+
import { RAW_VALUE } from '../../transforms/recordize.js';
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
scaledData,
|
|
13
|
+
path,
|
|
14
|
+
geomKey,
|
|
15
|
+
colorKeyword,
|
|
16
|
+
fill,
|
|
17
|
+
stroke,
|
|
18
|
+
strokeWidth,
|
|
19
|
+
strokeOpacity,
|
|
20
|
+
fillOpacity,
|
|
21
|
+
opacity,
|
|
22
|
+
strokeMiterlimit
|
|
23
|
+
}: {
|
|
24
|
+
scaledData: ScaledDataRecord[];
|
|
25
|
+
path: GeoPath;
|
|
26
|
+
/** Symbol key used to retrieve the GeoJSON geometry from each datum. */
|
|
27
|
+
geomKey: symbol;
|
|
28
|
+
/**
|
|
29
|
+
* The color keyword that, when used as fill/stroke, maps the threshold
|
|
30
|
+
* value through the plot's color scale. E.g. "value" for Contour,
|
|
31
|
+
* "density" for Density.
|
|
32
|
+
*/
|
|
33
|
+
colorKeyword: string;
|
|
34
|
+
fill: string;
|
|
35
|
+
stroke: string;
|
|
36
|
+
strokeWidth?: number;
|
|
37
|
+
strokeOpacity?: number;
|
|
38
|
+
fillOpacity?: number;
|
|
39
|
+
opacity?: number;
|
|
40
|
+
strokeMiterlimit?: number;
|
|
41
|
+
} = $props();
|
|
42
|
+
|
|
43
|
+
const plot = usePlot();
|
|
44
|
+
|
|
45
|
+
/** Resolve a fill/stroke string that may be the colorKeyword. */
|
|
46
|
+
function resolveColorProp(prop: string, value: number): string {
|
|
47
|
+
if (prop.toLowerCase() === colorKeyword.toLowerCase()) {
|
|
48
|
+
return (plot.scales.color?.fn(value) as string) ?? 'currentColor';
|
|
49
|
+
}
|
|
50
|
+
return prop;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const render: Attachment = (canvasEl: Element) => {
|
|
54
|
+
const canvas = canvasEl as HTMLCanvasElement;
|
|
55
|
+
const context = canvas.getContext('2d');
|
|
56
|
+
|
|
57
|
+
$effect(() => {
|
|
58
|
+
if (!context) return;
|
|
59
|
+
|
|
60
|
+
path.context(context);
|
|
61
|
+
context.resetTransform();
|
|
62
|
+
context.scale(devicePixelRatio.current ?? 1, devicePixelRatio.current ?? 1);
|
|
63
|
+
|
|
64
|
+
let currentColor: string | undefined;
|
|
65
|
+
|
|
66
|
+
const resolveCanvasColor = (color: string): string => {
|
|
67
|
+
if (color.toLowerCase() === 'currentcolor') {
|
|
68
|
+
return (
|
|
69
|
+
currentColor ||
|
|
70
|
+
(currentColor = getComputedStyle(
|
|
71
|
+
canvas.parentElement?.parentElement ?? canvas
|
|
72
|
+
).getPropertyValue('color'))
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (CSS_VAR.test(color)) {
|
|
76
|
+
return getComputedStyle(canvas).getPropertyValue(color.slice(4, -1));
|
|
77
|
+
}
|
|
78
|
+
return color;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const globalOpacity = opacity ?? 1;
|
|
82
|
+
if (strokeMiterlimit != null) context.miterLimit = strokeMiterlimit;
|
|
83
|
+
|
|
84
|
+
for (const d of scaledData) {
|
|
85
|
+
const geom = d.datum[geomKey as any] as any;
|
|
86
|
+
if (!geom?.coordinates?.length) continue;
|
|
87
|
+
|
|
88
|
+
const thresholdValue = (d.datum[RAW_VALUE as any] as number) ?? 0;
|
|
89
|
+
const fillColor = resolveCanvasColor(resolveColorProp(fill, thresholdValue));
|
|
90
|
+
const strokeColor = resolveCanvasColor(resolveColorProp(stroke, thresholdValue));
|
|
91
|
+
|
|
92
|
+
context.beginPath();
|
|
93
|
+
path(geom);
|
|
94
|
+
context.closePath();
|
|
95
|
+
|
|
96
|
+
if (fillColor && fillColor !== 'none') {
|
|
97
|
+
context.fillStyle = fillColor;
|
|
98
|
+
context.globalAlpha = globalOpacity * (fillOpacity ?? 1);
|
|
99
|
+
context.fill();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (strokeColor && strokeColor !== 'none') {
|
|
103
|
+
context.strokeStyle = strokeColor;
|
|
104
|
+
context.lineWidth = strokeWidth ?? 1;
|
|
105
|
+
context.globalAlpha = globalOpacity * (strokeOpacity ?? 1);
|
|
106
|
+
context.stroke();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Reset path context in case we switch back to SVG rendering.
|
|
111
|
+
path.context(null);
|
|
112
|
+
|
|
113
|
+
return () => {
|
|
114
|
+
context.clearRect(
|
|
115
|
+
0,
|
|
116
|
+
0,
|
|
117
|
+
plot.width * (devicePixelRatio.current ?? 1),
|
|
118
|
+
plot.height * (devicePixelRatio.current ?? 1)
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<CanvasLayer {@attach render} />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ScaledDataRecord } from '../../types/index.js';
|
|
2
|
+
import type { GeoPath } from 'd3-geo';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
scaledData: ScaledDataRecord[];
|
|
5
|
+
path: GeoPath;
|
|
6
|
+
/** Symbol key used to retrieve the GeoJSON geometry from each datum. */
|
|
7
|
+
geomKey: symbol;
|
|
8
|
+
/**
|
|
9
|
+
* The color keyword that, when used as fill/stroke, maps the threshold
|
|
10
|
+
* value through the plot's color scale. E.g. "value" for Contour,
|
|
11
|
+
* "density" for Density.
|
|
12
|
+
*/
|
|
13
|
+
colorKeyword: string;
|
|
14
|
+
fill: string;
|
|
15
|
+
stroke: string;
|
|
16
|
+
strokeWidth?: number;
|
|
17
|
+
strokeOpacity?: number;
|
|
18
|
+
fillOpacity?: number;
|
|
19
|
+
opacity?: number;
|
|
20
|
+
strokeMiterlimit?: number;
|
|
21
|
+
};
|
|
22
|
+
declare const GeoPathCanvas: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
23
|
+
type GeoPathCanvas = ReturnType<typeof GeoPathCanvas>;
|
|
24
|
+
export default GeoPathCanvas;
|