layerchart 2.0.0-next.55 → 2.0.0-next.57

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 (55) hide show
  1. package/dist/bench/ComposableLineChart.svelte +1 -1
  2. package/dist/bench/GeoBench.svelte +1 -8
  3. package/dist/components/AnnotationRange.svelte +21 -8
  4. package/dist/components/Arc.svelte +1 -3
  5. package/dist/components/ArcLabel.svelte.test.js +7 -7
  6. package/dist/components/Bar.svelte +4 -2
  7. package/dist/components/BoxPlot.svelte +4 -12
  8. package/dist/components/Cell.svelte +13 -8
  9. package/dist/components/Chart.svelte +69 -26
  10. package/dist/components/ChartChildren.svelte +22 -4
  11. package/dist/components/Circle.svelte +34 -12
  12. package/dist/components/ClipPath.svelte +3 -9
  13. package/dist/components/Ellipse.svelte +27 -6
  14. package/dist/components/GeoLegend.svelte +1 -3
  15. package/dist/components/GeoPoint.svelte +25 -3
  16. package/dist/components/GeoSpline.svelte +1 -4
  17. package/dist/components/GeoTile.svelte +8 -4
  18. package/dist/components/Group.svelte +11 -5
  19. package/dist/components/Highlight.svelte +3 -3
  20. package/dist/components/Image.svelte +42 -30
  21. package/dist/components/Labels.svelte +2 -4
  22. package/dist/components/Line.svelte +7 -6
  23. package/dist/components/LinearGradient.svelte +8 -4
  24. package/dist/components/Link.svelte +0 -1
  25. package/dist/components/Marker.svelte +9 -1
  26. package/dist/components/Path.svelte +43 -23
  27. package/dist/components/Pattern.svelte +101 -5
  28. package/dist/components/Pattern.svelte.d.ts +3 -1
  29. package/dist/components/Pie.svelte +2 -6
  30. package/dist/components/RadialGradient.svelte +8 -4
  31. package/dist/components/Rect.svelte +29 -12
  32. package/dist/components/Spline.svelte +24 -6
  33. package/dist/components/Text.svelte +9 -5
  34. package/dist/components/Trail.svelte +19 -7
  35. package/dist/components/Vector.svelte +37 -14
  36. package/dist/components/Violin.svelte +1 -2
  37. package/dist/components/charts/ArcChart.svelte +8 -5
  38. package/dist/components/charts/AreaChart.svelte +6 -1
  39. package/dist/components/charts/BarChart.svelte +3 -1
  40. package/dist/components/charts/LineChart.svelte +6 -1
  41. package/dist/components/charts/PieChart.svelte +10 -3
  42. package/dist/components/tooltip/Tooltip.svelte +2 -8
  43. package/dist/contexts/chart.d.ts +1 -1
  44. package/dist/contexts/chart.js +3 -1
  45. package/dist/server/TestBarChart.svelte +28 -28
  46. package/dist/server/TestLineChart.svelte +28 -28
  47. package/dist/server/index.js +1 -1
  48. package/dist/states/brush.svelte.js +16 -13
  49. package/dist/states/chart.svelte.js +14 -4
  50. package/dist/states/chart.svelte.test.js +70 -19
  51. package/dist/states/geo.svelte.js +1 -4
  52. package/dist/states/series.svelte.js +1 -1
  53. package/dist/utils/canvas.js +7 -4
  54. package/dist/utils/trail.js +3 -4
  55. package/package.json +1 -1
@@ -258,9 +258,7 @@
258
258
  const width = $derived(Math.ceil(barWidth) + padding * 2);
259
259
  const svgHeight = $derived(titleHeight + height + tickLabelHeight + padding * 2 + 3);
260
260
  const barY = $derived(
261
- labelPlacement === 'top'
262
- ? titleHeight + padding + tickLabelHeight
263
- : titleHeight + padding
261
+ labelPlacement === 'top' ? titleHeight + padding + tickLabelHeight : titleHeight + padding
264
262
  );
