layerchart 2.0.0-next.3 → 2.0.0-next.30

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 (108) hide show
  1. package/dist/components/AnnotationPoint.svelte +16 -9
  2. package/dist/components/AnnotationRange.svelte +3 -3
  3. package/dist/components/Arc.svelte +2 -2
  4. package/dist/components/Axis.svelte +63 -14
  5. package/dist/components/Axis.svelte.d.ts +12 -2
  6. package/dist/components/Blur.svelte +5 -3
  7. package/dist/components/Blur.svelte.d.ts +2 -5
  8. package/dist/components/BrushContext.svelte +1 -1
  9. package/dist/components/Calendar.svelte +10 -6
  10. package/dist/components/Calendar.svelte.d.ts +2 -1
  11. package/dist/components/Chart.svelte +2 -2
  12. package/dist/components/Connector.svelte +2 -2
  13. package/dist/components/Connector.svelte.d.ts +1 -1
  14. package/dist/components/Ellipse.svelte +187 -0
  15. package/dist/components/Ellipse.svelte.d.ts +64 -0
  16. package/dist/components/ForceSimulation.svelte +168 -50
  17. package/dist/components/ForceSimulation.svelte.d.ts +80 -21
  18. package/dist/components/GeoPath.svelte +12 -5
  19. package/dist/components/GeoPoint.svelte +1 -2
  20. package/dist/components/GeoSpline.svelte +4 -4
  21. package/dist/components/GeoSpline.svelte.d.ts +1 -1
  22. package/dist/components/Group.svelte +2 -2
  23. package/dist/components/Highlight.svelte +2 -2
  24. package/dist/components/Hull.svelte +1 -1
  25. package/dist/components/Labels.svelte +3 -2
  26. package/dist/components/Labels.svelte.d.ts +2 -2
  27. package/dist/components/Legend.svelte +19 -12
  28. package/dist/components/Legend.svelte.d.ts +5 -5
  29. package/dist/components/MonthPath.svelte +14 -11
  30. package/dist/components/MonthPath.svelte.d.ts +4 -3
  31. package/dist/components/Polygon.svelte +285 -0
  32. package/dist/components/Polygon.svelte.d.ts +115 -0
  33. package/dist/components/RadialGradient.svelte +1 -3
  34. package/dist/components/Spline.svelte +30 -18
  35. package/dist/components/Spline.svelte.d.ts +12 -4
  36. package/dist/components/Text.svelte +62 -60
  37. package/dist/components/Text.svelte.d.ts +6 -0
  38. package/dist/components/TransformControls.svelte +16 -20
  39. package/dist/components/Treemap.svelte +63 -26
  40. package/dist/components/Treemap.svelte.d.ts +11 -11
  41. package/dist/components/Voronoi.svelte +51 -33
  42. package/dist/components/Voronoi.svelte.d.ts +3 -1
  43. package/dist/components/charts/ArcChart.svelte +5 -3
  44. package/dist/components/charts/AreaChart.svelte +11 -11
  45. package/dist/components/charts/BarChart.svelte +64 -53
  46. package/dist/components/charts/DefaultTooltip.svelte +1 -1
  47. package/dist/components/charts/LineChart.svelte +10 -6
  48. package/dist/components/charts/PieChart.svelte +5 -3
  49. package/dist/components/charts/ScatterChart.svelte +2 -3
  50. package/dist/components/charts/utils.svelte.d.ts +2 -2
  51. package/dist/components/charts/utils.svelte.js +5 -1
  52. package/dist/components/index.d.ts +4 -0
  53. package/dist/components/index.js +5 -1
  54. package/dist/components/layout/Canvas.svelte +67 -49
  55. package/dist/components/layout/Canvas.svelte.d.ts +6 -0
  56. package/dist/components/layout/Layer.svelte +6 -4
  57. package/dist/components/layout/Layer.svelte.d.ts +6 -4
  58. package/dist/components/tooltip/Tooltip.svelte +14 -7
  59. package/dist/components/tooltip/TooltipContext.svelte +78 -34
  60. package/dist/components/tooltip/TooltipContext.svelte.d.ts +3 -3
  61. package/dist/components/tooltip/TooltipHeader.svelte +5 -4
  62. package/dist/components/tooltip/TooltipHeader.svelte.d.ts +3 -3
  63. package/dist/components/tooltip/TooltipItem.svelte +5 -4
  64. package/dist/components/tooltip/TooltipItem.svelte.d.ts +3 -3
  65. package/dist/components/tooltip/TooltipList.svelte +1 -1
  66. package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
  67. package/dist/docs/Blockquote.svelte +6 -4
  68. package/dist/docs/Blockquote.svelte.d.ts +4 -19
  69. package/dist/docs/Code.svelte +20 -12
  70. package/dist/docs/Code.svelte.d.ts +9 -23
  71. package/dist/docs/Header1.svelte +4 -2
  72. package/dist/docs/Header1.svelte.d.ts +4 -28
  73. package/dist/docs/Json.svelte +11 -3
  74. package/dist/docs/Json.svelte.d.ts +9 -21
  75. package/dist/docs/Layout.svelte +10 -7
  76. package/dist/docs/Layout.svelte.d.ts +4 -19
  77. package/dist/docs/Link.svelte +7 -3
  78. package/dist/docs/Link.svelte.d.ts +4 -38
  79. package/dist/docs/Preview.svelte +6 -3
  80. package/dist/docs/TilesetField.svelte +20 -19
  81. package/dist/docs/TilesetField.svelte.d.ts +5 -22
  82. package/dist/docs/ViewSourceButton.svelte +9 -6
  83. package/dist/docs/ViewSourceButton.svelte.d.ts +7 -21
  84. package/dist/utils/arcText.svelte.js +4 -4
  85. package/dist/utils/array.d.ts +11 -0
  86. package/dist/utils/array.js +23 -0
  87. package/dist/utils/array.test.d.ts +1 -0
  88. package/dist/utils/array.test.js +200 -0
  89. package/dist/utils/canvas.d.ts +77 -0
  90. package/dist/utils/canvas.js +105 -41
  91. package/dist/utils/genData.d.ts +14 -0
  92. package/dist/utils/genData.js +24 -6
  93. package/dist/utils/index.d.ts +1 -0
  94. package/dist/utils/index.js +1 -0
  95. package/dist/utils/path.d.ts +10 -0
  96. package/dist/utils/path.js +30 -0
  97. package/dist/utils/scales.svelte.d.ts +3 -2
  98. package/dist/utils/scales.svelte.js +7 -3
  99. package/dist/utils/shape.d.ts +43 -0
  100. package/dist/utils/shape.js +59 -0
  101. package/dist/utils/string.d.ts +49 -0
  102. package/dist/utils/string.js +4 -2
  103. package/dist/utils/ticks.d.ts +15 -4
  104. package/dist/utils/ticks.js +140 -159
  105. package/dist/utils/ticks.test.js +6 -16
  106. package/dist/utils/treemap.d.ts +1 -1
  107. package/package.json +27 -25
  108. package/dist/utils/object.js +0 -2
