layerchart 2.0.0-next.1 → 2.0.0-next.2

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 (266) hide show
  1. package/dist/actions/movable.d.ts +28 -0
  2. package/dist/actions/movable.js +91 -0
  3. package/dist/components/AnnotationLine.svelte +155 -0
  4. package/dist/components/AnnotationLine.svelte.d.ts +28 -0
  5. package/dist/components/AnnotationPoint.svelte +121 -0
  6. package/dist/components/AnnotationPoint.svelte.d.ts +32 -0
  7. package/dist/components/AnnotationRange.svelte +147 -0
  8. package/dist/components/AnnotationRange.svelte.d.ts +40 -0
  9. package/dist/components/Arc.svelte +344 -151
  10. package/dist/components/Arc.svelte.d.ts +138 -0
  11. package/dist/components/Area.svelte +165 -149
  12. package/dist/components/Area.svelte.d.ts +45 -0
  13. package/dist/components/Axis.svelte +287 -174
  14. package/dist/components/Axis.svelte.d.ts +116 -0
  15. package/dist/components/Bar.svelte +163 -107
  16. package/dist/components/Bar.svelte.d.ts +48 -0
  17. package/dist/components/Bars.svelte +54 -68
  18. package/dist/components/Bars.svelte.d.ts +27 -0
  19. package/dist/components/Blur.svelte +31 -7
  20. package/dist/components/Blur.svelte.d.ts +23 -21
  21. package/dist/components/Bounds.svelte +49 -19
  22. package/dist/components/Bounds.svelte.d.ts +24 -50
  23. package/dist/components/BrushContext.svelte +296 -168
  24. package/dist/components/BrushContext.svelte.d.ts +97 -65
  25. package/dist/components/Calendar.svelte +116 -59
  26. package/dist/components/Calendar.svelte.d.ts +50 -31
  27. package/dist/components/Chart.svelte +1289 -398
  28. package/dist/components/Chart.svelte.d.ts +535 -410
  29. package/dist/components/ChartClipPath.svelte +37 -15
  30. package/dist/components/ChartClipPath.svelte.d.ts +21 -19
  31. package/dist/components/Circle.svelte +124 -85
  32. package/dist/components/Circle.svelte.d.ts +52 -0
  33. package/dist/components/CircleClipPath.svelte +76 -16
  34. package/dist/components/CircleClipPath.svelte.d.ts +46 -0
  35. package/dist/components/ClipPath.svelte +60 -15
  36. package/dist/components/ClipPath.svelte.d.ts +40 -27
  37. package/dist/components/ColorRamp.svelte +75 -9
  38. package/dist/components/ColorRamp.svelte.d.ts +37 -19
  39. package/dist/components/ComputedStyles.svelte +17 -5
  40. package/dist/components/ComputedStyles.svelte.d.ts +11 -19
  41. package/dist/components/Connector.svelte +149 -0
  42. package/dist/components/Connector.svelte.d.ts +51 -0
  43. package/dist/components/Dagre.svelte +211 -122
  44. package/dist/components/Dagre.svelte.d.ts +119 -56
  45. package/dist/components/ForceSimulation.svelte +215 -90
  46. package/dist/components/ForceSimulation.svelte.d.ts +82 -35
  47. package/dist/components/Frame.svelte +33 -13
  48. package/dist/components/Frame.svelte.d.ts +13 -17
  49. package/dist/components/GeoCircle.svelte +29 -16
  50. package/dist/components/GeoCircle.svelte.d.ts +22 -24
  51. package/dist/components/GeoContext.svelte +113 -72
  52. package/dist/components/GeoContext.svelte.d.ts +49 -41
  53. package/dist/components/GeoEdgeFade.svelte +47 -12
  54. package/dist/components/GeoEdgeFade.svelte.d.ts +17 -19
  55. package/dist/components/GeoPath.svelte +157 -127
  56. package/dist/components/GeoPath.svelte.d.ts +48 -36
  57. package/dist/components/GeoPoint.svelte +52 -20
  58. package/dist/components/GeoPoint.svelte.d.ts +25 -22
  59. package/dist/components/GeoSpline.svelte +75 -26
  60. package/dist/components/GeoSpline.svelte.d.ts +29 -20
  61. package/dist/components/GeoTile.svelte +100 -49
  62. package/dist/components/GeoTile.svelte.d.ts +38 -23
  63. package/dist/components/GeoVisible.svelte +17 -9
  64. package/dist/components/GeoVisible.svelte.d.ts +10 -18
  65. package/dist/components/Graticule.svelte +28 -13
  66. package/dist/components/Graticule.svelte.d.ts +11 -52
  67. package/dist/components/Grid.svelte +226 -114
  68. package/dist/components/Grid.svelte.d.ts +70 -0
  69. package/dist/components/Group.svelte +132 -105
  70. package/dist/components/Group.svelte.d.ts +53 -0
  71. package/dist/components/Highlight.svelte +409 -307
  72. package/dist/components/Highlight.svelte.d.ts +107 -0
  73. package/dist/components/Hull.svelte +96 -45
  74. package/dist/components/Hull.svelte.d.ts +40 -30
  75. package/dist/components/Labels.svelte +125 -46
  76. package/dist/components/Labels.svelte.d.ts +70 -27
  77. package/dist/components/Legend.svelte +374 -190
  78. package/dist/components/Legend.svelte.d.ts +95 -44
  79. package/dist/components/Line.svelte +163 -125
  80. package/dist/components/Line.svelte.d.ts +75 -0
  81. package/dist/components/LinearGradient.svelte +153 -78
  82. package/dist/components/LinearGradient.svelte.d.ts +66 -31
  83. package/dist/components/Link.svelte +160 -104
  84. package/dist/components/Link.svelte.d.ts +54 -0
  85. package/dist/components/Marker.svelte +100 -39
  86. package/dist/components/Marker.svelte.d.ts +59 -27
  87. package/dist/components/MarkerWrapper.svelte +35 -0
  88. package/dist/components/MarkerWrapper.svelte.d.ts +18 -0
  89. package/dist/components/MonthPath.svelte +65 -20
  90. package/dist/components/MonthPath.svelte.d.ts +23 -17
  91. package/dist/components/MotionPath.svelte +80 -24
  92. package/dist/components/MotionPath.svelte.d.ts +46 -27
  93. package/dist/components/Pack.svelte +53 -17
  94. package/dist/components/Pack.svelte.d.ts +42 -21
  95. package/dist/components/Partition.svelte +64 -22
  96. package/dist/components/Partition.svelte.d.ts +49 -26
  97. package/dist/components/Pattern.svelte +297 -11
  98. package/dist/components/Pattern.svelte.d.ts +103 -19
  99. package/dist/components/Pie.svelte +122 -76
  100. package/dist/components/Pie.svelte.d.ts +65 -51
  101. package/dist/components/Point.svelte +20 -9
  102. package/dist/components/Point.svelte.d.ts +16 -20
  103. package/dist/components/Points.svelte +148 -137
  104. package/dist/components/Points.svelte.d.ts +45 -34
  105. package/dist/components/RadialGradient.svelte +143 -70
  106. package/dist/components/RadialGradient.svelte.d.ts +69 -31
  107. package/dist/components/Rect.svelte +121 -102
  108. package/dist/components/Rect.svelte.d.ts +36 -0
  109. package/dist/components/RectClipPath.svelte +82 -18
  110. package/dist/components/RectClipPath.svelte.d.ts +55 -0
  111. package/dist/components/Rule.svelte +105 -62
  112. package/dist/components/Rule.svelte.d.ts +40 -19
  113. package/dist/components/Sankey.svelte +132 -55
  114. package/dist/components/Sankey.svelte.d.ts +61 -31
  115. package/dist/components/Spline.svelte +281 -218
  116. package/dist/components/Spline.svelte.d.ts +95 -0
  117. package/dist/components/Text.svelte +437 -176
  118. package/dist/components/Text.svelte.d.ts +130 -0
  119. package/dist/components/Threshold.svelte +48 -16
  120. package/dist/components/Threshold.svelte.d.ts +29 -31
  121. package/dist/components/TileImage.svelte +103 -30
  122. package/dist/components/TileImage.svelte.d.ts +48 -23
  123. package/dist/components/TransformContext.svelte +365 -171
  124. package/dist/components/TransformControls.svelte +50 -26
  125. package/dist/components/TransformControls.svelte.d.ts +27 -19
  126. package/dist/components/Tree.svelte +74 -33
  127. package/dist/components/Tree.svelte.d.ts +42 -30
  128. package/dist/components/Treemap.svelte +119 -42
  129. package/dist/components/Treemap.svelte.d.ts +75 -27
  130. package/dist/components/Voronoi.svelte +106 -75
  131. package/dist/components/Voronoi.svelte.d.ts +40 -41
  132. package/dist/components/charts/ArcChart.svelte +464 -0
  133. package/dist/components/charts/ArcChart.svelte.d.ts +90 -0
  134. package/dist/components/charts/AreaChart.svelte +450 -393
  135. package/dist/components/charts/AreaChart.svelte.d.ts +61 -0
  136. package/dist/components/charts/BarChart.svelte +454 -389
  137. package/dist/components/charts/BarChart.svelte.d.ts +76 -0
  138. package/dist/components/charts/ChartAnnotations.svelte +37 -0
  139. package/dist/components/charts/ChartAnnotations.svelte.d.ts +10 -0
  140. package/dist/components/charts/DefaultTooltip.svelte +60 -0
  141. package/dist/components/charts/DefaultTooltip.svelte.d.ts +10 -0
  142. package/dist/components/charts/LineChart.svelte +369 -314
  143. package/dist/components/charts/LineChart.svelte.d.ts +53 -0
  144. package/dist/components/charts/PieChart.svelte +458 -316
  145. package/dist/components/charts/PieChart.svelte.d.ts +137 -353
  146. package/dist/components/charts/ScatterChart.svelte +334 -296
  147. package/dist/components/charts/ScatterChart.svelte.d.ts +39 -0
  148. package/dist/components/charts/index.d.ts +8 -0
  149. package/dist/components/charts/index.js +7 -0
  150. package/dist/components/charts/types.d.ts +253 -0
  151. package/dist/components/charts/utils.svelte.d.ts +30 -0
  152. package/dist/components/charts/utils.svelte.js +55 -0
  153. package/dist/components/index.d.ts +76 -4
  154. package/dist/components/index.js +76 -5
  155. package/dist/components/layout/Canvas.svelte +321 -155
  156. package/dist/components/layout/Canvas.svelte.d.ts +104 -55
  157. package/dist/components/layout/Html.svelte +82 -42
  158. package/dist/components/layout/Html.svelte.d.ts +39 -28
  159. package/dist/components/layout/Layer.svelte +39 -0
  160. package/dist/components/layout/Layer.svelte.d.ts +17 -0
  161. package/dist/components/layout/Svg.svelte +122 -70
  162. package/dist/components/layout/Svg.svelte.d.ts +53 -34
  163. package/dist/components/layout/WebGL.svelte +135 -0
  164. package/dist/components/layout/WebGL.svelte.d.ts +50 -0
  165. package/dist/components/tooltip/Tooltip.svelte +246 -78
  166. package/dist/components/tooltip/Tooltip.svelte.d.ts +149 -31
  167. package/dist/components/tooltip/TooltipContext.svelte +409 -271
  168. package/dist/components/tooltip/TooltipContext.svelte.d.ts +86 -55
  169. package/dist/components/tooltip/TooltipHeader.svelte +100 -11
  170. package/dist/components/tooltip/TooltipHeader.svelte.d.ts +43 -23
  171. package/dist/components/tooltip/TooltipItem.svelte +167 -27
  172. package/dist/components/tooltip/TooltipItem.svelte.d.ts +63 -31
  173. package/dist/components/tooltip/TooltipList.svelte +22 -3
  174. package/dist/components/tooltip/TooltipList.svelte.d.ts +6 -17
  175. package/dist/components/tooltip/TooltipSeparator.svelte +27 -1
  176. package/dist/components/tooltip/TooltipSeparator.svelte.d.ts +6 -15
  177. package/dist/components/tooltip/index.d.ts +6 -0
  178. package/dist/components/tooltip/index.js +6 -0
  179. package/dist/components/tooltip/tooltipMetaContext.d.ts +79 -0
  180. package/dist/components/tooltip/tooltipMetaContext.js +139 -0
  181. package/dist/components/types.d.ts +1 -0
  182. package/dist/components/types.js +1 -0
  183. package/dist/docs/Blockquote.svelte.d.ts +18 -14
  184. package/dist/docs/Code.svelte.d.ts +26 -22
  185. package/dist/docs/ConnectorSweepMenuField.svelte +17 -0
  186. package/dist/docs/ConnectorSweepMenuField.svelte.d.ts +7 -0
  187. package/dist/docs/ConnectorTypeMenuField.svelte +17 -0
  188. package/dist/docs/ConnectorTypeMenuField.svelte.d.ts +7 -0
  189. package/dist/docs/CurveMenuField.svelte +14 -3
  190. package/dist/docs/CurveMenuField.svelte.d.ts +9 -18
  191. package/dist/docs/GeoDebug.svelte +47 -42
  192. package/dist/docs/GeoDebug.svelte.d.ts +4 -16
  193. package/dist/docs/Header1.svelte.d.ts +27 -16
  194. package/dist/docs/Json.svelte.d.ts +20 -16
  195. package/dist/docs/Layout.svelte.d.ts +18 -13
  196. package/dist/docs/Link.svelte.d.ts +33 -21
  197. package/dist/docs/PathDataMenuField.svelte +14 -10
  198. package/dist/docs/PathDataMenuField.svelte.d.ts +8 -18
  199. package/dist/docs/Preview.svelte +20 -7
  200. package/dist/docs/Preview.svelte.d.ts +12 -22
  201. package/dist/docs/TilesetField.svelte.d.ts +21 -17
  202. package/dist/docs/TransformDebug.svelte +5 -6
  203. package/dist/docs/TransformDebug.svelte.d.ts +18 -14
  204. package/dist/docs/ViewSourceButton.svelte.d.ts +21 -17
  205. package/dist/types/d3-shape-extentions.d.ts +7 -0
  206. package/dist/utils/afterTick.d.ts +5 -0
  207. package/dist/utils/afterTick.js +8 -0
  208. package/dist/utils/arcText.svelte.d.ts +57 -0
  209. package/dist/utils/arcText.svelte.js +262 -0
  210. package/dist/utils/array.d.ts +9 -1
  211. package/dist/utils/array.js +13 -0
  212. package/dist/utils/attributes.d.ts +29 -0
  213. package/dist/utils/attributes.js +40 -0
  214. package/dist/utils/canvas.js +47 -10
  215. package/dist/utils/chart.d.ts +78 -0
  216. package/dist/utils/chart.js +512 -0
  217. package/dist/utils/color.d.ts +1 -0
  218. package/dist/utils/color.js +8 -0
  219. package/dist/utils/common.d.ts +3 -5
  220. package/dist/utils/common.js +3 -2
  221. package/dist/utils/connectorUtils.d.ts +21 -0
  222. package/dist/utils/connectorUtils.js +111 -0
  223. package/dist/utils/createId.d.ts +7 -0
  224. package/dist/utils/createId.js +9 -0
  225. package/dist/utils/debug.d.ts +1 -0
  226. package/dist/utils/debug.js +84 -0
  227. package/dist/utils/filterObject.d.ts +9 -0
  228. package/dist/utils/filterObject.js +12 -0
  229. package/dist/utils/graph/dagre.d.ts +34 -0
  230. package/dist/utils/graph/dagre.js +78 -0
  231. package/dist/utils/graph/dagre.test.d.ts +1 -0
  232. package/dist/utils/{graph.test.js → graph/dagre.test.js} +19 -33
  233. package/dist/utils/graph/sankey.d.ts +28 -0
  234. package/dist/utils/{graph.js → graph/sankey.js} +13 -41
  235. package/dist/utils/index.d.ts +3 -1
  236. package/dist/utils/index.js +3 -1
  237. package/dist/utils/key.svelte.d.ts +3 -0
  238. package/dist/utils/key.svelte.js +11 -0
  239. package/dist/utils/legendPayload.d.ts +7 -0
  240. package/dist/utils/legendPayload.js +8 -0
  241. package/dist/utils/motion.svelte.d.ts +140 -0
  242. package/dist/utils/motion.svelte.js +180 -0
  243. package/dist/utils/motion.test.d.ts +1 -0
  244. package/dist/utils/motion.test.js +213 -0
  245. package/dist/utils/{rect.d.ts → rect.svelte.d.ts} +7 -4
  246. package/dist/utils/rect.svelte.js +105 -0
  247. package/dist/utils/scales.svelte.d.ts +90 -0
  248. package/dist/utils/{scales.js → scales.svelte.js} +100 -39
  249. package/dist/utils/stack.d.ts +2 -3
  250. package/dist/utils/stack.js +1 -1
  251. package/dist/utils/string.js +87 -0
  252. package/dist/utils/ticks.d.ts +8 -2
  253. package/dist/utils/ticks.js +28 -0
  254. package/dist/utils/ticks.test.d.ts +1 -0
  255. package/dist/utils/ticks.test.js +67 -0
  256. package/dist/utils/types.d.ts +81 -0
  257. package/package.json +21 -19
  258. package/dist/components/ChartContext.svelte +0 -295
  259. package/dist/components/ChartContext.svelte.d.ts +0 -139
  260. package/dist/components/TransformContext.svelte.d.ts +0 -158
  261. package/dist/stores/motionStore.d.ts +0 -30
  262. package/dist/stores/motionStore.js +0 -62
  263. package/dist/utils/graph.d.ts +0 -37
  264. package/dist/utils/rect.js +0 -107
  265. package/dist/utils/scales.d.ts +0 -66
  266. /package/dist/{utils/graph.test.d.ts → components/charts/types.js} +0 -0