265
263
  const tickLabelY = $derived(
266
264
  labelPlacement === 'top'
@@ -63,11 +63,25 @@
63
63
 
64
64
  {#if layerCtx === 'svg'}
65
65
  {#if children}
66
- <Group {x} {y} opacity={opacity as number} class={className as string} {...extractLayerProps(restProps, 'lc-geo-point-group')}>
66
+ <Group
67
+ {x}
68
+ {y}
69
+ opacity={opacity as number}
70
+ class={className as string}
71
+ {...extractLayerProps(restProps, 'lc-geo-point-group')}
72
+ >
67
73
  {@render children({ x, y })}
68
74
  </Group>
69
75
  {:else}
70
- <Circle cx={x} cy={y} {opacity} {fillOpacity} {strokeWidth} class={className} {...extractLayerProps(restProps, 'lc-geo-point')} />
76
+ <Circle
77
+ cx={x}
78
+ cy={y}
79
+ {opacity}
80
+ {fillOpacity}
81
+ {strokeWidth}
82
+ class={className}
83
+ {...extractLayerProps(restProps, 'lc-geo-point')}
84
+ />
71
85
  {/if}
72
86
  {/if}
73
87
 
@@ -78,6 +92,14 @@
78
92
  {@render children({ x, y })}
79
93
  <!-- </Group> -->
80
94
  {:else}
81
- <Circle cx={x} cy={y} {opacity} {fillOpacity} {strokeWidth} class={className} {...extractLayerProps(restProps, 'lc-geo-point')} />
95
+ <Circle
96
+ cx={x}
97
+ cy={y}
98
+ {opacity}
99
+ {fillOpacity}
100
+ {strokeWidth}
101
+ class={className}
102
+ {...extractLayerProps(restProps, 'lc-geo-point')}
103
+ />
82
104
  {/if}
83
105
  {/if}
@@ -75,7 +75,4 @@
75
75
  );
76
76
  </script>
77
77
 
78
- <Path
79
- pathData={d}
80
- {...extractLayerProps(restProps, 'lc-geo-spline')}
81
- />
78
+ <Path pathData={d} {...extractLayerProps(restProps, 'lc-geo-spline')} />
@@ -91,10 +91,14 @@
91
91
  }
92
92
 
93
93
  if (layerCtx === 'canvas') {
94
- ctx.registerComponent({ name: 'GeoTile', kind: 'mark', canvasRender: {
95
- render,
96
- deps: () => [tiles],
97
- } });
94
+ ctx.registerComponent({
95
+ name: 'GeoTile',
96
+ kind: 'mark',
97
+ canvasRender: {
98
+ render,
99
+ deps: () => [tiles],
100
+ },
101
+ });
98
102
  }
99
103
  </script>
100
104
 
@@ -137,9 +137,7 @@
137
137
  const dataMode = $derived(hasAnyDataProp(x, y));
138
138
 
139
139
  // Data to iterate over in data mode
140
- const resolvedData: any[] = $derived(
141
- dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []
142
- );
140
+ const resolvedData: any[] = $derived(dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []);
143
141
 
144
142
  // Resolve a single data item to pixel coordinates
145
143
  function resolveGroup(d: any) {
@@ -198,10 +196,18 @@
198
196
  const initialY = initialYProp ?? (typeof y === 'number' ? y : undefined);
199
197
 
200
198
  const trueX = $derived(
201
- typeof x === 'number' ? x : (x == null && (center === 'x' || center === true) ? chartCtx.width / 2 : 0)
199
+ typeof x === 'number'
200
+ ? x
201
+ : x == null && (center === 'x' || center === true)
202
+ ? chartCtx.width / 2
203
+ : 0
202
204
  );
203
205
  const trueY = $derived(
204
- typeof y === 'number' ? y : (y == null && (center === 'y' || center === true) ? chartCtx.height / 2 : 0)
206
+ typeof y === 'number'
207
+ ? y
208
+ : y == null && (center === 'y' || center === true)
209
+ ? chartCtx.height / 2
210
+ : 0
205
211
  );
206
212
  const motionX = createMotion(initialX, () => trueX, motion);
207
213
  const motionY = createMotion(initialY, () => trueY, motion);
@@ -389,9 +389,9 @@
389
389
  : null;
390
390
  // For diverging stacks, use the outer edge (y0 for below-baseline, y1 for above)
391
391
  const stackedY1 = stackValue
392
- ? (ctx.series.stackLayout === 'stackDiverging' && stackValue[1] <= 0
393
- ? stackValue[0]
394
- : stackValue[1])
392
+ ? ctx.series.stackLayout === 'stackDiverging' && stackValue[1] <= 0
393
+ ? stackValue[0]
394
+ : stackValue[1]
395
395
  : 0;
396
396
 
397
397
  if (ctx.valueAxis === 'x') {
@@ -195,16 +195,16 @@
195
195
  const geo = getGeoContext();
196
196
 
197
197
  // Data to iterate over in data mode
198
- const resolvedData: any[] = $derived(
199
- dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []
200
- );
198
+ const resolvedData: any[] = $derived(dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []);
201
199
 
202
200
  // Resolve a single data item to pixel coordinates and dimensions
203
201
  function resolveImage(d: any) {
204
202
  const resolvedR = r !== undefined ? resolveDataProp(r, d, null, 0) : undefined;
205
203
  const defaultSize = resolvedR !== undefined ? resolvedR * 2 : 16;
206
- const resolvedWidth = width !== undefined ? resolveDataProp(width, d, null, defaultSize) : defaultSize;
207
- const resolvedHeight = height !== undefined ? resolveDataProp(height, d, null, defaultSize) : defaultSize;
204
+ const resolvedWidth =
205
+ width !== undefined ? resolveDataProp(width, d, null, defaultSize) : defaultSize;
206
+ const resolvedHeight =
207
+ height !== undefined ? resolveDataProp(height, d, null, defaultSize) : defaultSize;
208
208
 
209
209
  let resolvedX: number, resolvedY: number;
210
210
  if (geo.projection) {
@@ -247,7 +247,14 @@
247
247
  const key = keyFn(d, i);
248
248
  activeKeys.add(key);
249
249
  const resolved = resolveImage(d);
250
- untrack(() => dataMotionMap.update(key, { x: resolved.x, y: resolved.y, width: resolved.width, height: resolved.height }));
250
+ untrack(() =>
251
+ dataMotionMap.update(key, {
252
+ x: resolved.x,
253
+ y: resolved.y,
254
+ width: resolved.width,
255
+ height: resolved.height,
256
+ })
257
+ );
251
258
  }
252
259
  untrack(() => dataMotionMap.cleanup(activeKeys));
253
260
  });
@@ -416,29 +423,32 @@
416
423
  y: typeof y === 'string' ? y : undefined,
417
424
  };
418
425
  },
