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.
Files changed (251) hide show
  1. package/LICENSE.md +5 -0
  2. package/README.md +3 -35
  3. package/dist/Mark.svelte +292 -0
  4. package/dist/Mark.svelte.d.ts +22 -0
  5. package/dist/Plot.svelte +148 -156
  6. package/dist/Plot.svelte.d.ts +15 -15
  7. package/dist/constants.d.ts +15 -0
  8. package/dist/constants.js +110 -0
  9. package/dist/core/Facet.svelte +59 -0
  10. package/dist/core/Facet.svelte.d.ts +18 -0
  11. package/dist/core/FacetAxes.svelte +66 -0
  12. package/dist/core/FacetAxes.svelte.d.ts +4 -0
  13. package/dist/core/FacetGrid.svelte +86 -0
  14. package/dist/core/FacetGrid.svelte.d.ts +13 -0
  15. package/dist/core/Plot.svelte +568 -0
  16. package/dist/core/Plot.svelte.d.ts +14 -0
  17. package/dist/helpers/arrowPath.d.ts +14 -0
  18. package/dist/helpers/arrowPath.js +129 -0
  19. package/dist/helpers/autoProjection.d.ts +19 -0
  20. package/dist/helpers/autoProjection.js +87 -0
  21. package/dist/helpers/autoScales.d.ts +23 -0
  22. package/dist/helpers/autoScales.js +203 -0
  23. package/dist/helpers/autoTicks.d.ts +3 -0
  24. package/dist/helpers/autoTicks.js +40 -0
  25. package/dist/helpers/autoTimeFormat.d.ts +2 -2
  26. package/dist/helpers/autoTimeFormat.js +34 -5
  27. package/dist/helpers/callWithProps.d.ts +8 -0
  28. package/dist/helpers/callWithProps.js +13 -0
  29. package/dist/helpers/colors.js +17 -2
  30. package/dist/helpers/curves.d.ts +3 -0
  31. package/dist/helpers/curves.js +42 -0
  32. package/dist/helpers/data.d.ts +9 -0
  33. package/dist/helpers/data.js +16 -0
  34. package/dist/helpers/facets.d.ts +12 -0
  35. package/dist/helpers/facets.js +49 -0
  36. package/dist/helpers/formats.d.ts +3 -0
  37. package/dist/helpers/formats.js +3 -0
  38. package/dist/helpers/getBaseStyles.d.ts +7 -2
  39. package/dist/helpers/getBaseStyles.js +34 -10
  40. package/dist/helpers/getLogTicks.js +5 -5
  41. package/dist/helpers/group.d.ts +6 -0
  42. package/dist/helpers/group.js +53 -0
  43. package/dist/helpers/index.d.ts +18 -0
  44. package/dist/helpers/index.js +55 -0
  45. package/dist/helpers/isRawValue.d.ts +2 -0
  46. package/dist/helpers/isRawValue.js +5 -0
  47. package/dist/helpers/isValid.d.ts +6 -0
  48. package/dist/helpers/isValid.js +6 -0
  49. package/dist/helpers/math.d.ts +19 -0
  50. package/dist/helpers/math.js +116 -0
  51. package/dist/helpers/mergeDeep.d.ts +1 -1
  52. package/dist/helpers/noise.d.ts +1 -0
  53. package/dist/helpers/noise.js +72 -0
  54. package/dist/helpers/projection.d.ts +33 -0
  55. package/dist/helpers/projection.js +100 -0
  56. package/dist/helpers/reduce.d.ts +10 -0
  57. package/dist/helpers/reduce.js +85 -0
  58. package/dist/helpers/regressionLoess.d.ts +12 -0
  59. package/dist/helpers/regressionLoess.js +47 -0
  60. package/dist/helpers/removeIdenticalLines.d.ts +8 -1
  61. package/dist/helpers/removeIdenticalLines.js +14 -7
  62. package/dist/helpers/resolve.d.ts +21 -0
  63. package/dist/helpers/resolve.js +156 -0
  64. package/dist/helpers/roundedRect.d.ts +9 -0
  65. package/dist/helpers/roundedRect.js +31 -0
  66. package/dist/helpers/scales.d.ts +42 -0
  67. package/dist/helpers/scales.js +311 -0
  68. package/dist/helpers/time.d.ts +6 -0
  69. package/dist/helpers/time.js +282 -0
  70. package/dist/helpers/typeChecks.d.ts +8 -5
  71. package/dist/helpers/typeChecks.js +27 -6
  72. package/dist/index.d.ts +49 -1
  73. package/dist/index.js +53 -2
  74. package/dist/marks/Area.svelte +146 -0
  75. package/dist/marks/Area.svelte.d.ts +30 -0
  76. package/dist/marks/AreaX.svelte +27 -0
  77. package/dist/marks/AreaX.svelte.d.ts +12 -0
  78. package/dist/marks/AreaY.svelte +38 -0
  79. package/dist/marks/AreaY.svelte.d.ts +19 -0
  80. package/dist/marks/Arrow.svelte +139 -0
  81. package/dist/marks/Arrow.svelte.d.ts +44 -0
  82. package/dist/marks/AxisX.svelte +198 -93
  83. package/dist/marks/AxisX.svelte.d.ts +17 -16
  84. package/dist/marks/AxisY.svelte +176 -62
  85. package/dist/marks/AxisY.svelte.d.ts +17 -14
  86. package/dist/marks/BarX.svelte +93 -0
  87. package/dist/marks/BarX.svelte.d.ts +4 -0
  88. package/dist/marks/BarY.svelte +103 -0
  89. package/dist/marks/BarY.svelte.d.ts +25 -0
  90. package/dist/marks/BollingerX.svelte +44 -0
  91. package/dist/marks/BollingerX.svelte.d.ts +18 -0
  92. package/dist/marks/BollingerY.svelte +39 -0
  93. package/dist/marks/BollingerY.svelte.d.ts +18 -0
  94. package/dist/marks/BoxX.svelte +89 -0
  95. package/dist/marks/BoxX.svelte.d.ts +4 -0
  96. package/dist/marks/BoxY.svelte +110 -0
  97. package/dist/marks/BoxY.svelte.d.ts +29 -0
  98. package/dist/marks/Cell.svelte +110 -0
  99. package/dist/marks/Cell.svelte.d.ts +16 -0
  100. package/dist/marks/CellX.svelte +24 -0
  101. package/dist/marks/CellX.svelte.d.ts +3 -0
  102. package/dist/marks/CellY.svelte +24 -0
  103. package/dist/marks/CellY.svelte.d.ts +3 -0
  104. package/dist/marks/ColorLegend.svelte +148 -27
  105. package/dist/marks/ColorLegend.svelte.d.ts +12 -13
  106. package/dist/marks/CustomMark.svelte +43 -0
  107. package/dist/marks/CustomMark.svelte.d.ts +16 -0
  108. package/dist/marks/CustomMarkHTML.svelte +103 -0
  109. package/dist/marks/CustomMarkHTML.svelte.d.ts +17 -0
  110. package/dist/marks/DifferenceY.svelte +144 -0
  111. package/dist/marks/DifferenceY.svelte.d.ts +30 -0
  112. package/dist/marks/Dot.svelte +128 -73
  113. package/dist/marks/Dot.svelte.d.ts +24 -14
  114. package/dist/marks/DotX.svelte +15 -3
  115. package/dist/marks/DotX.svelte.d.ts +8 -16
  116. package/dist/marks/DotY.svelte +8 -3
  117. package/dist/marks/DotY.svelte.d.ts +5 -17
  118. package/dist/marks/Frame.svelte +39 -31
  119. package/dist/marks/Frame.svelte.d.ts +7 -14
  120. package/dist/marks/Geo.svelte +102 -0
  121. package/dist/marks/Geo.svelte.d.ts +10 -0
  122. package/dist/marks/Graticule.svelte +28 -0
  123. package/dist/marks/Graticule.svelte.d.ts +9 -0
  124. package/dist/marks/GridX.svelte +67 -36
  125. package/dist/marks/GridX.svelte.d.ts +7 -18
  126. package/dist/marks/GridY.svelte +64 -25
  127. package/dist/marks/GridY.svelte.d.ts +7 -14
  128. package/dist/marks/HTMLTooltip.svelte +91 -0
  129. package/dist/marks/HTMLTooltip.svelte.d.ts +11 -0
  130. package/dist/marks/Line.svelte +219 -58
  131. package/dist/marks/Line.svelte.d.ts +30 -14
  132. package/dist/marks/LineX.svelte +8 -8
  133. package/dist/marks/LineX.svelte.d.ts +4 -17
  134. package/dist/marks/LineY.svelte +7 -8
  135. package/dist/marks/LineY.svelte.d.ts +4 -17
  136. package/dist/marks/Link.svelte +180 -0
  137. package/dist/marks/Link.svelte.d.ts +21 -0
  138. package/dist/marks/Pointer.svelte +126 -0
  139. package/dist/marks/Pointer.svelte.d.ts +23 -0
  140. package/dist/marks/Rect.svelte +103 -0
  141. package/dist/marks/Rect.svelte.d.ts +15 -0
  142. package/dist/marks/RectX.svelte +33 -0
  143. package/dist/marks/RectX.svelte.d.ts +15 -0
  144. package/dist/marks/RectY.svelte +33 -0
  145. package/dist/marks/RectY.svelte.d.ts +15 -0
  146. package/dist/marks/RegressionX.svelte +26 -0
  147. package/dist/marks/RegressionX.svelte.d.ts +4 -0
  148. package/dist/marks/RegressionY.svelte +26 -0
  149. package/dist/marks/RegressionY.svelte.d.ts +4 -0
  150. package/dist/marks/RuleX.svelte +52 -28
  151. package/dist/marks/RuleX.svelte.d.ts +14 -14
  152. package/dist/marks/RuleY.svelte +52 -28
  153. package/dist/marks/RuleY.svelte.d.ts +14 -14
  154. package/dist/marks/Sphere.svelte +8 -0
  155. package/dist/marks/Sphere.svelte.d.ts +51 -0
  156. package/dist/marks/Spike.svelte +15 -0
  157. package/dist/marks/Spike.svelte.d.ts +4 -0
  158. package/dist/marks/SymbolLegend.svelte +27 -12
  159. package/dist/marks/SymbolLegend.svelte.d.ts +8 -14
  160. package/dist/marks/Text.svelte +189 -0
  161. package/dist/marks/Text.svelte.d.ts +26 -0
  162. package/dist/marks/TickX.svelte +89 -0
  163. package/dist/marks/TickX.svelte.d.ts +22 -0
  164. package/dist/marks/TickY.svelte +90 -0
  165. package/dist/marks/TickY.svelte.d.ts +22 -0
  166. package/dist/marks/Vector.svelte +219 -0
  167. package/dist/marks/Vector.svelte.d.ts +31 -0
  168. package/dist/marks/helpers/BaseAxisX.svelte +210 -0
  169. package/dist/marks/helpers/BaseAxisX.svelte.d.ts +24 -0
  170. package/dist/marks/helpers/BaseAxisY.svelte +187 -0
  171. package/dist/marks/helpers/BaseAxisY.svelte.d.ts +23 -0
  172. package/dist/marks/helpers/CanvasLayer.svelte +38 -0
  173. package/dist/marks/helpers/CanvasLayer.svelte.d.ts +13 -0
  174. package/dist/marks/helpers/DotCanvas.svelte +184 -0
  175. package/dist/marks/helpers/DotCanvas.svelte.d.ts +11 -0
  176. package/dist/marks/helpers/GeoCanvas.svelte +165 -0
  177. package/dist/marks/helpers/GeoCanvas.svelte.d.ts +13 -0
  178. package/dist/marks/helpers/GroupMultiple.svelte +17 -0
  179. package/dist/marks/helpers/GroupMultiple.svelte.d.ts +9 -0
  180. package/dist/marks/helpers/Marker.svelte +93 -0
  181. package/dist/marks/helpers/Marker.svelte.d.ts +10 -0
  182. package/dist/marks/helpers/MarkerPath.svelte +141 -0
  183. package/dist/marks/helpers/MarkerPath.svelte.d.ts +44 -0
  184. package/dist/marks/helpers/Regression.svelte +174 -0
  185. package/dist/marks/helpers/Regression.svelte.d.ts +26 -0
  186. package/dist/marks/helpers/events.d.ts +8 -0
  187. package/dist/marks/helpers/events.js +74 -0
  188. package/dist/transforms/bin.d.ts +51 -0
  189. package/dist/transforms/bin.js +171 -0
  190. package/dist/transforms/bollinger.d.ts +21 -0
  191. package/dist/transforms/bollinger.js +53 -0
  192. package/dist/transforms/centroid.d.ts +9 -0
  193. package/dist/transforms/centroid.js +13 -0
  194. package/dist/transforms/facet.d.ts +1 -0
  195. package/dist/transforms/facet.js +1 -0
  196. package/dist/transforms/filter.d.ts +2 -0
  197. package/dist/transforms/filter.js +8 -0
  198. package/dist/transforms/group.d.ts +66 -0
  199. package/dist/transforms/group.js +109 -0
  200. package/dist/transforms/interval.d.ts +11 -0
  201. package/dist/transforms/interval.js +34 -0
  202. package/dist/transforms/jitter.d.ts +1 -0
  203. package/dist/transforms/jitter.js +1 -0
  204. package/dist/transforms/map.d.ts +10 -0
  205. package/dist/transforms/map.js +89 -0
  206. package/dist/transforms/normalize.d.ts +9 -0
  207. package/dist/transforms/normalize.js +86 -0
  208. package/dist/transforms/recordize.d.ts +15 -0
  209. package/dist/transforms/recordize.js +78 -0
  210. package/dist/transforms/rename.d.ts +14 -0
  211. package/dist/transforms/rename.js +42 -0
  212. package/dist/transforms/select.d.ts +35 -0
  213. package/dist/transforms/select.js +55 -0
  214. package/dist/transforms/shift.d.ts +13 -0
  215. package/dist/transforms/shift.js +45 -0
  216. package/dist/transforms/sort.d.ts +28 -0
  217. package/dist/transforms/sort.js +66 -0
  218. package/dist/transforms/stack.d.ts +10 -0
  219. package/dist/transforms/stack.js +110 -0
  220. package/dist/transforms/window.d.ts +24 -0
  221. package/dist/transforms/window.js +73 -0
  222. package/dist/types.d.ts +625 -188
  223. package/dist/ui/Checkbox.svelte +6 -0
  224. package/dist/ui/Checkbox.svelte.d.ts +13 -0
  225. package/dist/ui/RadioInput.svelte +27 -0
  226. package/dist/ui/RadioInput.svelte.d.ts +9 -0
  227. package/dist/ui/Select.svelte +27 -0
  228. package/dist/ui/Select.svelte.d.ts +9 -0
  229. package/dist/ui/Slider.svelte +47 -0
  230. package/dist/ui/Slider.svelte.d.ts +11 -0
  231. package/dist/ui/Spiral.svelte +46 -0
  232. package/dist/ui/Spiral.svelte.d.ts +15 -0
  233. package/dist/ui/index.d.ts +4 -0
  234. package/dist/ui/index.js +4 -0
  235. package/package.json +81 -42
  236. package/LICENSE +0 -11
  237. package/dist/classes/Channel.svelte.js +0 -74
  238. package/dist/classes/Mark.svelte.js +0 -17
  239. package/dist/classes/Plot.svelte.js +0 -98
  240. package/dist/contants.d.ts +0 -3
  241. package/dist/contants.js +0 -40
  242. package/dist/helpers/GroupMultiple.svelte +0 -8
  243. package/dist/helpers/GroupMultiple.svelte.d.ts +0 -19
  244. package/dist/helpers/createScale.d.ts +0 -5
  245. package/dist/helpers/createScale.js +0 -57
  246. package/dist/helpers/resolveChannel.d.ts +0 -2
  247. package/dist/helpers/resolveChannel.js +0 -28
  248. package/dist/helpers/wrapArray.d.ts +0 -2
  249. package/dist/helpers/wrapArray.js +0 -4
  250. package/dist/marks/BaseMark.svelte +0 -22
  251. 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;