@@ -1,110 +1,217 @@
1
- <script lang="ts" context="module">
2
- import { getContext, setContext } from 'svelte';
1
+ <script lang="ts" module>
2
+ export type CanvasPropsWithoutHTML = {
3
+ /**
4
+ * The `<canvas>` tag. Useful for bindings.
5
+ *
6
+ * @bindable
7
+ */
8
+ ref?: HTMLCanvasElement;
9
+
10
+ /**
11
+ * The `<canvas>`'s 2d context. Useful for bindings.
12
+ *
13
+ * @bindable
14
+ */
15
+ canvasContext?: CanvasRenderingContext2D;
16
+
17
+ /**
18
+ * Force the use of a software (instead of hardware accelerated) 2D canvas, which can
19
+ * save memory when calling getImageData() frequently.
20
+ *
21
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext#willreadfrequently
22
+ *
23
+ * @default false
24
+ */
25
+ willReadFrequently?: boolean;
26
+
27
+ /**
28
+ * The `z-index` style to apply to the layer.
29
+ *
30
+ * @default 0
31
+ */
32
+ zIndex?: number;
33
+
34
+ /**
35
+ *
36
+ * Whether pointer events should be enabled on the canvas.
37
+ *
38
+ * - `false`: `pointer-events: none;` will be set on the entire layer.
39
+ * - `true`: pointer events will operate normally.
40
+ *
41
+ * @default true
42
+ */
43
+ pointerEvents?: boolean;
44
+
45
+ /**
46
+ * The content to display if canvas is not supported or cannot be rendered.
47
+ * This can either be a string or a snippet with custom markup.
48
+ */
49
+ fallback?: string | Snippet;
50
+
51
+ /**
52
+ * Translate children to center of the canvas (useful for radial layouts).
53
+ *
54
+ * @default false
55
+ */
56
+ center?: boolean | 'x' | 'y';
57
+
58
+ /**
59
+ * Ignore TransformContext.
60
+ *
61
+ * Useful to add static elements such as legends.
62
+ *
63
+ * @default false
64
+ */
65
+ ignoreTransform?: boolean;
66
+
67
+ /**
68
+ * Show the hit canvas for debugging purposes.
69
+ *
70
+ * @default false
71
+ */
72
+ debug?: boolean;
73
+
74
+ children?: Snippet<
75
+ [{ ref: HTMLCanvasElement; canvasContext: CanvasRenderingContext2D | undefined }]
76
+ >;
77
+ };
78
+
79
+ export type CanvasProps = CanvasPropsWithoutHTML &
80
+ Without<HTMLCanvasAttributes, CanvasPropsWithoutHTML>;
3
81
 