419
- canvasRender: layerCtx === 'canvas' ? {
420
- render: canvasRender,
421
- events: {
422
- click: restProps.onclick,
423
- pointerdown: restProps.onpointerdown,
424
- pointerenter: restProps.onpointerenter,
425
- pointermove: restProps.onpointermove,
426
- pointerleave: restProps.onpointerleave,
427
- },
428
- deps: () => [
429
- dataMode,
430
- dataMode ? resolvedItems : null,
431
- motionX.current,
432
- motionY.current,
433
- motionWidth.current,
434
- motionHeight.current,
435
- href,
436
- opacity,
437
- className,
438
- restProps.style,
439
- loadedImageCount,
440
- ],
441
- } : undefined,
426
+ canvasRender:
427
+ layerCtx === 'canvas'
428
+ ? {
429
+ render: canvasRender,
430
+ events: {
431
+ click: restProps.onclick,
432
+ pointerdown: restProps.onpointerdown,
433
+ pointerenter: restProps.onpointerenter,
434
+ pointermove: restProps.onpointermove,
435
+ pointerleave: restProps.onpointerleave,
436
+ },
437
+ deps: () => [
438
+ dataMode,
439
+ dataMode ? resolvedItems : null,
440
+ motionX.current,
441
+ motionY.current,
442
+ motionWidth.current,
443
+ motionHeight.current,
444
+ href,
445
+ opacity,
446
+ className,
447
+ restProps.style,
448
+ loadedImageCount,
449
+ ],
450
+ }
451
+ : undefined,
442
452
  });
443
453
  </script>
444
454
 
@@ -487,7 +497,9 @@
487
497
  width={motionWidth.current}
488
498
  height={motionHeight.current}
489
499
  clip-path={pixelR !== undefined ? `url(#${clipId})` : undefined}
490
- transform={pixelRotate ? `rotate(${pixelRotate}, ${motionX.current}, ${motionY.current})` : undefined}
500
+ transform={pixelRotate
501
+ ? `rotate(${pixelRotate}, ${motionX.current}, ${motionY.current})`
502
+ : undefined}
491
503
  {preserveAspectRatio}