@@ -88,23 +88,30 @@
88
88
  ? 'start'
89
89
  : 'middle',
90
90
  });
91
- </script>
92
91
 
93
- <Circle
94
- cx={point.x}
95
- cy={point.y}
96
- {r}
97
- onpointermove={(e) => {
92
+ function onPointerMove(e: PointerEvent | MouseEvent | TouchEvent) {
98
93
  if (details) {
99
94
  e.stopPropagation();
100
95
  ctx.tooltip.show(e, { annotation: { label, details } });
101
96
  }
102
- }}
103
- onpointerleave={() => {
97
+ }
98
+
99
+ function onPointerLeave(e: PointerEvent | MouseEvent | TouchEvent) {
104
100
  if (details) {
101
+ e.stopPropagation();
105
102
  ctx.tooltip.hide();
106
103
  }
107
- }}
104
+ }
105
+ </script>
106
+
107
+ <Circle
108
+ cx={point.x}
109
+ cy={point.y}
110
+ {r}
111
+ onmousemove={onPointerMove}
112
+ ontouchmove={onPointerMove}
113
+ onmouseleave={onPointerLeave}
114
+ ontouchend={onPointerLeave}
108
115
  {...props?.circle}
109
116
  class={cls('stroke-surface-100', props?.circle?.class)}