4
- type ComponentRender = {
82
+ type ComponentRender<T extends Element = Element> = {
5
83
  name: string;
6
84
  render: (ctx: CanvasRenderingContext2D, styleOverrides?: ComputedStylesOptions) => any;
7
85
  retainState?: boolean;
8
86
  events?: {
9
- click?: (e: MouseEvent) => void;
10
- dblclick?: (e: MouseEvent) => void;
11
- pointerenter?: (e: PointerEvent) => void;
12
- pointerover?: (e: PointerEvent) => void;
13
- pointermove?: (e: PointerEvent) => void;
14
- pointerleave?: (e: PointerEvent) => void;
15
- pointerout?: (e: PointerEvent) => void;
16
- pointerdown?: (e: PointerEvent) => void;
17
- touchmove?: (e: TouchEvent) => void;
87
+ click?: MouseEventHandler<T> | null;
88
+ dblclick?: MouseEventHandler<T> | null;
89
+ pointerenter?: PointerEventHandler<T> | null;
90
+ pointerover?: PointerEventHandler<T> | null;
91
+ pointermove?: PointerEventHandler<T> | null;
92
+ pointerleave?: PointerEventHandler<T> | null;
93
+ pointerout?: PointerEventHandler<T> | null;
94
+ pointerdown?: PointerEventHandler<T> | null;
95
+ touchmove?: TouchEventHandler<T> | null;
18
96
  };
97
+ /**
98
+ * Optional dependencies to track and invalidate the canvas context when they change.
99
+ */
100
+ deps?: () => any[];
19
101
  };
20
102
 
21
- export type CanvasContext = {
22
- /** Register component to render. Returns method to unregister on component destory */
23
- register(component: ComponentRender): () => void;
103
+ export type CanvasContextValue = {
104
+ /**
105
+ * Register component to render.
106
+ *
107
+ * Returns method to unregister on component destroy
108
+ */
109
+ register<T extends Element>(component: ComponentRender<T>): () => void;
24
110
  invalidate(): void;
25
111
  };
26
112
 
27
- export const canvasContextKey = Symbol();
113
+ const CanvasContext = new Context<CanvasContextValue>('CanvasContext');
114
+
115
+ const defaultCanvasContext: CanvasContextValue = {
116
+ register: <T extends Element>(_: ComponentRender<T>) => {
117
+ return () => {};
118
+ },
119
+ invalidate: () => {},
120
+ };
28
121
 
29
122
  export function getCanvasContext() {
30
- return getContext<CanvasContext>(canvasContextKey);
123
+ return CanvasContext.getOr(defaultCanvasContext);
31
124
  }
32
125
 
33
- function setCanvasContext(context: CanvasContext) {
34
- setContext(canvasContextKey, context);
126
+ function setCanvasContext(context: CanvasContextValue) {
127
+ return CanvasContext.set(context);
128
+ }
129
+
130
+ /**
131
+ * Handles the automatic registration of the component to the canvas context,
132
+ * with dependency tracking and cleanup on destroy.
133
+ */
134
+ export function registerCanvasComponent<T extends Element>(component: ComponentRender<T>) {
135
+ const canvasContext = getCanvasContext();
136
+
137
+ $effect.pre(() => {
138
+ return untrack(() => canvasContext.register(component));
139
+ });
35
140
  }
36
141
  </script>
37
142
 
38
143
  <script lang="ts">
39
- import { onMount, onDestroy } from 'svelte';
144
+ import { onMount, untrack, type Snippet } from 'svelte';
40
145
  import { cls } from '@layerstack/tailwind';
41
146
  import { Logger, localPoint } from '@layerstack/utils';
42
147
  import { darkColorScheme } from '@layerstack/svelte-stores';
43
148
 
44
149
  import { setRenderContext } from '../Chart.svelte';
45
- import { chartContext } from '../ChartContext.svelte';
46
- import { transformContext } from '../TransformContext.svelte';
150
+ import { getTransformContext } from '../TransformContext.svelte';
47
151
  import { getPixelColor, scaleCanvas, type ComputedStylesOptions } from '../../utils/canvas.js';
48
152
  import { getColorStr, rgbColorGenerator } from '../../utils/color.js';
153
+ import { Context } from 'runed';
154
+ import type {
155
+ HTMLCanvasAttributes,
156
+ MouseEventHandler,
157
+ PointerEventHandler,
158
+ TouchEventHandler,
159
+ } from 'svelte/elements';
160
+ import type { Without } from '../../utils/types.js';
161
+ import { getChartContext } from '../Chart.svelte';
162
+ import { layerClass } from '../../utils/attributes.js';
163
+
164
+ let {
165
+ ref: refProp = $bindable(),
166
+ canvasContext: canvasContextProp = $bindable(),
167
+ willReadFrequently = false,
168
+ debug = false,
169
+ zIndex = 0,
170
+ pointerEvents = true,
171
+ fallback,
172
+ center = false,
173
+ ignoreTransform = false,
174
+ class: className,
175
+ children,
176
+ onclick,
177
+ ondblclick,
178
+ onpointerenter,
179
+ onpointermove,
180
+ onpointerleave,
181
+ onpointerdown,
182
+ ontouchmove,
183
+ ...restProps
184
+ }: CanvasProps = $props();
185
+
186
+ let ref = $state<HTMLCanvasElement>();
187
+ let context = $state<CanvasRenderingContext2D>();
188
+
189
+ $effect.pre(() => {
190
+ refProp = ref;
191
+ });
49
192
 
50
- const { width, height, containerWidth, containerHeight, padding } = chartContext();
51
-
52
- /** The `<canvas>` tag. Useful for bindings. */
53
- export let element: HTMLCanvasElement | undefined = undefined;
54
-
55
- /** The `<canvas>`'s 2d context. Useful for bindings. */
56
- // @ts-expect-error: set during onMount()
57
- export let context: CanvasRenderingContext2D = undefined;
58
-
59
- /** Force the use of a software (instead of hardware accelerated) 2D canvas and can save memory when calling getImageData() frequently.
60
- * see: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext#willreadfrequently */
61
- export let willReadFrequently = false;
62
-
63
- /** The layer's z-index. */
64
- export let zIndex = undefined;
65
-
66
- /** Set this to `false` to set `pointer-events: none;` on the entire layer. */
67
- export let pointerEvents: boolean | undefined = undefined;
68
-
69
- /** Text to display if the browser won't render a canvas tag. You can also set arbitrary HTML via the "fallback" slot but this is fine if you just need text. If you use the "fallback" slot, this prop is ignored. */
70
- export let fallback = '';
71
-
72
- /** A string passed to the `aria-label` on the `<canvas>` tag. */
73
- export let label: string | undefined = undefined;
74
-
75
- /** A string passed to the `aria-labelledby` on the `<canvas>` tag. */
76
- export let labelledBy: string | undefined = undefined;
77
-
78
- /** A string passed to `aria-describedby` property on the `<canvas>` tag. */
79
- export let describedBy: string | undefined = undefined;
80
-
81
- /**
82
- * Translate children to center (useful for radial layouts)
83
- */
84
- export let center: boolean | 'x' | 'y' = false;
85
-
86
- /** Ignore TransformContext. Useful to add static elements such as legends. */
87
- export let ignoreTransform = false;
193
+ $effect.pre(() => {
194
+ canvasContextProp = context;
195
+ });
88
196
 
89
- /** Show hit canvas for debugging */
90
- export let debug = false;
197
+ const ctx = getChartContext();
198
+ const transformCtx = getTransformContext();
91
199
 
92
200
  const logger = new Logger('Canvas');
93
201
 
94
- let components = new Map<Symbol, ComponentRender>();
202
+ let components = new Map<Symbol, ComponentRender<Element>>();
95
203
  let pendingInvalidation = false;
96
204
  let frameId: number | undefined;
97
205
 
98
- const { mode, scale, translate, dragging, moving } = transformContext();
99
-
100
206
  /**
101
207
  * HitCanvas
102
208
  */
103
- let hitCanvasElement: HTMLCanvasElement | undefined = undefined;
104
- let hitCanvasContext: CanvasRenderingContext2D | undefined = undefined;
209
+ let hitCanvasElement = $state<HTMLCanvasElement>();
210
+ let hitCanvasContext = $state<CanvasRenderingContext2D>();
105
211
  let colorGenerator = rgbColorGenerator();
106
- let activeCanvas = false;
107
- let lastActiveComponent: ComponentRender | undefined | null;
212
+ let activeCanvas = $state(false);
213
+ let lastActiveComponent: ComponentRender | null | undefined = null;
214
+
108
215
  const componentByColor = new Map<string, ComponentRender>();
109
216
 
110
217
  function getPointerComponent(e: PointerEvent | MouseEvent | TouchEvent) {
@@ -116,7 +223,7 @@
116
223
  return component;
117
224
  }
118
225
 
119
- function onPointerMove(e: PointerEvent) {
226
+ const onPointerMove: PointerEventHandler<Element> = (e) => {
120
227
  activeCanvas = true;
121
228
  const component = getPointerComponent(e);
122
229
 
@@ -133,9 +240,9 @@
133
240
  component?.events?.pointermove?.(e);
134
241
 
135
242
  lastActiveComponent = component;
136
- }
243
+ };
137
244
 
138
- function onPointerLeave(e: PointerEvent) {
245
+ const onPointerLeave: PointerEventHandler<Element> = (e) => {
139
246
  // Pointer outside of canvas
140
247
 
141
248
  // Call last active component `pointerleave` event in case it was not triggered by hit canvas (quickly exiting canvas element before `pointermove` is triggered)
@@ -144,13 +251,13 @@
144
251
 
145
252
  lastActiveComponent = null;
146
253
  activeCanvas = false;
147
- }
254
+ };
148
255
  /**
149
256
  * end HitCanvas
150
257
  */
151
258
 
152
259
  onMount(() => {
153
- context = element?.getContext('2d', { willReadFrequently }) as CanvasRenderingContext2D;
260
+ context = ref?.getContext('2d', { willReadFrequently }) as CanvasRenderingContext2D;
154
261
 
155
262
  hitCanvasContext = hitCanvasElement?.getContext('2d', {
156
263
  willReadFrequently: false, // Explicitly set to `false` to resolve pixel artifacts between fill and stroke with the same color (issue #372)
@@ -172,142 +279,196 @@
172
279
 
173
280
  return () => {
174
281
  observer.disconnect();
282
+ if (frameId) {
283
+ cancelAnimationFrame(frameId);
284
+ }
175
285
  };
176
286
  });
177
287
 
178
- onDestroy(() => {
179
- if (frameId) {
180
- cancelAnimationFrame(frameId);
181
- }
182
- });
183
-
184
288
  function update() {
185
289
  if (!context) return;
186
- // TODO: only `scaleCanvas()` when containerWidth/Height change (not all invalidations)
187
- // scaleCanvas in `update()` to fix `requestAnimationFrame()` timing causing flash of blank canvas
188
- scaleCanvas(context, $containerWidth, $containerHeight);
189
290
 
190
- context.clearRect(0, 0, $containerWidth, $containerHeight);
291
+ // scale main canvas
292
+ scaleCanvas(context, ctx.containerWidth, ctx.containerHeight);
293
+ context.clearRect(0, 0, ctx.containerWidth, ctx.containerHeight);
294
+
295
+ // apply padding translation
296
+ context.translate(ctx.padding.left ?? 0, ctx.padding.top ?? 0);
191
297
 
192
- context.translate($padding.left ?? 0, $padding.top ?? 0);
298
+ let newTranslate: undefined | { x: number; y: number };
193
299
 
300
+ // apply centering or transform
194
301
  if (center) {
195
- const newTranslate = {
196
- x: center === 'x' || center === true ? $width / 2 : 0,
197
- y: center === 'y' || center === true ? $height / 2 : 0,
302
+ newTranslate = {
303
+ x: center === 'x' || center === true ? ctx.width / 2 : 0,
304
+ y: center === 'y' || center === true ? ctx.height / 2 : 0,
198
305
  };
199
306
  context.translate(newTranslate.x, newTranslate.y);
200
- } else if (mode === 'canvas' && !ignoreTransform) {
201
- context.translate($translate.x, $translate.y);
202
- context.scale($scale, $scale);
307
+ } else if (transformCtx.mode === 'canvas' && !ignoreTransform) {
308
+ context.translate(transformCtx.translate.x, transformCtx.translate.y);
309
+ context.scale(transformCtx.scale, transformCtx.scale);
203
310
  }
204
311
 
205
- // Sync hit canvas transform with main canvas
206
- if (hitCanvasContext) {
207
- scaleCanvas(hitCanvasContext, $containerWidth, $containerHeight);
208
- hitCanvasContext.clearRect(0, 0, $containerWidth, $containerHeight);
209
- hitCanvasContext.setTransform(context.getTransform());
312
+ // separate components into those that retain state and those that don't
313
+ const retainStateComponents: ComponentRender[] = [];
314
+ const nonRetainStateComponents: ComponentRender[] = [];
210
315
 
211
- // Reset color generator whenever updated so always reusing same colors (and not exhausting)
212
- colorGenerator = rgbColorGenerator();
213
- }
214
-
215
- components.forEach((c) => {
316
+ for (const [_, c] of components) {
216
317
  if (c.retainState) {
217
- // Do not call save/restore canvas draw state (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save) (ex. Group ctx.translate() affecting children)
218
- c.render(context);
318
+ retainStateComponents.push(c);
219
319
  } else {
220
- context.save();
221
- c.render(context);
222
- context.restore();
320
+ nonRetainStateComponents.push(c);
223
321
  }
322
+ }
323
+
324
+ // render retainState components on main canvas first
325
+ for (const c of retainStateComponents) {
326
+ c.render(context);
327
+ }
224
328
 
225
- // Delayed rendering using `activeCanvas` can cause a delay for tooltip interactivity for complex canvases (ex. country choropleth) so only ignore while moving/animating programmatically (ex. clicking on countries on Animated Globe)
226
- const inactiveMoving = !activeCanvas && $moving;
329
+ // store the main canvas transform after retainState components
330
+ const mainTransformAfterRetain = context.getTransform();
227
331
 
228
- const componentHasEvents = c.events && Object.values(c.events).filter((d) => d).length > 0;
332
+ // render non-retainState components on main canvas
333
+ for (const c of nonRetainStateComponents) {
334
+ context.save();
335
+ c.render(context);
336
+ context.restore();
337
+ }
229
338
 
230
- if (hitCanvasContext && componentHasEvents && !inactiveMoving && !$dragging) {
231
- const color = getColorStr(colorGenerator.next().value);
232
- // Stroking shape seems to help with dark border, but there is still antialising and thus gaps
233
- const styleOverrides = { styles: { fill: color, stroke: color, _fillOpacity: 0.1 } };
339
+ // sync hit canvas with main canvas
340
+ if (hitCanvasContext) {
341
+ // scale hit canvas to match main canvas
342
+ scaleCanvas(hitCanvasContext, ctx.containerWidth, ctx.containerHeight);
343
+ hitCanvasContext.clearRect(0, 0, ctx.containerWidth, ctx.containerHeight);
344
+
345
+ // reset and sync transform to the state after retainState components
346
+ hitCanvasContext.resetTransform();
347
+ hitCanvasContext.setTransform(mainTransformAfterRetain);
348
+
349
+ // reset color generator
350
+ colorGenerator = rgbColorGenerator();
351
+
352
+ const inactiveMoving = !activeCanvas && transformCtx.moving;
353
+
354
+ // render retainState components on hit canvas (e.g., Group)
355
+ for (const c of retainStateComponents) {
356
+ const componentHasEvents = c.events && Object.values(c.events).filter((d) => d).length > 0;
357
+
358
+ if (componentHasEvents && !inactiveMoving && !transformCtx.dragging) {
359
+ // since the transform was already applied via setTransform, skip rendering
360
+ // the retainState component's transform again; proceed to its children
361
+ continue;
362
+ }
363
+ }
364
+
365
+ // render non-retainState components on hit canvas
366
+ for (const c of nonRetainStateComponents) {
367
+ const componentHasEvents = c.events && Object.values(c.events).filter((d) => d).length > 0;
368
+
369
+ if (componentHasEvents && !inactiveMoving && !transformCtx.dragging) {
370
+ const color = getColorStr(colorGenerator.next().value);
371
+ const styleOverrides = { styles: { fill: color, stroke: color, _fillOpacity: 0.1 } };
234
372
 
235
- if (c.retainState) {
236
- c.render(hitCanvasContext, styleOverrides);
237
- } else {
238
373
  hitCanvasContext.save();
239
374
  c.render(hitCanvasContext, styleOverrides);
240
375
  hitCanvasContext.restore();
241
- }
242
376
 
243
- componentByColor.set(color, c);
377
+ componentByColor.set(color, c);
378
+ }
244
379
  }
245
- });
380
+ }
246
381
 
247
382
  pendingInvalidation = false;
248
383
  }
249
384
 
250
- const canvasContext: CanvasContext = {
251
- register(component) {
385
+ function createCanvasContext(): CanvasContextValue {
386
+ function register<T extends Element>(component: ComponentRender<T>) {
252
387
  const key = Symbol();
253
- components.set(key, component);
254
- this.invalidate();
388
+ components.set(key, component as ComponentRender<Element>);
389
+ invalidate();
390
+
391
+ const cleanupRoot = $effect.root(() => {
392
+ if (component.deps) {
393
+ $effect.pre(() => {
394
+ component.deps?.(); // track deps
395
+ invalidate(); // invalidate when deps change.
396
+ });
397
+ }
398
+ });
399
+
400
+ $effect.pre(() => {
401
+ return cleanupRoot;
402
+ });
255
403
 
256
- // Unregister
404
+ /**
405
+ * Removes the component from the registry and cleans up the invalidation
406
+ * effect
407
+ */
257
408
  return () => {
258
409
  components.delete(key);
259
- this.invalidate();
410
+ cleanupRoot();
411
+ invalidate();
260
412
  };
261
- },
262
- invalidate() {
413
+ }
414
+
415
+ function invalidate() {
263
416
  if (pendingInvalidation) return;
264
417
  pendingInvalidation = true;
265
418
  frameId = requestAnimationFrame(update);
266
- },
267
- };
419
+ }
268
420
 
269
- $: {
270
- // Redraw when resized or transform dragging changes. Note: adding `activeCanvas` (pointer enters/exits canvas) causes initial interactivity issues while canvas is rendering and is not needed
271
- $containerWidth, $containerHeight && $dragging;
272
- canvasContext.invalidate();
421
+ return { register, invalidate };
273
422
  }
274
423
 
424
+ const canvasContext = createCanvasContext();
425
+
426
+ $effect.pre(() => {
427
+ [ctx.height, ctx.width, ctx.containerHeight, ctx.containerWidth, transformCtx.dragging];
428
+ canvasContext.invalidate();
429
+ });
430
+
275
431
  setCanvasContext(canvasContext);
276
432
  setRenderContext('canvas');
277
433
  </script>
278
434
 
279
435
  <canvas
280
- bind:this={element}
436
+ bind:this={ref}
281
437
  style:z-index={zIndex}
282
438
  class={cls(
283
- 'layercake-layout-canvas',
439
+ layerClass('layout-canvas'),
284
440
  'absolute top-0 left-0 w-full h-full',
285
441
  pointerEvents === false && 'pointer-events-none',
286
- $$props.class
442
+ className
287
443
  )}
288
- aria-label={label}
289
- aria-labelledby={labelledBy}
290
- aria-describedby={describedBy}
291
- on:click={(e) => {
444
+ onclick={(e) => {
292
445
  const component = getPointerComponent(e);
293
446
  component?.events?.click?.(e);
447
+ onclick?.(e);
294
448
  }}
295
- on:click
296
- on:dblclick={(e) => {
449
+ ondblclick={(e) => {
297
450
  const component = getPointerComponent(e);
298
451
  component?.events?.dblclick?.(e);
452
+ ondblclick?.(e);
299
453
  }}
300
- on:pointerdown={(e) => {
454
+ onpointerdown={(e) => {
301
455
  const component = getPointerComponent(e);
302
456
  component?.events?.pointerdown?.(e);
457
+ onpointerdown?.(e);
458
+ }}
459
+ onpointerenter={(e) => {
460
+ onpointerenter?.(e);
461
+ onPointerMove(e);
462
+ }}
463
+ onpointermove={(e) => {
464
+ onpointermove?.(e);
465
+ onPointerMove(e);
466
+ }}
467
+ onpointerleave={(e) => {
468
+ onpointerleave?.(e);
469
+ onPointerLeave(e);
303
470
  }}
304
- on:pointerenter={onPointerMove}
305
- on:pointerenter
306
- on:pointermove={onPointerMove}
307
- on:pointermove
308
- on:pointerleave={onPointerLeave}
309
- on:pointerleave
310
- on:touchmove={(e) => {
471
+ ontouchmove={(e) => {
311
472
  // Prevent touch from interfering with pointer if over data
312
473
  if (lastActiveComponent) {
313
474
  e.preventDefault();
@@ -316,17 +477,22 @@
316
477
  const component = getPointerComponent(e);
317
478
  component?.events?.touchmove?.(e);
318
479
  }}
319
- on:touchmove
480
+ {...restProps}
320
481
  >
321
- <slot name="fallback">
322
- {fallback || ''}
323
- </slot>
482
+ {#if fallback}
483
+ {#if typeof fallback === 'function'}
484
+ {@render fallback()}
485
+ {:else}
486
+ {fallback}
487
+ {/if}
488
+ {/if}
324
489
  </canvas>
325
490
 
326
491
  <!-- Hit canvas used for hidden context -->
327
492
  <canvas
328
493
  bind:this={hitCanvasElement}
329
494
  class={cls(
495
+ layerClass('hit-canvas'),
330
496
  'layerchart-hitcanvas',
331
497
  'absolute top-0 left-0 w-full h-full',
332
498
  'pointer-events-none', // events all handled by main canvas
@@ -336,4 +502,4 @@
336
502
  )}
337
503
  ></canvas>
338
504
 
339
- <slot {element} {context}></slot>
505
+ {@render children?.({ ref, canvasContext: context })}