492
504
  crossorigin={crossOrigin}
493
505
  image-rendering={imageRendering}
@@ -173,8 +173,7 @@
173
173
  fill: fillValue,
174
174
  x: point.x + (placement === 'outside' ? -offset : offset),
175
175
  y: point.y,
176
- textAnchor:
177
- placement === 'middle' ? 'middle' : placement === 'outside' ? 'end' : 'start',
176
+ textAnchor: placement === 'middle' ? 'middle' : placement === 'outside' ? 'end' : 'start',
178
177
  verticalAnchor: 'middle',
179
178
  capHeight: '.6rem',
180
179
  };
@@ -185,8 +184,7 @@
185
184
  fill: fillValue,
186
185
  x: point.x + (placement === 'outside' ? offset : -offset),
187
186
  y: point.y,
188
- textAnchor:
189
- placement === 'middle' ? 'middle' : placement === 'outside' ? 'start' : 'end',
187
+ textAnchor: placement === 'middle' ? 'middle' : placement === 'outside' ? 'start' : 'end',
190
188
  verticalAnchor: 'middle',
191
189
  capHeight: '.6rem',
192
190
  };
@@ -298,12 +298,13 @@
298
298
  'lc-line',
299
299
  itemClass ?? (typeof className === 'string' ? className : undefined)
300
300
  ),
301
- style: [
302
- restProps.style as string | undefined,
303
- dashArrayAttr ? `stroke-dasharray: ${dashArrayAttr}` : undefined,
304
- ]
305
- .filter(Boolean)
306
- .join('; ') || undefined,
301
+ style:
302
+ [
303
+ restProps.style as string | undefined,
304
+ dashArrayAttr ? `stroke-dasharray: ${dashArrayAttr}` : undefined,
305
+ ]
306
+ .filter(Boolean)
307
+ .join('; ') || undefined,
307
308
  };
308
309
  }
309
310
 
@@ -174,10 +174,14 @@
174
174
  }
175
175
 
176
176
  if (layerCtx === 'canvas') {
177
- ctx.registerComponent({ name: 'Gradient', kind: 'group', canvasRender: {
178
- render,
179
- deps: () => [x1, y1, x2, y2, stops, className],
180
- } });
177
+ ctx.registerComponent({
178
+ name: 'Gradient',
179
+ kind: 'group',
180
+ canvasRender: {
181
+ render,
182
+ deps: () => [x1, y1, x2, y2, stops, className],
183
+ },
184
+ });
181
185
  }
182
186
  </script>
183
187
 
@@ -171,7 +171,6 @@ TODO:
171
171
  return FALLBACK_COORDS;
172
172
  }
173
173
  });
174
-
175
174
  </script>
176
175
 
177
176
  <Connector
@@ -8,7 +8,15 @@
8
8
  *
9
9
  * Pass `children` to render a custom element/component inside the marker instead.
10
10
  */
11
- type?: 'arrow' | 'triangle' | 'line' | 'circle' | 'circle-stroke' | 'dot' | 'square' | 'square-stroke';
11
+ type?:
12
+ | 'arrow'
13
+ | 'triangle'
14
+ | 'line'
15
+ | 'circle'
16
+ | 'circle-stroke'
17
+ | 'dot'
18
+ | 'square'
19
+ | 'square-stroke';
12
20
 