110
117
  />
@@ -118,13 +118,13 @@
118
118
  </script>
119
119
 
120
120
  {#if fill || className}
121
- <Rect {...rect} {fill} class={cls(props?.rect?.class, className)} />
121
+ <Rect {...rect} {...props?.rect} {fill} class={cls(props?.rect?.class, className)} />
122
122
  {/if}
123
123
 
124
124
  {#if gradient}
125
125
  <LinearGradient {...gradient}>
126
126
  {#snippet children({ gradient })}
127
- <Rect {...rect} fill={gradient} class={props?.rect?.class} />
127
+ <Rect {...rect} {...props?.rect} fill={gradient} />
128
128
  {/snippet}
129
129
  </LinearGradient>
130
130
  {/if}
@@ -132,7 +132,7 @@
132
132
  {#if pattern}
133
133
  <Pattern {...pattern}>
134
134
  {#snippet children({ pattern })}
135
- <Rect {...rect} fill={pattern} class={props?.rect?.class} />
135
+ <Rect {...rect} {...props?.rect} fill={pattern} />
136
136
  {/snippet}
137
137
  </Pattern>
138
138
  {/if}
@@ -401,13 +401,13 @@
401
401
  <Spline
402
402
  pathData={trackArc()}
403
403
  stroke="none"
404
- bind:splineRef={trackRef}
404
+ bind:pathRef={trackRef}
405
405
  {...extractLayerProps(track, 'arc-track')}
406
406
  />
407
407
  {/if}
408
408
 
409
409
  <Spline
410
- bind:splineRef={ref}
410
+ bind:pathRef={ref}
411
411
  pathData={arc()}
412
412
  transform="translate({xOffset}, {yOffset})"
413
413
  {fill}
@@ -43,6 +43,18 @@
43
43
  */
44
44
  ticks?: TicksConfig;
45
45
 
46
+ /**
47
+ * Width or height of each tick in pxiels (responsive reduce)
48
+ */
49
+ tickSpacing?: number;
50
+
51
+ /**
52
+ * Whether to render tick labels on multiple lines for additional context
53
+ *
54
+ * @default false
55
+ */
56
+ tickMultiline?: boolean;
57
+
46
58
  /**
47
59
  * Length of the tick line
48
60
  * @default 4
@@ -59,7 +71,7 @@
59
71
  /**
60
72
  * Format tick labels
61
73
  */
62
- format?: FormatType;
74
+ format?: FormatType | FormatConfig;
63
75
 
64
76
  /**
65
77
  * Props to apply to each tick label
@@ -114,7 +126,7 @@
114
126
  import { extent } from 'd3-array';
115
127
  import { pointRadial } from 'd3-shape';
116
128
 
117
- import { format as formatValue, type FormatType } from '@layerstack/utils';
129
+ import { type FormatType, type FormatConfig } from '@layerstack/utils';
118
130
  import { cls } from '@layerstack/tailwind';
119
131
 
120
132
  import Group, { type GroupProps } from './Group.svelte';
@@ -126,7 +138,7 @@
126
138
  import { getChartContext } from './Chart.svelte';
127
139
  import { extractLayerProps, layerClass } from '../utils/attributes.js';
128
140
  import { type MotionProp } from '../utils/motion.svelte.js';
129
- import { resolveTickVals, type TicksConfig } from '../utils/ticks.js';
141
+ import { resolveTickFormat, resolveTickVals, type TicksConfig } from '../utils/ticks.js';
130
142
 
131
143
  let {
132
144
  placement,
@@ -136,6 +148,12 @@
136
148
  rule = false,
137
149
  grid = false,
138
150
  ticks,
151
+ tickSpacing = ['top', 'bottom', 'angle'].includes(placement)
152
+ ? 80
153
+ : ['left', 'right', 'radius'].includes(placement)
154
+ ? 50
155
+ : undefined,
156
+ tickMultiline = false,
139
157
  tickLength = 4,
140
158
  tickMarks = true,
141
159
  format,
@@ -169,7 +187,36 @@
169
187
  const xRangeMinMax = $derived(extent<number>(ctx.xRange)) as [number, number];
170
188
  const yRangeMinMax = $derived(extent<number>(ctx.yRange)) as [number, number];
171
189
 
172
- const tickVals = $derived(resolveTickVals(scale, ticks, placement));
190
+ const ctxSize = $derived(
191
+ orientation === 'vertical'
192
+ ? ctx.height
193
+ : orientation === 'horizontal'
194
+ ? ctx.width
195
+ : orientation === 'radius'
196
+ ? ctx.height / 2
197
+ : orientation === 'angle'
198
+ ? ctx.width
199
+ : null
200
+ );
201
+
202
+ const tickCount = $derived(
203
+ typeof ticks === 'number'
204
+ ? ticks
205
+ : tickSpacing && ctxSize
206
+ ? Math.round(ctxSize / tickSpacing)
207
+ : undefined
208
+ );
209
+ const tickVals = $derived(resolveTickVals(scale, ticks, tickCount));
210
+ const tickFormat = $derived(
211
+ resolveTickFormat({
212
+ scale,
213
+ ticks,
214
+ count: tickCount,
215
+ formatType: format,
216
+ multiline: tickMultiline,
217
+ placement,
218
+ })
219
+ );
173
220
 
174
221
  function getCoords(tick: any) {
175
222
  switch (placement) {
@@ -217,14 +264,14 @@
217
264
  return {
218
265
  textAnchor: 'middle',
219
266
  verticalAnchor: 'end',
220
- dy: -tickLength - 2, // manually adjusted until Text supports custom styles
267
+ dy: -tickLength,
221
268
  };
222
269
 
223
270
  case 'bottom':
224
271
  return {
225
272
  textAnchor: 'middle',
226
273
  verticalAnchor: 'start',
227
- dy: tickLength, // manually adjusted until Text supports custom styles
274
+ dy: tickLength,
228
275
  };
229
276
 
230
277
  case 'left':
@@ -232,7 +279,6 @@
232
279
  textAnchor: 'end',
233
280
  verticalAnchor: 'middle',
234
281
  dx: -tickLength,
235
- dy: -2, // manually adjusted until Text supports custom styles
236
282
  };
237
283
 
238
284
  case 'right':
@@ -240,7 +286,6 @@
240
286
  textAnchor: 'start',
241
287
  verticalAnchor: 'middle',
242
288
  dx: tickLength,
243
- dy: -2, // manually adjusted until Text supports custom styles
244
289
  };
245
290
 
246
291
  case 'angle':
@@ -255,7 +300,7 @@
255
300
  ? 'end'
256
301
  : 'start',
257
302
  verticalAnchor: 'middle',
258
- dx: Math.sin(xValue) * (tickLength + 2),
303
+ dx: Math.sin(xValue) * tickLength,
259
304
  dy: -Math.cos(xValue) * (tickLength + 4), // manually adjusted until Text supports custom styles
260
305
  };
261
306
 
@@ -264,7 +309,6 @@
264
309
  textAnchor: 'middle',
265
310
  verticalAnchor: 'middle',
266
311
  dx: 2,
267
- dy: -2, // manually adjusted until Text supports custom styles
268
312
  };
269
313
  }
270
314
  }
@@ -317,13 +361,15 @@
317
361
  });
318
362
 
319
363
  const resolvedLabelProps = $derived({
320
- value: typeof label === 'function' ? '' : undefined,
364
+ value: typeof label === 'function' ? '' : label,
321
365
  x: resolvedLabelX,
322
366
  y: resolvedLabelY,
323
367
  textAnchor: resolvedLabelTextAnchor,
324
368
  verticalAnchor: resolvedLabelVerticalAnchor,
325
369
  rotate: orientation === 'vertical' && labelPlacement === 'middle' ? -90 : 0,
326
- capHeight: '.5rem', // text-[10px]
370
+ // complement 10px text (until Text supports custom styles)
371
+ capHeight: '7px',
372
+ lineHeight: '11px',
327
373
  ...labelProps,
328
374
  class: cls(
329
375
  layerClass('axis-label'),
@@ -356,7 +402,7 @@
356
402
  <Text {...resolvedLabelProps} />
357
403
  {/if}
358
404
 
359
- {#each tickVals as tick, index (tick.toString())}
405
+ {#each tickVals as tick, index (tick.valueOf())}
360
406
  {@const tickCoords = getCoords(tick)}
361
407
  {@const [radialTickCoordsX, radialTickCoordsY] = pointRadial(tickCoords.x, tickCoords.y)}
362
408
  {@const [radialTickMarkCoordsX, radialTickMarkCoordsY] = pointRadial(
@@ -366,9 +412,12 @@
366
412
  {@const resolvedTickLabelProps = {
367
413
  x: orientation === 'angle' ? radialTickCoordsX : tickCoords.x,
368
414
  y: orientation === 'angle' ? radialTickCoordsY : tickCoords.y,
369
- value: formatValue(tick, format ?? scale.tickFormat?.() ?? ((v) => v)),
415
+ value: tickFormat(tick, index),
370
416
  ...getDefaultTickLabelProps(tick),
371
417
  motion,
418
+ // complement 10px text (until Text supports custom styles)
419
+ capHeight: '7px',
420
+ lineHeight: '11px',
372
421
  ...tickLabelProps,
373
422
  class: cls(
374
423
  layerClass('axis-tick-label'),
@@ -36,6 +36,16 @@ export type AxisPropsWithoutHTML<In extends Transition = Transition> = {
36
36
  * Control the number of ticks
37
37
  */
38
38
  ticks?: TicksConfig;
39
+ /**
40
+ * Width or height of each tick in pxiels (responsive reduce)
41
+ */
42
+ tickSpacing?: number;
43
+ /**
44
+ * Whether to render tick labels on multiple lines for additional context
45
+ *
46
+ * @default false
47
+ */
48
+ tickMultiline?: boolean;
39
49
  /**
40
50
  * Length of the tick line
41
51
  * @default 4
@@ -50,7 +60,7 @@ export type AxisPropsWithoutHTML<In extends Transition = Transition> = {
50
60
  /**
51
61
  * Format tick labels
52
62
  */
53
- format?: FormatType;
63
+ format?: FormatType | FormatConfig;
54
64
  /**
55
65
  * Props to apply to each tick label
56
66
  */
@@ -92,7 +102,7 @@ export type AxisPropsWithoutHTML<In extends Transition = Transition> = {
92
102
  export type AxisProps<In extends Transition = Transition> = AxisPropsWithoutHTML<In> & Without<GroupProps, AxisPropsWithoutHTML<In>>;
93
103
  import { type ComponentProps, type Snippet } from 'svelte';
94
104
  import type { SVGAttributes } from 'svelte/elements';
95
- import { type FormatType } from '@layerstack/utils';
105
+ import { type FormatType, type FormatConfig } from '@layerstack/utils';
96
106
  import { type GroupProps } from './Group.svelte';
97
107
  import Rule from './Rule.svelte';
98
108
  import Text from './Text.svelte';
@@ -14,9 +14,9 @@
14
14
 
15
15
  /**
16
16
  * The default children snippet which provides
17
- * the id and url for the filter.
17
+ * the id for the filter.
18
18
  */
19
- children?: Snippet<[{ id: string; url: string }]>;
19
+ children?: Snippet;
20
20
  };
21
21
  </script>
22
22
 
@@ -42,7 +42,9 @@
42
42
 
43
43
  {#if children}
44
44
  <g filter="url(#{id})" class={layerClass('blur-g')}>
45
- {@render children({ id, url: `url(#${id})` })}
45
+ {@render children()}
46
46
  </g>
47
47
  {/if}
48
+ {:else if children}
49
+ {@render children()}
48
50
  {/if}
@@ -11,12 +11,9 @@ export type BlurProps = {
11
11
  stdDeviation?: number;
12
12
  /**
13
13
  * The default children snippet which provides
14
- * the id and url for the filter.
14
+ * the id for the filter.
15
15
  */
16
- children?: Snippet<[{
17
- id: string;
18
- url: string;
19
- }]>;
16
+ children?: Snippet;
20
17
  };
21
18
  import type { Snippet } from 'svelte';
22
19
  declare const Blur: import("svelte").Component<BlurProps, {}, "">;
@@ -319,7 +319,7 @@
319
319
  _range.width < RESET_THRESHOLD ||
320
320
  _range.height < RESET_THRESHOLD
321
321
  ) {
322
- // Clicked on frame, or pointer delta was <1
322
+ // Clicked on frame, or pointer delta was less than threshold (default: 1px)
323
323
  if (ignoreResetClick) {
324
324
  logger.debug('ignoring frame click reset');
325
325
  } else {
@@ -36,14 +36,14 @@
36
36
  /**
37
37
  * Props to pass to the `<text>` element for month labels.
38
38
  */
39
- monthLabel?: Partial<ComponentProps<typeof Text>>;
39
+ monthLabel?: boolean | Partial<ComponentProps<typeof Text>>;
40
40
 
41
41
  /**
42
42
  * Tooltip context to setup mouse events to show tooltip for related data
43
43
  */
44
44
  tooltipContext?: TooltipContextValue;
45
45
 
46
- children?: Snippet<[{ cells: CalendarCell[] }]>;
46
+ children?: Snippet<[{ cells: CalendarCell[]; cellSize: [number, number] }]>;
47
47
  } & Omit<
48
48
  RectPropsWithoutHTML,
49
49
  'children' | 'x' | 'y' | 'width' | 'height' | 'fill' | 'onpointermove' | 'onpointerleave'
@@ -57,7 +57,7 @@
57
57
  import { type ComponentProps, type Snippet } from 'svelte';
58
58
  import { timeDays, timeMonths, timeWeek, timeYear } from 'd3-time';
59
59
  import { index } from 'd3-array';
60
- import { format } from 'date-fns';
60
+ import { format } from '@layerstack/utils';
61
61
 
62
62
  import Rect, { type RectPropsWithoutHTML } from './Rect.svelte';
63
63
  import type { TooltipContextValue } from './tooltip/TooltipContext.svelte';
@@ -74,9 +74,9 @@
74
74
  start,
75
75
  cellSize: cellSizeProp,
76
76
  monthPath = false,
77
+ monthLabel = true,
77
78
  tooltipContext: tooltip,
78
79
  children,
79
- monthLabel,
80
80
  ...restProps
81
81
  }: CalendarPropsWithoutHTML = $props();
82
82
 
@@ -117,7 +117,7 @@
117
117
  </script>
118
118
 
119
119
  {#if children}
120
- {@render children({ cells })}
120
+ {@render children({ cells, cellSize })}
121
121
  {:else}
122
122
  {#each cells as cell}
123
123
  <Rect
@@ -136,11 +136,15 @@
136
136
  {#if monthPath}
137
137
  {#each yearMonths as date}
138
138
  <MonthPath {date} {cellSize} {...extractLayerProps(monthPath, 'calendar-month-path')} />
139
+ {/each}
140
+ {/if}
139
141
 
142
+ {#if monthLabel}
143
+ {#each yearMonths as date}
140
144
  <Text
141
145
  x={timeWeek.count(timeYear.floor(date), timeWeek.ceil(date)) * cellSize[0]}
142
146
  y={-4}
143
- value={format(date, 'MMM')}
147
+ value={format(date, 'month', { variant: 'short' })}
144
148
  {...extractLayerProps(monthLabel, 'calendar-month-label', 'text-xs')}
145
149
  />
146
150
  {/each}
@@ -30,13 +30,14 @@ export type CalendarPropsWithoutHTML = {
30
30
  /**
31
31
  * Props to pass to the `<text>` element for month labels.
32
32
  */
33
- monthLabel?: Partial<ComponentProps<typeof Text>>;
33
+ monthLabel?: boolean | Partial<ComponentProps<typeof Text>>;
34
34
  /**
35
35
  * Tooltip context to setup mouse events to show tooltip for related data
36
36
  */
37
37
  tooltipContext?: TooltipContextValue;
38
38
  children?: Snippet<[{
39
39
  cells: CalendarCell[];
40
+ cellSize: [number, number];
40
41
  }]>;
41
42
  } & Omit<RectPropsWithoutHTML, 'children' | 'x' | 'y' | 'width' | 'height' | 'fill' | 'onpointermove' | 'onpointerleave'>;
42
43
  export type CalendarProps = CalendarPropsWithoutHTML & Without<SVGAttributes<SVGRectElement>, CalendarPropsWithoutHTML>;
@@ -844,12 +844,12 @@
844
844
  if (verbose === true) {
845
845
  if (width <= 0 && isMounted === true) {
846
846
  console.warn(
847
- '[LayerChart] Target div has zero or negative width. Did you forget to set an explicit width in CSS on the container?'
847
+ `[LayerChart] Target div has zero or negative width (${width}). Did you forget to set an explicit width in CSS on the container?`
848
848
  );
849
849
  }
850
850
  if (height <= 0 && isMounted === true) {
851
851
  console.warn(
852
- '[LayerChart] Target div has zero or negative height. Did you forget to set an explicit height in CSS on the container?'
852
+ `[LayerChart] Target div has zero or negative height (${height}). Did you forget to set an explicit height in CSS on the container?`
853
853
  );
854
854
  }
855
855
  }
@@ -82,7 +82,7 @@
82
82
  type = 'rounded',
83
83
  radius = 20,
84
84
  curve = curveLinear,
85
- splineRef = $bindable(),
85
+ pathRef = $bindable(),
86
86
  pathData: pathDataProp,
87
87
  marker,
88
88
  markerStart,
@@ -137,7 +137,7 @@
137
137
 
138
138
  <Spline
139
139
  pathData={motionPath.current}
140
- bind:splineRef
140
+ bind:pathRef
141
141
  marker-start={markerStartId ? `url(#${markerStartId})` : undefined}
142
142
  marker-mid={markerMidId ? `url(#${markerMidId})` : undefined}
143
143
  marker-end={markerEndId ? `url(#${markerEndId})` : undefined}
@@ -46,6 +46,6 @@ import { type CurveFactory } from 'd3-shape';
46
46
  import { type ConnectorCoords, type ConnectorSweep, type ConnectorType } from '../utils/connectorUtils.js';
47
47
  import { type SplineProps, type SplinePropsWithoutHTML } from './Spline.svelte';
48
48
  import type { Without } from '../utils/types.js';
49
- declare const Connector: import("svelte").Component<ConnectorProps, {}, "splineRef">;
49
+ declare const Connector: import("svelte").Component<ConnectorProps, {}, "pathRef">;
50
50
  type Connector = ReturnType<typeof Connector>;
51
51
  export default Connector;
@@ -0,0 +1,187 @@
1
+ <script lang="ts" module>
2
+ import type { CommonStyleProps, Without } from '../utils/types.js';
3
+
4
+ export type EllipsePropsWithoutHTML = {
5
+ /**
6
+ * The center x position of the ellipse.
7
+ *
8
+ * @default 0
9
+ */
10
+ cx?: number;
11
+
12
+ /**
13
+ * The initial center x position of the ellipse.
14
+ *
15
+ * @default cx
16
+ */
17
+ initialCx?: number;
18
+
19
+ /**
20
+ * The center y position of the ellipse.
21
+ *
22
+ * @default 0
23
+ */
24
+ cy?: number;
25
+
26
+ /**
27
+ * The initial center y position of the ellipse.
28
+ *
29
+ * @default cy
30
+ */
31
+ initialCy?: number;
32
+
33
+ /**
34
+ * The radius of the ellipse on the x-axis.
35
+ *
36
+ * @default 1
37
+ */
38
+ rx?: number;
39
+
40
+ /**
41
+ * The initial radius of the ellipse on the x-axis.
42
+ *
43
+ * @default rx
44
+ */
45
+ initialRx?: number;
46
+
47
+ /**
48
+ * The radius of the ellipse on the y-axis.
49
+ *
50
+ * @default 1
51
+ */
52
+ ry?: number;
53
+
54
+ /**
55
+ * The initial radius of the ellipse on the y-axis.
56
+ *
57
+ * @default ry
58
+ */
59
+ initialRy?: number;
60
+
61
+ /**
62
+ * A bindable reference to the `<ellipse>` element
63
+ *
64
+ * @bindable
65
+ */
66
+ ref?: SVGEllipseElement;
67
+
68
+ motion?: MotionProp;
69
+ } & CommonStyleProps;
70
+
71
+ export type EllipseProps = EllipsePropsWithoutHTML &
72
+ Without<SVGAttributes<Element>, EllipsePropsWithoutHTML>;
73
+ </script>
74
+
75
+ <script lang="ts">
76
+ import { cls } from '@layerstack/tailwind';
77
+ import { merge } from 'lodash-es';
78
+
79
+ import { getRenderContext } from './Chart.svelte';
80
+ import { createMotion, type MotionProp } from '../utils/motion.svelte.js';
81
+ import { registerCanvasComponent } from './layout/Canvas.svelte';
82
+ import { renderEllipse, type ComputedStylesOptions } from '../utils/canvas.js';
83
+ import type { SVGAttributes } from 'svelte/elements';
84
+ import { createKey } from '../utils/key.svelte.js';
85
+ import { layerClass } from '../utils/attributes.js';
86
+
87
+ let {
88
+ cx = 0,
89
+ initialCx: initialCxProp,
90
+ cy = 0,
91
+ initialCy: initialCyProp,
92
+ rx = 1,
93
+ initialRx: initialRxProp,
94
+ ry = 1,
95
+ initialRy: initialRyProp,
96
+ motion,
97
+ fill,
98
+ fillOpacity,
99
+ stroke,
100
+ strokeWidth,
101
+ opacity,
102
+ class: className,
103
+ ref: refProp = $bindable(),
104
+ ...restProps
105
+ }: EllipseProps = $props();
106
+
107
+ let ref = $state<SVGEllipseElement>();
108
+
109
+ $effect.pre(() => {
110
+ refProp = ref;
111
+ });
112
+
113
+ const initialCx = initialCxProp ?? cx;
114
+ const initialCy = initialCyProp ?? cy;
115
+ const initialRx = initialRxProp ?? rx;
116
+ const initialRy = initialRyProp ?? ry;
117
+
118
+ const renderCtx = getRenderContext();
119
+
120
+ const motionCx = createMotion(initialCx, () => cx, motion);
121
+ const motionCy = createMotion(initialCy, () => cy, motion);
122
+ const motionRx = createMotion(initialRx, () => rx, motion);
123
+ const motionRy = createMotion(initialRy, () => ry, motion);
124
+
125
+ function render(
126
+ ctx: CanvasRenderingContext2D,
127
+ styleOverrides: ComputedStylesOptions | undefined
128
+ ) {
129
+ renderEllipse(
130
+ ctx,
131
+ { cx: motionCx.current, cy: motionCy.current, rx: motionRx.current, ry: motionRy.current },
132
+ styleOverrides
133
+ ? merge({ styles: { strokeWidth } }, styleOverrides)
134
+ : {
135
+ styles: { fill, fillOpacity, stroke, strokeWidth, opacity },
136
+ classes: className,
137
+ }
138
+ );
139
+ }
140
+
141
+ // TODO: Use objectId to work around Svelte 4 reactivity issue (even when memoizing gradients)
142
+ const fillKey = createKey(() => fill);
143
+ const strokeKey = createKey(() => stroke);
144
+
145
+ if (renderCtx === 'canvas') {
146
+ registerCanvasComponent({
147
+ name: 'Ellipse',
148
+ render,
149
+ events: {
150
+ click: restProps.onclick,
151
+ pointerdown: restProps.onpointerdown,
152
+ pointerenter: restProps.onpointerenter,
153
+ pointermove: restProps.onpointermove,
154
+ pointerleave: restProps.onpointerleave,
155
+ },
156
+ deps: () => [
157
+ motionCx.current,
158
+ motionCy.current,
159
+ motionRx.current,
160
+ motionRy.current,
161
+ fillKey.current,
162
+ fillOpacity,
163
+ strokeKey.current,
164
+ strokeWidth,
165
+ opacity,
166
+ className,
167
+ ],
168
+ });
169
+ }
170
+ </script>
171
+
172
+ {#if renderCtx === 'svg'}
173
+ <ellipse
174
+ bind:this={ref}
175
+ cx={motionCx.current}
176
+ cy={motionCy.current}
177
+ rx={motionRx.current}
178
+ ry={motionRy.current}
179
+ {fill}
180
+ fill-opacity={fillOpacity}
181
+ {stroke}
182
+ stroke-width={strokeWidth}
183
+ {opacity}
184
+ class={cls(layerClass('ellipse'), fill == null && 'fill-surface-content', className)}
185
+ {...restProps}
186
+ />
187
+ {/if}