svelteplot 0.0.1-alpha.9 → 0.1.3-next.12
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/LICENSE.md +5 -0
- package/README.md +3 -35
- package/dist/Mark.svelte +292 -0
- package/dist/Mark.svelte.d.ts +22 -0
- package/dist/Plot.svelte +148 -156
- package/dist/Plot.svelte.d.ts +15 -15
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +110 -0
- package/dist/core/Facet.svelte +59 -0
- package/dist/core/Facet.svelte.d.ts +18 -0
- package/dist/core/FacetAxes.svelte +66 -0
- package/dist/core/FacetAxes.svelte.d.ts +4 -0
- package/dist/core/FacetGrid.svelte +86 -0
- package/dist/core/FacetGrid.svelte.d.ts +13 -0
- package/dist/core/Plot.svelte +568 -0
- package/dist/core/Plot.svelte.d.ts +14 -0
- package/dist/helpers/arrowPath.d.ts +14 -0
- package/dist/helpers/arrowPath.js +129 -0
- package/dist/helpers/autoProjection.d.ts +19 -0
- package/dist/helpers/autoProjection.js +87 -0
- package/dist/helpers/autoScales.d.ts +23 -0
- package/dist/helpers/autoScales.js +203 -0
- package/dist/helpers/autoTicks.d.ts +3 -0
- package/dist/helpers/autoTicks.js +40 -0
- package/dist/helpers/autoTimeFormat.d.ts +2 -2
- package/dist/helpers/autoTimeFormat.js +34 -5
- package/dist/helpers/callWithProps.d.ts +8 -0
- package/dist/helpers/callWithProps.js +13 -0
- package/dist/helpers/colors.js +17 -2
- package/dist/helpers/curves.d.ts +3 -0
- package/dist/helpers/curves.js +42 -0
- package/dist/helpers/data.d.ts +9 -0
- package/dist/helpers/data.js +16 -0
- package/dist/helpers/facets.d.ts +12 -0
- package/dist/helpers/facets.js +49 -0
- package/dist/helpers/formats.d.ts +3 -0
- package/dist/helpers/formats.js +3 -0
- package/dist/helpers/getBaseStyles.d.ts +7 -2
- package/dist/helpers/getBaseStyles.js +34 -10
- package/dist/helpers/getLogTicks.js +5 -5
- package/dist/helpers/group.d.ts +6 -0
- package/dist/helpers/group.js +53 -0
- package/dist/helpers/index.d.ts +18 -0
- package/dist/helpers/index.js +55 -0
- package/dist/helpers/isRawValue.d.ts +2 -0
- package/dist/helpers/isRawValue.js +5 -0
- package/dist/helpers/isValid.d.ts +6 -0
- package/dist/helpers/isValid.js +6 -0
- package/dist/helpers/math.d.ts +19 -0
- package/dist/helpers/math.js +116 -0
- package/dist/helpers/mergeDeep.d.ts +1 -1
- package/dist/helpers/noise.d.ts +1 -0
- package/dist/helpers/noise.js +72 -0
- package/dist/helpers/projection.d.ts +33 -0
- package/dist/helpers/projection.js +100 -0
- package/dist/helpers/reduce.d.ts +10 -0
- package/dist/helpers/reduce.js +85 -0
- package/dist/helpers/regressionLoess.d.ts +12 -0
- package/dist/helpers/regressionLoess.js +47 -0
- package/dist/helpers/removeIdenticalLines.d.ts +8 -1
- package/dist/helpers/removeIdenticalLines.js +14 -7
- package/dist/helpers/resolve.d.ts +21 -0
- package/dist/helpers/resolve.js +156 -0
- package/dist/helpers/roundedRect.d.ts +9 -0
- package/dist/helpers/roundedRect.js +31 -0
- package/dist/helpers/scales.d.ts +42 -0
- package/dist/helpers/scales.js +311 -0
- package/dist/helpers/time.d.ts +6 -0
- package/dist/helpers/time.js +282 -0
- package/dist/helpers/typeChecks.d.ts +8 -5
- package/dist/helpers/typeChecks.js +27 -6
- package/dist/index.d.ts +49 -1
- package/dist/index.js +53 -2
- package/dist/marks/Area.svelte +146 -0
- package/dist/marks/Area.svelte.d.ts +30 -0
- package/dist/marks/AreaX.svelte +27 -0
- package/dist/marks/AreaX.svelte.d.ts +12 -0
- package/dist/marks/AreaY.svelte +38 -0
- package/dist/marks/AreaY.svelte.d.ts +19 -0
- package/dist/marks/Arrow.svelte +139 -0
- package/dist/marks/Arrow.svelte.d.ts +44 -0
- package/dist/marks/AxisX.svelte +198 -93
- package/dist/marks/AxisX.svelte.d.ts +17 -16
- package/dist/marks/AxisY.svelte +176 -62
- package/dist/marks/AxisY.svelte.d.ts +17 -14
- package/dist/marks/BarX.svelte +93 -0
- package/dist/marks/BarX.svelte.d.ts +4 -0
- package/dist/marks/BarY.svelte +103 -0
- package/dist/marks/BarY.svelte.d.ts +25 -0
- package/dist/marks/BollingerX.svelte +44 -0
- package/dist/marks/BollingerX.svelte.d.ts +18 -0
- package/dist/marks/BollingerY.svelte +39 -0
- package/dist/marks/BollingerY.svelte.d.ts +18 -0
- package/dist/marks/BoxX.svelte +89 -0
- package/dist/marks/BoxX.svelte.d.ts +4 -0
- package/dist/marks/BoxY.svelte +110 -0
- package/dist/marks/BoxY.svelte.d.ts +29 -0
- package/dist/marks/Cell.svelte +110 -0
- package/dist/marks/Cell.svelte.d.ts +16 -0
- package/dist/marks/CellX.svelte +24 -0
- package/dist/marks/CellX.svelte.d.ts +3 -0
- package/dist/marks/CellY.svelte +24 -0
- package/dist/marks/CellY.svelte.d.ts +3 -0
- package/dist/marks/ColorLegend.svelte +148 -27
- package/dist/marks/ColorLegend.svelte.d.ts +12 -13
- package/dist/marks/CustomMark.svelte +43 -0
- package/dist/marks/CustomMark.svelte.d.ts +16 -0
- package/dist/marks/CustomMarkHTML.svelte +103 -0
- package/dist/marks/CustomMarkHTML.svelte.d.ts +17 -0
- package/dist/marks/DifferenceY.svelte +144 -0
- package/dist/marks/DifferenceY.svelte.d.ts +30 -0
- package/dist/marks/Dot.svelte +128 -73
- package/dist/marks/Dot.svelte.d.ts +24 -14
- package/dist/marks/DotX.svelte +15 -3
- package/dist/marks/DotX.svelte.d.ts +8 -16
- package/dist/marks/DotY.svelte +8 -3
- package/dist/marks/DotY.svelte.d.ts +5 -17
- package/dist/marks/Frame.svelte +39 -31
- package/dist/marks/Frame.svelte.d.ts +7 -14
- package/dist/marks/Geo.svelte +102 -0
- package/dist/marks/Geo.svelte.d.ts +10 -0
- package/dist/marks/Graticule.svelte +28 -0
- package/dist/marks/Graticule.svelte.d.ts +9 -0
- package/dist/marks/GridX.svelte +67 -36
- package/dist/marks/GridX.svelte.d.ts +7 -18
- package/dist/marks/GridY.svelte +64 -25
- package/dist/marks/GridY.svelte.d.ts +7 -14
- package/dist/marks/HTMLTooltip.svelte +91 -0
- package/dist/marks/HTMLTooltip.svelte.d.ts +11 -0
- package/dist/marks/Line.svelte +219 -58
- package/dist/marks/Line.svelte.d.ts +30 -14
- package/dist/marks/LineX.svelte +8 -8
- package/dist/marks/LineX.svelte.d.ts +4 -17
- package/dist/marks/LineY.svelte +7 -8
- package/dist/marks/LineY.svelte.d.ts +4 -17
- package/dist/marks/Link.svelte +180 -0
- package/dist/marks/Link.svelte.d.ts +21 -0
- package/dist/marks/Pointer.svelte +126 -0
- package/dist/marks/Pointer.svelte.d.ts +23 -0
- package/dist/marks/Rect.svelte +103 -0
- package/dist/marks/Rect.svelte.d.ts +15 -0
- package/dist/marks/RectX.svelte +33 -0
- package/dist/marks/RectX.svelte.d.ts +15 -0
- package/dist/marks/RectY.svelte +33 -0
- package/dist/marks/RectY.svelte.d.ts +15 -0
- package/dist/marks/RegressionX.svelte +26 -0
- package/dist/marks/RegressionX.svelte.d.ts +4 -0
- package/dist/marks/RegressionY.svelte +26 -0
- package/dist/marks/RegressionY.svelte.d.ts +4 -0
- package/dist/marks/RuleX.svelte +52 -28
- package/dist/marks/RuleX.svelte.d.ts +14 -14
- package/dist/marks/RuleY.svelte +52 -28
- package/dist/marks/RuleY.svelte.d.ts +14 -14
- package/dist/marks/Sphere.svelte +8 -0
- package/dist/marks/Sphere.svelte.d.ts +51 -0
- package/dist/marks/Spike.svelte +15 -0
- package/dist/marks/Spike.svelte.d.ts +4 -0
- package/dist/marks/SymbolLegend.svelte +27 -12
- package/dist/marks/SymbolLegend.svelte.d.ts +8 -14
- package/dist/marks/Text.svelte +189 -0
- package/dist/marks/Text.svelte.d.ts +26 -0
- package/dist/marks/TickX.svelte +89 -0
- package/dist/marks/TickX.svelte.d.ts +22 -0
- package/dist/marks/TickY.svelte +90 -0
- package/dist/marks/TickY.svelte.d.ts +22 -0
- package/dist/marks/Vector.svelte +219 -0
- package/dist/marks/Vector.svelte.d.ts +31 -0
- package/dist/marks/helpers/BaseAxisX.svelte +210 -0
- package/dist/marks/helpers/BaseAxisX.svelte.d.ts +24 -0
- package/dist/marks/helpers/BaseAxisY.svelte +187 -0
- package/dist/marks/helpers/BaseAxisY.svelte.d.ts +23 -0
- package/dist/marks/helpers/CanvasLayer.svelte +38 -0
- package/dist/marks/helpers/CanvasLayer.svelte.d.ts +13 -0
- package/dist/marks/helpers/DotCanvas.svelte +184 -0
- package/dist/marks/helpers/DotCanvas.svelte.d.ts +11 -0
- package/dist/marks/helpers/GeoCanvas.svelte +165 -0
- package/dist/marks/helpers/GeoCanvas.svelte.d.ts +13 -0
- package/dist/marks/helpers/GroupMultiple.svelte +17 -0
- package/dist/marks/helpers/GroupMultiple.svelte.d.ts +9 -0
- package/dist/marks/helpers/Marker.svelte +93 -0
- package/dist/marks/helpers/Marker.svelte.d.ts +10 -0
- package/dist/marks/helpers/MarkerPath.svelte +141 -0
- package/dist/marks/helpers/MarkerPath.svelte.d.ts +44 -0
- package/dist/marks/helpers/Regression.svelte +174 -0
- package/dist/marks/helpers/Regression.svelte.d.ts +26 -0
- package/dist/marks/helpers/events.d.ts +8 -0
- package/dist/marks/helpers/events.js +74 -0
- package/dist/transforms/bin.d.ts +51 -0
- package/dist/transforms/bin.js +171 -0
- package/dist/transforms/bollinger.d.ts +21 -0
- package/dist/transforms/bollinger.js +53 -0
- package/dist/transforms/centroid.d.ts +9 -0
- package/dist/transforms/centroid.js +13 -0
- package/dist/transforms/facet.d.ts +1 -0
- package/dist/transforms/facet.js +1 -0
- package/dist/transforms/filter.d.ts +2 -0
- package/dist/transforms/filter.js +8 -0
- package/dist/transforms/group.d.ts +66 -0
- package/dist/transforms/group.js +109 -0
- package/dist/transforms/interval.d.ts +11 -0
- package/dist/transforms/interval.js +34 -0
- package/dist/transforms/jitter.d.ts +1 -0
- package/dist/transforms/jitter.js +1 -0
- package/dist/transforms/map.d.ts +10 -0
- package/dist/transforms/map.js +89 -0
- package/dist/transforms/normalize.d.ts +9 -0
- package/dist/transforms/normalize.js +86 -0
- package/dist/transforms/recordize.d.ts +15 -0
- package/dist/transforms/recordize.js +78 -0
- package/dist/transforms/rename.d.ts +14 -0
- package/dist/transforms/rename.js +42 -0
- package/dist/transforms/select.d.ts +35 -0
- package/dist/transforms/select.js +55 -0
- package/dist/transforms/shift.d.ts +13 -0
- package/dist/transforms/shift.js +45 -0
- package/dist/transforms/sort.d.ts +28 -0
- package/dist/transforms/sort.js +66 -0
- package/dist/transforms/stack.d.ts +10 -0
- package/dist/transforms/stack.js +110 -0
- package/dist/transforms/window.d.ts +24 -0
- package/dist/transforms/window.js +73 -0
- package/dist/types.d.ts +625 -188
- package/dist/ui/Checkbox.svelte +6 -0
- package/dist/ui/Checkbox.svelte.d.ts +13 -0
- package/dist/ui/RadioInput.svelte +27 -0
- package/dist/ui/RadioInput.svelte.d.ts +9 -0
- package/dist/ui/Select.svelte +27 -0
- package/dist/ui/Select.svelte.d.ts +9 -0
- package/dist/ui/Slider.svelte +47 -0
- package/dist/ui/Slider.svelte.d.ts +11 -0
- package/dist/ui/Spiral.svelte +46 -0
- package/dist/ui/Spiral.svelte.d.ts +15 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +4 -0
- package/package.json +81 -42
- package/LICENSE +0 -11
- package/dist/classes/Channel.svelte.js +0 -74
- package/dist/classes/Mark.svelte.js +0 -17
- package/dist/classes/Plot.svelte.js +0 -98
- package/dist/contants.d.ts +0 -3
- package/dist/contants.js +0 -40
- package/dist/helpers/GroupMultiple.svelte +0 -8
- package/dist/helpers/GroupMultiple.svelte.d.ts +0 -19
- package/dist/helpers/createScale.d.ts +0 -5
- package/dist/helpers/createScale.js +0 -57
- package/dist/helpers/resolveChannel.d.ts +0 -2
- package/dist/helpers/resolveChannel.js +0 -28
- package/dist/helpers/wrapArray.d.ts +0 -2
- package/dist/helpers/wrapArray.js +0 -4
- package/dist/marks/BaseMark.svelte +0 -22
- package/dist/marks/BaseMark.svelte.d.ts +0 -19
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let {
|
|
3
|
+
canvas = $bindable(),
|
|
4
|
+
devicePixelRatio = $bindable(1),
|
|
5
|
+
plot
|
|
6
|
+
}: {
|
|
7
|
+
canvas: HTMLCanvasElement;
|
|
8
|
+
devicePixelRatio: number;
|
|
9
|
+
plot: PlotState;
|
|
10
|
+
} = $props();
|
|
11
|
+
|
|
12
|
+
$effect(() => {
|
|
13
|
+
devicePixelRatio = window.devicePixelRatio || 1;
|
|
14
|
+
const ctx = canvas.getContext('2d');
|
|
15
|
+
});
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<!--
|
|
19
|
+
@component The CanvasLayer component is a helper component that inserts a
|
|
20
|
+
canvas element inside a foreignObject for use in a plot and takes care of
|
|
21
|
+
scaling it to the device pixel ratio.
|
|
22
|
+
-->
|
|
23
|
+
|
|
24
|
+
<foreignObject x="0" y="0" width={plot.width} height={plot.height}>
|
|
25
|
+
<canvas
|
|
26
|
+
xmlns="http://www.w3.org/1999/xhtml"
|
|
27
|
+
bind:this={canvas}
|
|
28
|
+
width={plot.width * devicePixelRatio}
|
|
29
|
+
height={plot.height * devicePixelRatio}
|
|
30
|
+
style="width: {plot.width}px; height: {plot.height}px;"></canvas>
|
|
31
|
+
</foreignObject>
|
|
32
|
+
|
|
33
|
+
<style>
|
|
34
|
+
foreignObject,
|
|
35
|
+
canvas {
|
|
36
|
+
color: currentColor;
|
|
37
|
+
}
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
canvas: HTMLCanvasElement;
|
|
3
|
+
devicePixelRatio: number;
|
|
4
|
+
plot: PlotState;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The CanvasLayer component is a helper component that inserts a
|
|
8
|
+
* canvas element inside a foreignObject for use in a plot and takes care of
|
|
9
|
+
* scaling it to the device pixel ratio.
|
|
10
|
+
*/
|
|
11
|
+
declare const CanvasLayer: import("svelte").Component<$$ComponentProps, {}, "canvas" | "devicePixelRatio">;
|
|
12
|
+
type CanvasLayer = ReturnType<typeof CanvasLayer>;
|
|
13
|
+
export default CanvasLayer;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PlotState, Mark, DataRecord, BaseMarkProps } from '../../types.js';
|
|
3
|
+
import { CSS_VAR } from '../../constants.js';
|
|
4
|
+
import { isValid, testFilter } from '../../helpers/index.js';
|
|
5
|
+
import { resolveChannel, resolveProp, resolveScaledStyleProps } from '../../helpers/resolve.js';
|
|
6
|
+
import { projectXY } from '../../helpers/scales.js';
|
|
7
|
+
import { maybeSymbol } from '../../helpers/symbols.js';
|
|
8
|
+
import { symbol as d3Symbol } from 'd3-shape';
|
|
9
|
+
import { untrack } from 'svelte';
|
|
10
|
+
import { isEqual } from 'es-toolkit';
|
|
11
|
+
|
|
12
|
+
let canvas: HTMLCanvasElement | undefined = $state();
|
|
13
|
+
let devicePixelRatio = $state(1);
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
mark,
|
|
17
|
+
plot,
|
|
18
|
+
data,
|
|
19
|
+
testFacet,
|
|
20
|
+
usedScales
|
|
21
|
+
}: {
|
|
22
|
+
mark: Mark<BaseMarkProps>;
|
|
23
|
+
plot: PlotState;
|
|
24
|
+
data: DataRecord[];
|
|
25
|
+
testFacet: any;
|
|
26
|
+
usedScales: any;
|
|
27
|
+
} = $props();
|
|
28
|
+
|
|
29
|
+
function drawSymbolPath(symbolType: string, size: number, context) {
|
|
30
|
+
// maybeSymbol(symbolType).draw(context, size);
|
|
31
|
+
return d3Symbol(maybeSymbol(symbolType), size).context(context)();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function scaleHash(scale) {
|
|
35
|
+
return { domain: scale.domain, type: scale.type, range: scale.range };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let _plotSize = $state([plot.width, plot.height]);
|
|
39
|
+
let _usedScales = $state(usedScales);
|
|
40
|
+
let _markOptions = $state(mark.options);
|
|
41
|
+
const xScale = $derived(scaleHash(plot.scales.x));
|
|
42
|
+
const yScale = $derived(scaleHash(plot.scales.y));
|
|
43
|
+
const rScale = $derived(scaleHash(plot.scales.r));
|
|
44
|
+
let _xScale = $state(xScale);
|
|
45
|
+
let _yScale = $state(yScale);
|
|
46
|
+
let _rScale = $state(rScale);
|
|
47
|
+
|
|
48
|
+
const filteredData = $derived(
|
|
49
|
+
data.filter((datum) => testFilter(datum, _markOptions) && testFacet(datum, _markOptions))
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
let _filteredData: DataRecord[] = $state([]);
|
|
53
|
+
|
|
54
|
+
$effect(() => {
|
|
55
|
+
// update _usedScales only if changed
|
|
56
|
+
if (!isEqual(usedScales, _usedScales)) _usedScales = usedScales;
|
|
57
|
+
if (!isEqual(mark.options, _markOptions)) _markOptions = mark.options;
|
|
58
|
+
|
|
59
|
+
const plotSize = [plot.width, plot.height];
|
|
60
|
+
if (!isEqual(plotSize, _plotSize)) _plotSize = plotSize;
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
_markOptions.filter
|
|
64
|
+
? !isEqual(filteredData, _filteredData)
|
|
65
|
+
: filteredData.length !== _filteredData.length
|
|
66
|
+
) {
|
|
67
|
+
_filteredData = filteredData;
|
|
68
|
+
}
|
|
69
|
+
if (!isEqual(xScale, _xScale)) _xScale = xScale;
|
|
70
|
+
if (!isEqual(yScale, _yScale)) _yScale = yScale;
|
|
71
|
+
if (!isEqual(rScale, _rScale)) _rScale = rScale;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
$effect(() => {
|
|
75
|
+
// track plot size, since we're untracking the scales
|
|
76
|
+
_plotSize;
|
|
77
|
+
_markOptions;
|
|
78
|
+
_xScale;
|
|
79
|
+
_yScale;
|
|
80
|
+
_rScale;
|
|
81
|
+
const plotScales = untrack(() => plot.scales);
|
|
82
|
+
const context = canvas.getContext('2d');
|
|
83
|
+
if (context === null) return;
|
|
84
|
+
// this will re-run whenever `color` or `size` change
|
|
85
|
+
context.resetTransform();
|
|
86
|
+
context.scale(devicePixelRatio, devicePixelRatio);
|
|
87
|
+
|
|
88
|
+
for (const datum of _filteredData) {
|
|
89
|
+
// untrack the filter test to avoid redrawing when not necessary
|
|
90
|
+
const x = resolveChannel('x', datum, _markOptions);
|
|
91
|
+
const y = resolveChannel('y', datum, _markOptions);
|
|
92
|
+
const r = resolveChannel('r', datum, _markOptions) || 2;
|
|
93
|
+
const symbol_ = resolveChannel('symbol', datum, {
|
|
94
|
+
symbol: 'circle',
|
|
95
|
+
..._markOptions
|
|
96
|
+
});
|
|
97
|
+
const symbol = _usedScales.symbol ? plotScales.symbol.fn(symbol_) : symbol_;
|
|
98
|
+
|
|
99
|
+
if (isValid(x) && isValid(y) && isValid(r)) {
|
|
100
|
+
const [px, py] = projectXY(plotScales, x, y, true, true);
|
|
101
|
+
|
|
102
|
+
const r_ = _usedScales.r ? plotScales.r.fn(r) : r;
|
|
103
|
+
const size = r_ * r_ * Math.PI * devicePixelRatio;
|
|
104
|
+
let { stroke, strokeOpacity, fillOpacity, fill, opacity } = resolveScaledStyleProps(
|
|
105
|
+
datum,
|
|
106
|
+
_markOptions,
|
|
107
|
+
_usedScales,
|
|
108
|
+
untrack(() => plot),
|
|
109
|
+
'stroke'
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (`${fill}`.toLowerCase() === 'currentcolor')
|
|
113
|
+
fill = getComputedStyle(canvas.parentElement.parentElement).getPropertyValue(
|
|
114
|
+
'color'
|
|
115
|
+
);
|
|
116
|
+
if (`${stroke}`.toLowerCase() === 'currentcolor')
|
|
117
|
+
stroke = getComputedStyle(canvas.parentElement.parentElement).getPropertyValue(
|
|
118
|
+
'color'
|
|
119
|
+
);
|
|
120
|
+
if (CSS_VAR.test(fill))
|
|
121
|
+
fill = getComputedStyle(canvas).getPropertyValue(fill.slice(4, -1));
|
|
122
|
+
if (CSS_VAR.test(stroke))
|
|
123
|
+
stroke = getComputedStyle(canvas).getPropertyValue(stroke.slice(4, -1));
|
|
124
|
+
|
|
125
|
+
if (stroke && stroke !== 'none') {
|
|
126
|
+
const strokeWidth = resolveProp(_markOptions.strokeWidth, datum, 1.6);
|
|
127
|
+
context.lineWidth = strokeWidth;
|
|
128
|
+
}
|
|
129
|
+
context.fillStyle = fill ? fill : 'none';
|
|
130
|
+
context.strokeStyle = stroke ? stroke : 'none';
|
|
131
|
+
context.translate(px, py);
|
|
132
|
+
|
|
133
|
+
context.beginPath();
|
|
134
|
+
drawSymbolPath(symbol, size, context);
|
|
135
|
+
context.closePath();
|
|
136
|
+
|
|
137
|
+
if (opacity != null) context.globalAlpha = opacity ?? 1;
|
|
138
|
+
if (fillOpacity != null) context.globalAlpha = (opacity ?? 1) * fillOpacity;
|
|
139
|
+
if (fill && fill !== 'none') context.fill();
|
|
140
|
+
if (strokeOpacity != null) context.globalAlpha = (opacity ?? 1) * strokeOpacity;
|
|
141
|
+
if (stroke && stroke !== 'none') context.stroke();
|
|
142
|
+
context.translate(-px, -py);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return () => {
|
|
146
|
+
canvas?.getContext('2d')?.clearRect(0, 0, canvas?.width, canvas?.height);
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// code from https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
|
|
151
|
+
let remove: null | (() => void) = null;
|
|
152
|
+
|
|
153
|
+
function updatePixelRatio() {
|
|
154
|
+
if (remove != null) {
|
|
155
|
+
remove();
|
|
156
|
+
}
|
|
157
|
+
const mqString = `(resolution: ${window.devicePixelRatio}dppx)`;
|
|
158
|
+
const media = matchMedia(mqString);
|
|
159
|
+
media.addEventListener('change', updatePixelRatio);
|
|
160
|
+
remove = () => {
|
|
161
|
+
media.removeEventListener('change', updatePixelRatio);
|
|
162
|
+
};
|
|
163
|
+
devicePixelRatio = window.devicePixelRatio;
|
|
164
|
+
}
|
|
165
|
+
$effect(() => {
|
|
166
|
+
updatePixelRatio();
|
|
167
|
+
});
|
|
168
|
+
</script>
|
|
169
|
+
|
|
170
|
+
<foreignObject x="0" y="0" width={plot.width} height={plot.height}>
|
|
171
|
+
<canvas
|
|
172
|
+
xmlns="http://www.w3.org/1999/xhtml"
|
|
173
|
+
bind:this={canvas}
|
|
174
|
+
width={plot.width * devicePixelRatio}
|
|
175
|
+
height={plot.height * devicePixelRatio}
|
|
176
|
+
style="width: {plot.width}px; height: {plot.height}px;"></canvas>
|
|
177
|
+
</foreignObject>
|
|
178
|
+
|
|
179
|
+
<style>
|
|
180
|
+
foreignObject,
|
|
181
|
+
canvas {
|
|
182
|
+
color: currentColor;
|
|
183
|
+
}
|
|
184
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PlotState, Mark, DataRecord, BaseMarkProps } from '../../types.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
mark: Mark<BaseMarkProps>;
|
|
4
|
+
plot: PlotState;
|
|
5
|
+
data: DataRecord[];
|
|
6
|
+
testFacet: any;
|
|
7
|
+
usedScales: any;
|
|
8
|
+
};
|
|
9
|
+
declare const DotCanvas: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type DotCanvas = ReturnType<typeof DotCanvas>;
|
|
11
|
+
export default DotCanvas;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PlotState, Mark, DataRecord, BaseMarkProps } from '../../types.js';
|
|
3
|
+
import { CSS_VAR } from '../../constants.js';
|
|
4
|
+
import { testFilter } from '../../helpers/index.js';
|
|
5
|
+
import { resolveProp, resolveScaledStyleProps } from '../../helpers/resolve.js';
|
|
6
|
+
import { untrack } from 'svelte';
|
|
7
|
+
import { isEqual } from 'es-toolkit';
|
|
8
|
+
import { type GeoPath } from 'd3-geo';
|
|
9
|
+
|
|
10
|
+
let canvas: HTMLCanvasElement | undefined = $state();
|
|
11
|
+
let devicePixelRatio = $state(1);
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
mark,
|
|
15
|
+
plot,
|
|
16
|
+
data,
|
|
17
|
+
testFacet,
|
|
18
|
+
usedScales,
|
|
19
|
+
path
|
|
20
|
+
}: {
|
|
21
|
+
mark: Mark<BaseMarkProps>;
|
|
22
|
+
plot: PlotState;
|
|
23
|
+
data: DataRecord[];
|
|
24
|
+
testFacet: any;
|
|
25
|
+
usedScales: any;
|
|
26
|
+
path: GeoPath;
|
|
27
|
+
} = $props();
|
|
28
|
+
|
|
29
|
+
function scaleHash(scale) {
|
|
30
|
+
return { domain: scale.domain, type: scale.type, range: scale.range };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let _plotSize = $state([plot.width, plot.height]);
|
|
34
|
+
let _usedScales = $state(usedScales);
|
|
35
|
+
let _markOptions = $state(mark.options);
|
|
36
|
+
|
|
37
|
+
const filteredData = $derived(
|
|
38
|
+
data.filter((datum) => testFilter(datum, _markOptions) && testFacet(datum, _markOptions))
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
let _filteredData: DataRecord[] = $state([]);
|
|
42
|
+
|
|
43
|
+
$effect(() => {
|
|
44
|
+
// update _usedScales only if changed
|
|
45
|
+
if (!isEqual(usedScales, _usedScales)) _usedScales = usedScales;
|
|
46
|
+
if (!isEqual(mark.options, _markOptions)) _markOptions = mark.options;
|
|
47
|
+
|
|
48
|
+
const plotSize = [plot.width, plot.height];
|
|
49
|
+
if (!isEqual(plotSize, _plotSize)) _plotSize = plotSize;
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
_markOptions.filter
|
|
53
|
+
? !isEqual(filteredData, _filteredData)
|
|
54
|
+
: filteredData.length !== _filteredData.length
|
|
55
|
+
) {
|
|
56
|
+
_filteredData = filteredData;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
$effect(() => {
|
|
61
|
+
// track plot size, since we're untracking the scales
|
|
62
|
+
_plotSize;
|
|
63
|
+
_markOptions;
|
|
64
|
+
|
|
65
|
+
const plotScales = untrack(() => plot.scales);
|
|
66
|
+
const context = canvas.getContext('2d');
|
|
67
|
+
if (context === null) return;
|
|
68
|
+
// this will re-run whenever `color` or `size` change
|
|
69
|
+
context.resetTransform();
|
|
70
|
+
context.scale(devicePixelRatio, devicePixelRatio);
|
|
71
|
+
|
|
72
|
+
let currentColor;
|
|
73
|
+
|
|
74
|
+
path.context(context);
|
|
75
|
+
|
|
76
|
+
const plot_ = untrack(() => plot);
|
|
77
|
+
|
|
78
|
+
for (const datum of _filteredData) {
|
|
79
|
+
// untrack the filter test to avoid redrawing when not necessary
|
|
80
|
+
let { stroke, fill, opacity, ...restStyles } = resolveScaledStyleProps(
|
|
81
|
+
datum,
|
|
82
|
+
_markOptions,
|
|
83
|
+
_usedScales,
|
|
84
|
+
plot_,
|
|
85
|
+
'fill'
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const fillOpacity = restStyles['fill-opacity'];
|
|
89
|
+
const strokeOpacity = restStyles['stroke-opacity'];
|
|
90
|
+
|
|
91
|
+
if (`${fill}`.toLowerCase() === 'currentcolor')
|
|
92
|
+
fill =
|
|
93
|
+
currentColor ||
|
|
94
|
+
(currentColor = getComputedStyle(
|
|
95
|
+
canvas?.parentElement?.parentElement
|
|
96
|
+
).getPropertyValue('color'));
|
|
97
|
+
if (`${stroke}`.toLowerCase() === 'currentcolor')
|
|
98
|
+
stroke =
|
|
99
|
+
currentColor ||
|
|
100
|
+
(currentColor = getComputedStyle(
|
|
101
|
+
canvas?.parentElement?.parentElement
|
|
102
|
+
).getPropertyValue('color'));
|
|
103
|
+
if (CSS_VAR.test(fill))
|
|
104
|
+
fill = getComputedStyle(canvas).getPropertyValue(fill.slice(4, -1));
|
|
105
|
+
if (CSS_VAR.test(stroke))
|
|
106
|
+
stroke = getComputedStyle(canvas).getPropertyValue(stroke.slice(4, -1));
|
|
107
|
+
|
|
108
|
+
if (stroke && stroke !== 'none') {
|
|
109
|
+
const strokeWidth = resolveProp(_markOptions.strokeWidth, datum, 1.6);
|
|
110
|
+
context.lineWidth = strokeWidth;
|
|
111
|
+
}
|
|
112
|
+
context.fillStyle = fill ? fill : 'none';
|
|
113
|
+
context.strokeStyle = stroke ? stroke : 'none';
|
|
114
|
+
|
|
115
|
+
context.beginPath();
|
|
116
|
+
path(datum);
|
|
117
|
+
context.closePath();
|
|
118
|
+
|
|
119
|
+
if (opacity != null) context.globalAlpha = opacity ?? 1;
|
|
120
|
+
if (fillOpacity != null) context.globalAlpha = (opacity ?? 1) * fillOpacity;
|
|
121
|
+
|
|
122
|
+
if (fill && fill !== 'none') context.fill();
|
|
123
|
+
if (strokeOpacity != null) context.globalAlpha = (opacity ?? 1) * strokeOpacity;
|
|
124
|
+
if (stroke && stroke !== 'none') context.stroke();
|
|
125
|
+
}
|
|
126
|
+
return () => {
|
|
127
|
+
canvas?.getContext('2d')?.clearRect(0, 0, canvas?.width, canvas?.height);
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// code from https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
|
|
132
|
+
let remove: null | (() => void) = null;
|
|
133
|
+
|
|
134
|
+
function updatePixelRatio() {
|
|
135
|
+
if (remove != null) {
|
|
136
|
+
remove();
|
|
137
|
+
}
|
|
138
|
+
const mqString = `(resolution: ${window.devicePixelRatio}dppx)`;
|
|
139
|
+
const media = matchMedia(mqString);
|
|
140
|
+
media.addEventListener('change', updatePixelRatio);
|
|
141
|
+
remove = () => {
|
|
142
|
+
media.removeEventListener('change', updatePixelRatio);
|
|
143
|
+
};
|
|
144
|
+
devicePixelRatio = window.devicePixelRatio;
|
|
145
|
+
}
|
|
146
|
+
$effect(() => {
|
|
147
|
+
updatePixelRatio();
|
|
148
|
+
});
|
|
149
|
+
</script>
|
|
150
|
+
|
|
151
|
+
<foreignObject x="0" y="0" width={plot.width} height={plot.height}>
|
|
152
|
+
<canvas
|
|
153
|
+
xmlns="http://www.w3.org/1999/xhtml"
|
|
154
|
+
bind:this={canvas}
|
|
155
|
+
width={plot.width * devicePixelRatio}
|
|
156
|
+
height={plot.height * devicePixelRatio}
|
|
157
|
+
style="width: {plot.width}px; height: {plot.height}px;"></canvas>
|
|
158
|
+
</foreignObject>
|
|
159
|
+
|
|
160
|
+
<style>
|
|
161
|
+
foreignObject,
|
|
162
|
+
canvas {
|
|
163
|
+
color: currentColor;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PlotState, Mark, DataRecord, BaseMarkProps } from '../../types.js';
|
|
2
|
+
import { type GeoPath } from 'd3-geo';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
mark: Mark<BaseMarkProps>;
|
|
5
|
+
plot: PlotState;
|
|
6
|
+
data: DataRecord[];
|
|
7
|
+
testFacet: any;
|
|
8
|
+
usedScales: any;
|
|
9
|
+
path: GeoPath;
|
|
10
|
+
};
|
|
11
|
+
declare const GeoCanvas: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type GeoCanvas = ReturnType<typeof GeoCanvas>;
|
|
13
|
+
export default GeoCanvas;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
let {
|
|
4
|
+
length = 1,
|
|
5
|
+
children,
|
|
6
|
+
class: className = null,
|
|
7
|
+
...groupProps
|
|
8
|
+
}: { children: Snippet; length?: number; class?: string | null } = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
{#if length > 1 || className}
|
|
12
|
+
<g class={className} {...groupProps}>
|
|
13
|
+
{@render children()}
|
|
14
|
+
</g>
|
|
15
|
+
{:else}
|
|
16
|
+
{@render children()}
|
|
17
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
children: Snippet;
|
|
4
|
+
length?: number;
|
|
5
|
+
class?: string | null;
|
|
6
|
+
};
|
|
7
|
+
declare const GroupMultiple: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type GroupMultiple = ReturnType<typeof GroupMultiple>;
|
|
9
|
+
export default GroupMultiple;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export type MarkerShape =
|
|
3
|
+
| 'dot'
|
|
4
|
+
| 'circle'
|
|
5
|
+
| 'circle-stroke'
|
|
6
|
+
| 'arrow'
|
|
7
|
+
| 'arrow-reverse'
|
|
8
|
+
| 'tick'
|
|
9
|
+
| 'tick-x'
|
|
10
|
+
| 'tick-y';
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<!--
|
|
14
|
+
@component Marker is a helper component that creates a marker for use in a line or path.
|
|
15
|
+
-->
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import { getContext } from 'svelte';
|
|
19
|
+
|
|
20
|
+
type MarkerProps = {
|
|
21
|
+
id: string;
|
|
22
|
+
shape: MarkerShape;
|
|
23
|
+
color: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
let { id, shape, color }: MarkerProps = $props();
|
|
27
|
+
|
|
28
|
+
const tickMarker = (orient: number | 'auto') => ({
|
|
29
|
+
viewBox: '-3 -3 6 6',
|
|
30
|
+
path: 'M0,-3v6',
|
|
31
|
+
width: 6,
|
|
32
|
+
height: 6,
|
|
33
|
+
orient,
|
|
34
|
+
color: 'stroke'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const MARKERS: Record<
|
|
38
|
+
MarkerShape,
|
|
39
|
+
{
|
|
40
|
+
path?: string;
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
orient: number | 'auto';
|
|
44
|
+
color: 'fill' | 'stroke';
|
|
45
|
+
bg?: 'fill' | 'stroke';
|
|
46
|
+
viewBox?: string;
|
|
47
|
+
}
|
|
48
|
+
> = {
|
|
49
|
+
circle: { width: 6.67, height: 6.67, orient: 0, color: 'fill', bg: 'stroke' },
|
|
50
|
+
dot: { width: 6.67, height: 6.67, orient: 0, color: 'fill' },
|
|
51
|
+
'circle-stroke': { width: 6.67, height: 6.67, orient: 0, color: 'stroke', bg: 'fill' },
|
|
52
|
+
tick: tickMarker('auto'),
|
|
53
|
+
'tick-x': tickMarker(90),
|
|
54
|
+
'tick-y': tickMarker(0),
|
|
55
|
+
arrow: {
|
|
56
|
+
path: 'M-1.5,-3l3,3l-3,3',
|
|
57
|
+
width: 6.67,
|
|
58
|
+
height: 6.67,
|
|
59
|
+
orient: 'auto',
|
|
60
|
+
color: 'stroke'
|
|
61
|
+
},
|
|
62
|
+
'arrow-reverse': {
|
|
63
|
+
path: 'M1.5,-3l-3,3l3,3',
|
|
64
|
+
width: 6.67,
|
|
65
|
+
height: 6.67,
|
|
66
|
+
orient: 'auto',
|
|
67
|
+
color: 'stroke'
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const defaultDotRadius = getContext('svelteplot/_defaults').markerDotRadius;
|
|
72
|
+
|
|
73
|
+
const markerColors = $derived({
|
|
74
|
+
fill: 'none',
|
|
75
|
+
[MARKERS[shape].color]: color,
|
|
76
|
+
...(MARKERS[shape].bg ? { [MARKERS[shape].bg as string]: 'var(--svelteplot-bg)' } : {})
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<marker
|
|
81
|
+
{id}
|
|
82
|
+
viewBox={MARKERS[shape].viewBox || '-5 -5 10 10'}
|
|
83
|
+
markerWidth={MARKERS[shape].width}
|
|
84
|
+
orient={MARKERS[shape].orient}
|
|
85
|
+
markerHeight={MARKERS[shape].height}
|
|
86
|
+
stroke-width="1.5"
|
|
87
|
+
{...markerColors}>
|
|
88
|
+
{#if shape === 'dot' || shape === 'circle' || shape === 'circle-stroke'}
|
|
89
|
+
<circle r={defaultDotRadius} />
|
|
90
|
+
{:else}
|
|
91
|
+
<path d={MARKERS[shape].path} />
|
|
92
|
+
{/if}
|
|
93
|
+
</marker>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type MarkerShape = 'dot' | 'circle' | 'circle-stroke' | 'arrow' | 'arrow-reverse' | 'tick' | 'tick-x' | 'tick-y';
|
|
2
|
+
type MarkerProps = {
|
|
3
|
+
id: string;
|
|
4
|
+
shape: MarkerShape;
|
|
5
|
+
color: string;
|
|
6
|
+
};
|
|
7
|
+
/** Marker is a helper component that creates a marker for use in a line or path. */
|
|
8
|
+
declare const Marker: import("svelte").Component<MarkerProps, {}, "">;
|
|
9
|
+
type Marker = ReturnType<typeof Marker>;
|
|
10
|
+
export default Marker;
|