13
21
  /**
14
22
  * Unique identifier for the marker
@@ -197,30 +197,50 @@
197
197
  const strokeKey = layerCtx === 'canvas' ? createKey(() => stroke) : undefined;
198
198
 
199
199
  if (layerCtx === 'canvas') {
200
- ctx.registerComponent({ name: 'Path', kind: 'mark', canvasRender: {
201
- render,
202
- events: {
203
- get click() { return onclick; },
204
- get pointerenter() { return onpointerenter; },
205
- get pointermove() { return onpointermove; },
206
- get pointerleave() { return onpointerleave; },
207
- get pointerdown() { return onpointerdown; },
208
- get pointerover() { return onpointerover; },
209
- get pointerout() { return onpointerout; },
210
- get touchmove() { return ontouchmove; },
200
+ ctx.registerComponent({
201
+ name: 'Path',
202
+ kind: 'mark',
203
+ canvasRender: {
204
+ render,
205
+ events: {
206
+ get click() {
207
+ return onclick;
208
+ },
209
+ get pointerenter() {
210
+ return onpointerenter;
211
+ },
212
+ get pointermove() {
213
+ return onpointermove;
214
+ },
215
+ get pointerleave() {
216
+ return onpointerleave;
217
+ },
218
+ get pointerdown() {
219
+ return onpointerdown;
220
+ },
221
+ get pointerover() {
222
+ return onpointerover;
223
+ },
224
+ get pointerout() {
225
+ return onpointerout;
226
+ },
227
+ get touchmove() {
228
+ return ontouchmove;
229
+ },
230
+ },
231
+ deps: () => [
232
+ fillKey!.current,
233
+ fillOpacity,
234
+ strokeKey!.current,
235
+ strokeOpacity,
236
+ strokeWidth,
237
+ opacity,
238
+ className,
239
+ tweenedState.current,
240
+ restProps.style,
241
+ ],
211
242
  },
212
- deps: () => [
213
- fillKey!.current,
214
- fillOpacity,
215
- strokeKey!.current,
216
- strokeOpacity,
217
- strokeWidth,
218
- opacity,
219
- className,
220
- tweenedState.current,
221
- restProps.style,
222
- ],
223
- } });
243
+ });
224
244
  }
225
245
 
226
246
  let startPoint = $state<DOMPoint | undefined>();
@@ -95,7 +95,9 @@
95
95
  background?: string;
96
96
 
97
97
  /**
98
- * Render as a child of the pattern
98
+ * Render as a child of the pattern.
99
+ *
100
+ * Note: only supported on the `<Svg>` layer.
99
101
  */
100
102
  patternContent?: Snippet;
101
103
 
@@ -250,10 +252,102 @@
250
252
  }
251
253
 
252
254
  if (layerCtx === 'canvas') {
253
- chartCtx.registerComponent({ name: 'Pattern', kind: 'mark', canvasRender: {
254
- render,
255
- deps: () => [width, height, shapes, background],
256
- } });
255
+ chartCtx.registerComponent({
256
+ name: 'Pattern',
257
+ kind: 'group',
258
+ canvasRender: {
259
+ render,
260
+ deps: () => [width, height, shapes, background],
261
+ },
262
+ });
263
+ }
264
+
265
+ function withOpacity(color: string, opacity: number) {
266
+ return opacity === 1 ? color : `color-mix(in srgb, ${color} ${opacity * 100}%, transparent)`;
267
+ }
268
+
269
+ // Build a CSS `background` value from lines/circles/background.
270
+ // Uses repeating-linear-gradient for lines and radial-gradient for circles
271
+ // so CSS variables/classes resolve natively in the HTML layer.
272
+ function createCSSPattern(): string {
273
+ const layers: string[] = [];
274
+
275
+ if (linesProp) {
276
+ const lineDefs = Array.isArray(linesProp)
277
+ ? linesProp
278
+ : linesProp === true
279
+ ? [{}]
280
+ : [linesProp];
281
+ for (const line of lineDefs) {
282
+ const color = withOpacity(
283
+ line.color ?? 'var(--color-surface-content, currentColor)',
284
+ line.opacity ?? 1
285
+ );
286
+ const sw = line.width ?? 1;
287
+
288
+ let rotate = Math.round(line.rotate ?? 0) % 360;
289
+ if (rotate > 180) rotate = rotate - 360;
290
+ else if (rotate > 90) rotate = rotate - 180;
291
+ else if (rotate < -180) rotate = rotate + 360;
292
+ else if (rotate < -90) rotate = rotate + 180;
293
+
294
+ let angle: number;
295
+ let period: number;
296
+ if (rotate === 0) {
297
+ angle = 0;
298
+ period = height;
299
+ } else if (rotate === 90) {
300
+ angle = 90;
301
+ period = width;
302
+ } else if (rotate > 0) {
303
+ angle = 45;
304
+ period = (width * height) / Math.sqrt(width * width + height * height);
305
+ } else {
306
+ angle = 135;
307
+ period = (width * height) / Math.sqrt(width * width + height * height);
308
+ }
309
+
310
+ layers.push(
311
+ `repeating-linear-gradient(${angle}deg, ${color} 0 ${sw}px, transparent ${sw}px ${period}px)`
312
+ );
313
+ }
314
+ }
315
+
316
+ if (circlesProp) {
317
+ const circleDefs = Array.isArray(circlesProp)
318
+ ? circlesProp
319
+ : circlesProp === true
320
+ ? [{}]
321
+ : [circlesProp];
322
+ for (const circle of circleDefs) {
323
+ const color = withOpacity(
324
+ circle.color ?? 'var(--color-surface-content, currentColor)',
325
+ circle.opacity ?? 1
326
+ );
327
+ const r = circle.radius ?? 1;
328
+
329
+ if (circle.stagger) {
330
+ layers.push(
331
+ `radial-gradient(circle at 25% 25%, ${color} ${r}px, transparent ${r}px) 0 0 / ${size}px ${size}px`,
332
+ `radial-gradient(circle at 75% 75%, ${color} ${r}px, transparent ${r}px) 0 0 / ${size}px ${size}px`
333
+ );
334
+ } else {
335
+ layers.push(
336
+ `radial-gradient(circle at center, ${color} ${r}px, transparent ${r}px) 0 0 / ${size}px ${size}px`
337
+ );
338
+ }
339
+ }
340
+ }
341
+
342
+ // `background` may be either a plain color or an image value (e.g. `linear-gradient(...)`
343
+ // when used as `<Pattern background={gradient}>`). Images go in the image-layer list
344
+ // tiled at the pattern size (after shape layers so they paint underneath);
345
+ // colors go in the background-color slot.
346
+ const isImage = background != null && /gradient\(|url\(/i.test(background);
347
+ if (isImage) layers.push(`${background} 0 0 / ${width}px ${height}px`);
348
+
349
+ if (layers.length === 0) return background ?? 'transparent';
350
+ return !isImage && background ? `${layers.join(', ')}, ${background}` : layers.join(', ');
257
351
  }
258
352
  </script>
259
353
 
@@ -299,4 +393,6 @@
299
393
  </defs>
300
394
 
301
395
  {@render children?.({ id, pattern: `url(#${id})` })}
396
+ {:else if layerCtx === 'html'}
397
+ {@render children?.({ id, pattern: createCSSPattern() })}
302
398
  {/if}
@@ -75,7 +75,9 @@ export type PatternPropsWithoutHTML = {
75
75
  */
76
76
  background?: string;
77
77
  /**
78
- * Render as a child of the pattern
78
+ * Render as a child of the pattern.
79
+ *
80
+ * Note: only supported on the `<Svg>` layer.
79
81
  */
80
82
  patternContent?: Snippet;
81
83
  children?: Snippet<[{
@@ -109,9 +109,7 @@
109
109
 
110
110
  const endAngle = $derived(
111
111
  endAngleProp ??
112
- degreesToRadians(
113
- (ctx.config.xRange ? max(ctx.config.xRange as number[]) : max(range))!
114
- )
112
+ degreesToRadians((ctx.config.xRange ? max(ctx.config.xRange as number[]) : max(range))!)
115
113
  );
116
114
 
117
115
  const motionEndAngle = createMotion(0, () => endAngle, motion);
@@ -120,9 +118,7 @@
120
118
  let _pie = d3pie<any>()
121
119
  .startAngle(
122
120
  startAngleProp ??
123
- degreesToRadians(
124
- (ctx.config.xRange ? min(ctx.config.xRange as number[]) : min(range))!
125
- )
121
+ degreesToRadians((ctx.config.xRange ? min(ctx.config.xRange as number[]) : min(range))!)
126
122
  )
127
123
  .endAngle(motionEndAngle.current)
128
124
  .padAngle(padAngle)
@@ -144,10 +144,14 @@
144
144
  }
145
145
 
146
146
  if (layerCtx === 'canvas') {
147
- ctx.registerComponent({ name: 'Gradient', kind: 'group', canvasRender: {
148
- render,
149
- deps: () => [stops, cx, cy, fx, fy, ctx.width, ctx.height],
150
- } });
147
+ ctx.registerComponent({
148
+ name: 'Gradient',
149
+ kind: 'group',
150
+ canvasRender: {
151
+ render,
152
+ deps: () => [stops, cx, cy, fx, fy, ctx.width, ctx.height],
153
+ },
154
+ });
151
155
  }
152
156
  </script>
153
157