layerchart 2.0.0-next.4 → 2.0.0-next.41

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 (180) hide show
  1. package/dist/components/AnnotationLine.svelte +15 -2
  2. package/dist/components/AnnotationPoint.svelte +29 -11
  3. package/dist/components/AnnotationRange.svelte +18 -4
  4. package/dist/components/Arc.svelte +5 -5
  5. package/dist/components/Area.svelte +10 -2
  6. package/dist/components/Axis.svelte +175 -58
  7. package/dist/components/Axis.svelte.d.ts +23 -6
  8. package/dist/components/Bar.svelte +20 -15
  9. package/dist/components/Bar.svelte.d.ts +2 -2
  10. package/dist/components/Bars.svelte +4 -4
  11. package/dist/components/Blur.svelte +7 -6
  12. package/dist/components/Blur.svelte.d.ts +2 -5
  13. package/dist/components/BrushContext.svelte +45 -45
  14. package/dist/components/Calendar.svelte +31 -10
  15. package/dist/components/Calendar.svelte.d.ts +2 -1
  16. package/dist/components/Chart.svelte +76 -27
  17. package/dist/components/Chart.svelte.d.ts +26 -8
  18. package/dist/components/ChartClipPath.svelte +1 -1
  19. package/dist/components/Circle.svelte +44 -3
  20. package/dist/components/CircleClipPath.svelte +8 -1
  21. package/dist/components/ClipPath.svelte +1 -2
  22. package/dist/components/ColorRamp.svelte +1 -1
  23. package/dist/components/ComputedStyles.svelte +9 -2
  24. package/dist/components/Connector.svelte +3 -3
  25. package/dist/components/Connector.svelte.d.ts +1 -1
  26. package/dist/components/Ellipse.svelte +228 -0
  27. package/dist/components/Ellipse.svelte.d.ts +64 -0
  28. package/dist/components/ForceSimulation.svelte +184 -50
  29. package/dist/components/ForceSimulation.svelte.d.ts +95 -21
  30. package/dist/components/Frame.svelte +1 -1
  31. package/dist/components/GeoCircle.svelte +1 -1
  32. package/dist/components/GeoEdgeFade.svelte +1 -1
  33. package/dist/components/GeoPath.svelte +30 -8
  34. package/dist/components/GeoPoint.svelte +4 -5
  35. package/dist/components/GeoSpline.svelte +5 -5
  36. package/dist/components/GeoSpline.svelte.d.ts +1 -1
  37. package/dist/components/GeoTile.svelte +1 -1
  38. package/dist/components/Graticule.svelte +5 -5
  39. package/dist/components/Grid.svelte +60 -63
  40. package/dist/components/Group.svelte +13 -8
  41. package/dist/components/Group.svelte.d.ts +10 -3
  42. package/dist/components/Highlight.svelte +55 -28
  43. package/dist/components/Highlight.svelte.d.ts +4 -0
  44. package/dist/components/Hull.svelte +12 -5
  45. package/dist/components/Labels.svelte +24 -13
  46. package/dist/components/Labels.svelte.d.ts +12 -5
  47. package/dist/components/Legend.svelte +143 -70
  48. package/dist/components/Legend.svelte.d.ts +12 -8
  49. package/dist/components/Line.svelte +40 -3
  50. package/dist/components/LinearGradient.svelte +35 -4
  51. package/dist/components/Link.svelte +1 -1
  52. package/dist/components/Marker.svelte +37 -26
  53. package/dist/components/MonthPath.svelte +26 -12
  54. package/dist/components/MonthPath.svelte.d.ts +4 -3
  55. package/dist/components/MotionPath.svelte +1 -1
  56. package/dist/components/Pack.svelte.d.ts +10 -3
  57. package/dist/components/Partition.svelte.d.ts +10 -3
  58. package/dist/components/Pattern.svelte +5 -5
  59. package/dist/components/Pie.svelte +1 -2
  60. package/dist/components/Points.svelte +11 -72
  61. package/dist/components/Points.svelte.d.ts +1 -8
  62. package/dist/components/Polygon.svelte +309 -0
  63. package/dist/components/Polygon.svelte.d.ts +115 -0
  64. package/dist/components/RadialGradient.svelte +4 -6
  65. package/dist/components/Rect.svelte +55 -5
  66. package/dist/components/Rect.svelte.d.ts +2 -2
  67. package/dist/components/RectClipPath.svelte +4 -3
  68. package/dist/components/RectClipPath.svelte.d.ts +2 -2
  69. package/dist/components/Rule.svelte +167 -77
  70. package/dist/components/Rule.svelte.d.ts +7 -2
  71. package/dist/components/Spline.svelte +59 -28
  72. package/dist/components/Spline.svelte.d.ts +12 -4
  73. package/dist/components/Text.svelte +121 -73
  74. package/dist/components/Text.svelte.d.ts +6 -0
  75. package/dist/components/TileImage.svelte +19 -4
  76. package/dist/components/TransformContext.svelte +9 -3
  77. package/dist/components/TransformControls.svelte +89 -38
  78. package/dist/components/Tree.svelte.d.ts +10 -3
  79. package/dist/components/Treemap.svelte +63 -26
  80. package/dist/components/Treemap.svelte.d.ts +21 -14
  81. package/dist/components/Voronoi.svelte +12 -13
  82. package/dist/components/charts/ArcChart.svelte +43 -71
  83. package/dist/components/charts/ArcChart.svelte.d.ts +10 -3
  84. package/dist/components/charts/AreaChart.svelte +29 -59
  85. package/dist/components/charts/AreaChart.svelte.d.ts +10 -3
  86. package/dist/components/charts/BarChart.svelte +79 -71
  87. package/dist/components/charts/BarChart.svelte.d.ts +10 -3
  88. package/dist/components/charts/DefaultTooltip.svelte +3 -3
  89. package/dist/components/charts/DefaultTooltip.svelte.d.ts +1 -1
  90. package/dist/components/charts/LineChart.svelte +69 -75
  91. package/dist/components/charts/LineChart.svelte.d.ts +21 -8
  92. package/dist/components/charts/PieChart.svelte +44 -71
  93. package/dist/components/charts/PieChart.svelte.d.ts +10 -3
  94. package/dist/components/charts/ScatterChart.svelte +10 -39
  95. package/dist/components/charts/ScatterChart.svelte.d.ts +10 -3
  96. package/dist/components/charts/utils.svelte.d.ts +1 -19
  97. package/dist/components/charts/utils.svelte.js +7 -35
  98. package/dist/components/index.d.ts +4 -0
  99. package/dist/components/index.js +5 -1
  100. package/dist/components/layout/Canvas.svelte +96 -69
  101. package/dist/components/layout/Canvas.svelte.d.ts +6 -0
  102. package/dist/components/layout/Html.svelte +15 -9
  103. package/dist/components/layout/Layer.svelte +6 -4
  104. package/dist/components/layout/Layer.svelte.d.ts +6 -4
  105. package/dist/components/layout/Svg.svelte +19 -11
  106. package/dist/components/layout/WebGL.svelte +26 -6
  107. package/dist/components/layout/WebGL.svelte.d.ts +5 -2
  108. package/dist/components/tooltip/Tooltip.svelte +73 -36
  109. package/dist/components/tooltip/Tooltip.svelte.d.ts +10 -3
  110. package/dist/components/tooltip/TooltipContext.svelte +167 -54
  111. package/dist/components/tooltip/TooltipContext.svelte.d.ts +19 -5
  112. package/dist/components/tooltip/TooltipHeader.svelte +32 -18
  113. package/dist/components/tooltip/TooltipHeader.svelte.d.ts +3 -3
  114. package/dist/components/tooltip/TooltipItem.svelte +46 -37
  115. package/dist/components/tooltip/TooltipItem.svelte.d.ts +3 -3
  116. package/dist/components/tooltip/TooltipList.svelte +12 -10
  117. package/dist/components/tooltip/TooltipSeparator.svelte +18 -10
  118. package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
  119. package/dist/docs/Blockquote.svelte +6 -4
  120. package/dist/docs/Blockquote.svelte.d.ts +4 -19
  121. package/dist/docs/Code.svelte +70 -28
  122. package/dist/docs/Code.svelte.d.ts +9 -24
  123. package/dist/docs/Header1.svelte +4 -2
  124. package/dist/docs/Header1.svelte.d.ts +4 -28
  125. package/dist/docs/Json.svelte +11 -3
  126. package/dist/docs/Json.svelte.d.ts +9 -21
  127. package/dist/docs/Layout.svelte +10 -7
  128. package/dist/docs/Layout.svelte.d.ts +4 -19
  129. package/dist/docs/Link.svelte +7 -3
  130. package/dist/docs/Link.svelte.d.ts +4 -38
  131. package/dist/docs/Preview.svelte +22 -23
  132. package/dist/docs/Preview.svelte.d.ts +5 -6
  133. package/dist/docs/TilesetField.svelte +20 -19
  134. package/dist/docs/TilesetField.svelte.d.ts +5 -22
  135. package/dist/docs/ViewSourceButton.svelte +10 -7
  136. package/dist/docs/ViewSourceButton.svelte.d.ts +7 -21
  137. package/dist/states/series.svelte.d.ts +30 -0
  138. package/dist/states/series.svelte.js +54 -0
  139. package/dist/styles/daisyui-5.css +6 -0
  140. package/dist/styles/shadcn-svelte.css +11 -0
  141. package/dist/styles/skeleton-3.css +15 -0
  142. package/dist/utils/arcText.svelte.js +4 -4
  143. package/dist/utils/array.d.ts +11 -0
  144. package/dist/utils/array.js +23 -0
  145. package/dist/utils/array.test.d.ts +1 -0
  146. package/dist/utils/array.test.js +200 -0
  147. package/dist/utils/attributes.d.ts +3 -13
  148. package/dist/utils/attributes.js +4 -18
  149. package/dist/utils/canvas.d.ts +77 -0
  150. package/dist/utils/canvas.js +105 -41
  151. package/dist/utils/common.d.ts +9 -0
  152. package/dist/utils/common.js +18 -1
  153. package/dist/utils/common.test.js +26 -1
  154. package/dist/utils/genData.d.ts +22 -8
  155. package/dist/utils/genData.js +34 -14
  156. package/dist/utils/graph/dagre.d.ts +4 -4
  157. package/dist/utils/graph/dagre.js +5 -7
  158. package/dist/utils/index.d.ts +1 -0
  159. package/dist/utils/index.js +1 -0
  160. package/dist/utils/math.d.ts +17 -0
  161. package/dist/utils/math.js +17 -0
  162. package/dist/utils/motion.svelte.js +1 -1
  163. package/dist/utils/path.d.ts +10 -0
  164. package/dist/utils/path.js +30 -0
  165. package/dist/utils/rect.svelte.d.ts +2 -2
  166. package/dist/utils/rect.svelte.js +73 -1
  167. package/dist/utils/scales.svelte.d.ts +9 -3
  168. package/dist/utils/scales.svelte.js +47 -4
  169. package/dist/utils/shape.d.ts +43 -0
  170. package/dist/utils/shape.js +59 -0
  171. package/dist/utils/stack.js +1 -1
  172. package/dist/utils/string.d.ts +49 -0
  173. package/dist/utils/string.js +4 -2
  174. package/dist/utils/ticks.d.ts +15 -4
  175. package/dist/utils/ticks.js +140 -159
  176. package/dist/utils/ticks.test.js +16 -26
  177. package/dist/utils/treemap.d.ts +1 -1
  178. package/dist/utils/types.d.ts +15 -2
  179. package/package.json +36 -35
  180. package/dist/utils/object.js +0 -2
@@ -130,7 +130,7 @@
130
130
  x2={line.x2}
131
131
  y2={line.y2}
132
132
  {...props?.line}
133
- class={cls('stroke-surface-content', props?.line?.class)}
133
+ class={cls('lc-annotation-line', props?.line?.class)}
134
134
  />
135
135
 
136
136
  {#if label}
@@ -138,6 +138,19 @@
138
138
  value={label}
139
139
  {...labelProps}
140
140
  {...props?.label}
141
- class={cls('text-xs pointer-events-none', props?.label?.class)}
141
+ class={cls('lc-annotation-line-label', props?.label?.class)}
142
142
  />
143
143
  {/if}
144
+
145
+ <style>
146
+ @layer components {
147
+ :global(:where(.lc-annotation-line)) {
148
+ --stroke-color: var(--color-surface-content, currentColor);
149
+ }
150
+
151
+ :global(:where(.lc-annotation-line-label)) {
152
+ font-size: 12px;
153
+ pointer-events: none;
154
+ }
155
+ }
156
+ </style>
@@ -88,25 +88,34 @@
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
+ onpointermove={onPointerMove}
112
+ onmousemove={onPointerMove}
113
+ ontouchmove={onPointerMove}
114
+ onpointerleave={onPointerLeave}
115
+ onmouseleave={onPointerLeave}
116
+ ontouchend={onPointerLeave}
108
117
  {...props?.circle}
109
- class={cls('stroke-surface-100', props?.circle?.class)}
118
+ class={cls('lc-annotation-point', props?.circle?.class)}
110
119
  />
111
120
 
112
121
  {#if label}
@@ -114,6 +123,15 @@
114
123
  value={label}
115
124
  {...labelProps}
116
125
  {...props?.label}
117
- class={cls('text-xs pointer-events-none', props?.label?.class)}
126
+ class={cls('lc-annotation-point-label', props?.label?.class)}
118
127
  />
119
128
  {/if}
129
+
130
+ <style>
131
+ @layer components {
132
+ :global(:where(.lc-annotation-point-label)) {
133
+ font-size: 12px;
134
+ pointer-events: none;
135
+ }
136
+ }
137
+ </style>
@@ -118,13 +118,18 @@
118
118
  </script>
119
119
 
120
120
  {#if fill || className}
121
- <Rect {...rect} {fill} class={cls(props?.rect?.class, className)} />
121
+ <Rect
122
+ {...rect}
123
+ {...props?.rect}
124
+ {fill}
125
+ class={cls('lc-annotation-range', props?.rect?.class, className)}
126
+ />
122
127
  {/if}
123
128
 
124
129
  {#if gradient}
125
130
  <LinearGradient {...gradient}>
126
131
  {#snippet children({ gradient })}
127
- <Rect {...rect} fill={gradient} class={props?.rect?.class} />
132
+ <Rect {...rect} {...props?.rect} fill={gradient} />
128
133
  {/snippet}
129
134
  </LinearGradient>
130
135
  {/if}
@@ -132,7 +137,7 @@
132
137
  {#if pattern}
133
138
  <Pattern {...pattern}>
134
139
  {#snippet children({ pattern })}
135
- <Rect {...rect} fill={pattern} class={props?.rect?.class} />
140
+ <Rect {...rect} {...props?.rect} fill={pattern} />
136
141
  {/snippet}
137
142
  </Pattern>
138
143
  {/if}
@@ -142,6 +147,15 @@
142
147
  value={label}
143
148
  {...labelProps}
144
149
  {...props?.label}
145
- class={cls('text-xs pointer-events-none', props?.label?.class)}
150
+ class={cls('lc-annotation-range-label', props?.label?.class)}
146
151
  />
147
152
  {/if}
153
+
154
+ <style>
155
+ @layer components {
156
+ :global(:where(.lc-annotation-range-label)) {
157
+ font-size: 12px;
158
+ pointer-events: none;
159
+ }
160
+ }
161
+ </style>
@@ -189,7 +189,7 @@
189
189
 
190
190
  import { degreesToRadians } from '../utils/math.js';
191
191
  import { getChartContext } from './Chart.svelte';
192
- import { extractLayerProps, layerClass } from '../utils/attributes.js';
192
+ import { extractLayerProps } from '../utils/attributes.js';
193
193
  import { cls } from '@layerstack/tailwind';
194
194
  import { max } from 'd3-array';
195
195
  import {
@@ -401,13 +401,13 @@
401
401
  <Spline
402
402
  pathData={trackArc()}
403
403
  stroke="none"
404
- bind:splineRef={trackRef}
405
- {...extractLayerProps(track, 'arc-track')}
404
+ bind:pathRef={trackRef}
405
+ {...extractLayerProps(track, 'lc-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}
@@ -416,7 +416,7 @@
416
416
  stroke-width={strokeWidth}
417
417
  {opacity}
418
418
  {...restProps}
419
- class={cls(layerClass('arc-line'), className)}
419
+ class={cls('lc-arc-line', className)}
420
420
  onpointerenter={onPointerEnter}
421
421
  onpointermove={onPointerMove}
422
422
  onpointerleave={onPointerLeave}
@@ -239,7 +239,15 @@
239
239
  </script>
240
240
 
241
241
  {#if line}
242
- <Spline {data} {x} y={y1} {curve} {defined} {motion} {...extractLayerProps(line, 'area-line')} />
242
+ <Spline
243
+ {data}
244
+ {x}
245
+ y={y1}
246
+ {curve}
247
+ {defined}
248
+ {motion}
249
+ {...extractLayerProps(line, 'lc-area-line')}
250
+ />
243
251
  {/if}
244
252
 
245
253
  {#if renderCtx === 'svg'}
@@ -251,6 +259,6 @@
251
259
  {stroke}
252
260
  stroke-width={strokeWidth}
253
261
  {opacity}
254
- {...extractLayerProps(restProps, 'area-path')}
262
+ {...extractLayerProps(restProps, 'lc-area-path')}
255
263
  />
256
264
  {/if}
@@ -43,6 +43,18 @@
43
43
  */
44
44
  ticks?: TicksConfig;
45
45
 
46
+ /**
47
+ * Width or height of each tick in pixels (enabling responsive count)
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
@@ -84,7 +96,7 @@
84
96
  transitionInParams?: TransitionParams<In>;
85
97
 
86
98
  /**
87
- * Scale for the axis
99
+ * Override scale for the axis
88
100
  */
89
101
  scale?: any;
90
102
 
@@ -113,8 +125,17 @@
113
125
 
114
126
  import { extent } from 'd3-array';
115
127
  import { pointRadial } from 'd3-shape';
116
-
117
- import { format as formatValue, type FormatType } from '@layerstack/utils';
128
+ import {
129
+ timeDay,
130
+ timeHour,
131
+ timeMillisecond,
132
+ timeMinute,
133
+ timeMonth,
134
+ timeSecond,
135
+ timeYear,
136
+ } from 'd3-time';
137
+
138
+ import { type FormatType, type FormatConfig, unique, PeriodType } from '@layerstack/utils';
118
139
  import { cls } from '@layerstack/tailwind';
119
140
 
120
141
  import Group, { type GroupProps } from './Group.svelte';
@@ -124,9 +145,9 @@
124
145
  import { isScaleBand } from '../utils/scales.svelte.js';
125
146
 
126
147
  import { getChartContext } from './Chart.svelte';
127
- import { extractLayerProps, layerClass } from '../utils/attributes.js';
148
+ import { extractLayerProps } from '../utils/attributes.js';
128
149
  import { type MotionProp } from '../utils/motion.svelte.js';
129
- import { resolveTickVals, type TicksConfig } from '../utils/ticks.js';
150
+ import { autoTickVals, autoTickFormat, type TicksConfig } from '../utils/ticks.js';
130
151
 
131
152
  let {
132
153
  placement,
@@ -136,6 +157,12 @@
136
157
  rule = false,
137
158
  grid = false,
138
159
  ticks,
160
+ tickSpacing = ['top', 'bottom', 'angle'].includes(placement)
161
+ ? 80
162
+ : ['left', 'right', 'radius'].includes(placement)
163
+ ? 50
164
+ : undefined,
165
+ tickMultiline = false,
139
166
  tickLength = 4,
140
167
  tickMarks = true,
141
168
  format,
@@ -165,36 +192,107 @@
165
192
  const scale = $derived(
166
193
  scaleProp ?? (['horizontal', 'angle'].includes(orientation) ? ctx.xScale : ctx.yScale)
167
194
  );
195
+ const interval = $derived(
196
+ ['horizontal', 'angle'].includes(orientation) ? ctx.xInterval : ctx.yInterval
197
+ );
168
198
 
169
199
  const xRangeMinMax = $derived(extent<number>(ctx.xRange)) as [number, number];
170
200
  const yRangeMinMax = $derived(extent<number>(ctx.yRange)) as [number, number];
171
201
 
172
- const tickVals = $derived(resolveTickVals(scale, ticks, placement));
202
+ const ctxSize = $derived(
203
+ orientation === 'vertical'
204
+ ? ctx.height
205
+ : orientation === 'horizontal'
206
+ ? ctx.width
207
+ : orientation === 'radius'
208
+ ? ctx.height / 2
209
+ : orientation === 'angle'
210
+ ? ctx.width
211
+ : null
212
+ );
213
+
214
+ const tickCount = $derived(
215
+ typeof ticks === 'number'
216
+ ? ticks
217
+ : tickSpacing && ctxSize
218
+ ? Math.round(ctxSize / tickSpacing)
219
+ : undefined
220
+ );
221
+ const tickVals = $derived.by(() => {
222
+ let tickVals = autoTickVals(scale, ticks, tickCount);
223
+
224
+ if (interval != null) {
225
+ // Remove last tick when interval is provided (such as for bar charts with center aligned (offset) ticks)
226
+ tickVals.pop();
227
+ }
228
+
229
+ // Use format to filter ticks (helpful to keep ticks above a threshold for wide charts or short durations)
230
+ const formatType = typeof format === 'object' ? format?.type : format;
231
+
232
+ if (formatType === 'integer') {
233
+ tickVals = tickVals.filter(Number.isInteger);
234
+ } else if (formatType === 'year' || formatType === PeriodType.CalendarYear) {
235
+ tickVals = tickVals.filter((val) => +timeYear.floor(val) === +val);
236
+ } else if (
237
+ formatType === 'month' ||
238
+ formatType === PeriodType.Month ||
239
+ formatType === PeriodType.MonthYear
240
+ ) {
241
+ // tickVals = tickVals.filter((val) => +timeMonth.floor(val) === +val);
242
+ tickVals = tickVals.filter((val) => val.getDate() < 7); // first week of the month
243
+ } else if (formatType === 'day' || formatType === PeriodType.Day) {
244
+ tickVals = tickVals.filter((val) => +timeDay.floor(val) === +val);
245
+ } else if (formatType === 'hour' || formatType === PeriodType.Hour) {
246
+ tickVals = tickVals.filter((val) => +timeHour.floor(val) === +val);
247
+ } else if (formatType === 'minute' || formatType === PeriodType.Minute) {
248
+ tickVals = tickVals.filter((val) => +timeMinute.floor(val) === +val);
249
+ } else if (formatType === 'second' || formatType === PeriodType.Second) {
250
+ tickVals = tickVals.filter((val) => +timeSecond.floor(val) === +val);
251
+ } else if (formatType === 'millisecond' || formatType === PeriodType.Millisecond) {
252
+ tickVals = tickVals.filter((val) => +timeMillisecond.floor(val) === +val);
253
+ }
254
+
255
+ // Remove any duplicates (manually added)
256
+ return unique(tickVals);
257
+ });
258
+
259
+ const tickFormat = $derived(
260
+ autoTickFormat({
261
+ scale,
262
+ ticks,
263
+ count: tickCount,
264
+ formatType: format,
265
+ multiline: tickMultiline,
266
+ placement,
267
+ })
268
+ );
173
269
 
174
270
  function getCoords(tick: any) {
175
271
  switch (placement) {
176
272
  case 'top':
177
- return {
178
- x: scale(tick) + (isScaleBand(scale) ? scale.bandwidth() / 2 : 0),
179
- y: yRangeMinMax[0],
180
- };
181
-
182
273
  case 'bottom':
183
274
  return {
184
- x: scale(tick) + (isScaleBand(scale) ? scale.bandwidth() / 2 : 0),
185
- y: yRangeMinMax[1],
275
+ x:
276
+ scale(tick) +
277
+ (isScaleBand(scale)
278
+ ? scale.bandwidth() / 2
279
+ : ctx.xInterval
280
+ ? (scale(ctx.xInterval.offset(tick)) - scale(tick)) / 2 // offset 1/2 width of time interval
281
+ : 0),
282
+ y: placement === 'top' ? yRangeMinMax[0] : yRangeMinMax[1],
186
283
  };
187
284
 
188
285
  case 'left':
189
- return {
190
- x: xRangeMinMax[0],
191
- y: scale(tick) + (isScaleBand(scale) ? scale.bandwidth() / 2 : 0),
192
- };
193
-
194
286
  case 'right':
195
287
  return {
196
- x: xRangeMinMax[1],
197
- y: scale(tick) + (isScaleBand(scale) ? scale.bandwidth() / 2 : 0),
288
+ x: placement === 'left' ? xRangeMinMax[0] : xRangeMinMax[1],
289
+ y:
290
+ scale(tick) +
291
+ (isScaleBand(scale)
292
+ ? scale.bandwidth() / 2
293
+ : ctx.yInterval
294
+ ? (scale(ctx.yInterval.offset(tick)) - scale(tick)) / 2 // offset 1/2 height of time interval
295
+ : 0),
198
296
  };
199
297
 
200
298
  case 'angle':
@@ -217,14 +315,14 @@
217
315
  return {
218
316
  textAnchor: 'middle',
219
317
  verticalAnchor: 'end',
220
- dy: -tickLength - 2, // manually adjusted until Text supports custom styles
318
+ dy: -tickLength,
221
319
  };
222
320
 
223
321
  case 'bottom':
224
322
  return {
225
323
  textAnchor: 'middle',
226
324
  verticalAnchor: 'start',
227
- dy: tickLength, // manually adjusted until Text supports custom styles
325
+ dy: tickLength,
228
326
  };
229
327
 
230
328
  case 'left':
@@ -232,7 +330,6 @@
232
330
  textAnchor: 'end',
233
331
  verticalAnchor: 'middle',
234
332
  dx: -tickLength,
235
- dy: -2, // manually adjusted until Text supports custom styles
236
333
  };
237
334
 
238
335
  case 'right':
@@ -240,7 +337,6 @@
240
337
  textAnchor: 'start',
241
338
  verticalAnchor: 'middle',
242
339
  dx: tickLength,
243
- dy: -2, // manually adjusted until Text supports custom styles
244
340
  };
245
341
 
246
342
  case 'angle':
@@ -255,7 +351,7 @@
255
351
  ? 'end'
256
352
  : 'start',
257
353
  verticalAnchor: 'middle',
258
- dx: Math.sin(xValue) * (tickLength + 2),
354
+ dx: Math.sin(xValue) * tickLength,
259
355
  dy: -Math.cos(xValue) * (tickLength + 4), // manually adjusted until Text supports custom styles
260
356
  };
261
357
 
@@ -264,7 +360,6 @@
264
360
  textAnchor: 'middle',
265
361
  verticalAnchor: 'middle',
266
362
  dx: 2,
267
- dy: -2, // manually adjusted until Text supports custom styles
268
363
  };
269
364
  }
270
365
  }
@@ -317,36 +412,31 @@
317
412
  });
318
413
 
319
414
  const resolvedLabelProps = $derived({
320
- value: typeof label === 'function' ? '' : undefined,
415
+ value: typeof label === 'function' ? '' : label,
321
416
  x: resolvedLabelX,
322
417
  y: resolvedLabelY,
323
418
  textAnchor: resolvedLabelTextAnchor,
324
419
  verticalAnchor: resolvedLabelVerticalAnchor,
325
420
  rotate: orientation === 'vertical' && labelPlacement === 'middle' ? -90 : 0,
326
- capHeight: '.5rem', // text-[10px]
421
+ // complement 10px text (until Text supports custom styles)
422
+ capHeight: '7px',
423
+ lineHeight: '11px',
327
424
  ...labelProps,
328
- class: cls(
329
- layerClass('axis-label'),
330
- 'text-[10px] stroke-surface-100 [stroke-width:2px] font-light',
331
- classes.label,
332
- labelProps?.class
333
- ),
425
+ class: cls('lc-axis-label', classes.label, labelProps?.class),
334
426
  }) satisfies ComponentProps<typeof Text>;
335
427
  </script>
336
428
 
337
429
  <Group
338
430
  {...restProps}
339
431
  data-placement={placement}
340
- class={cls(layerClass('axis'), `placement-${placement}`, classes.root, className)}
432
+ class={cls('lc-axis', `placement-${placement}`, classes.root, className)}
341
433
  >
342
434
  {#if rule !== false}
343
- {@const ruleProps = extractLayerProps(rule, 'axis-rule')}
344
435
  <Rule
345
- x={placement === 'left' || placement === 'right' ? placement : placement === 'angle'}
346
- y={placement === 'top' || placement === 'bottom' ? placement : placement === 'radius'}
436
+ x={placement === 'left' ? '$left' : placement === 'right' ? '$right' : placement === 'angle'}
437
+ y={placement === 'top' ? '$top' : placement === 'bottom' ? '$bottom' : placement === 'radius'}
347
438
  {motion}
348
- {...ruleProps}
349
- class={cls('stroke-surface-content/50', classes.rule, ruleProps?.class)}
439
+ {...extractLayerProps(rule, 'lc-axis-rule', classes.rule ?? '')}
350
440
  />
351
441
  {/if}
352
442
 
@@ -356,7 +446,7 @@
356
446
  <Text {...resolvedLabelProps} />
357
447
  {/if}
358
448
 
359
- {#each tickVals as tick, index (tick.toString())}
449
+ {#each tickVals as tick, index (tick.valueOf())}
360
450
  {@const tickCoords = getCoords(tick)}
361
451
  {@const [radialTickCoordsX, radialTickCoordsY] = pointRadial(tickCoords.x, tickCoords.y)}
362
452
  {@const [radialTickMarkCoordsX, radialTickMarkCoordsY] = pointRadial(
@@ -366,36 +456,28 @@
366
456
  {@const resolvedTickLabelProps = {
367
457
  x: orientation === 'angle' ? radialTickCoordsX : tickCoords.x,
368
458
  y: orientation === 'angle' ? radialTickCoordsY : tickCoords.y,
369
- value: formatValue(tick, format ?? scale.tickFormat?.() ?? ((v) => v)),
459
+ value: tickFormat(tick, index),
370
460
  ...getDefaultTickLabelProps(tick),
371
461
  motion,
462
+ // complement 10px text (until Text supports custom styles)
463
+ capHeight: '7px',
464
+ lineHeight: '11px',
372
465
  ...tickLabelProps,
373
- class: cls(
374
- layerClass('axis-tick-label'),
375
- 'text-[10px] stroke-surface-100 [stroke-width:2px] font-light',
376
- classes.tickLabel,
377
- tickLabelProps?.class
378
- ),
466
+ class: cls('lc-axis-tick-label', classes.tickLabel, tickLabelProps?.class),
379
467
  }}
380
468
 
381
- <Group {transitionIn} {transitionInParams} class={layerClass('axis-tick-group')}>
469
+ <Group {transitionIn} {transitionInParams} class="lc-axis-tick-group">
382
470
  {#if grid !== false}
383
- {@const ruleProps = extractLayerProps(grid, 'axis-grid')}
384
471
  <Rule
385
472
  x={orientation === 'horizontal' || orientation === 'angle' ? tick : false}
386
473
  y={orientation === 'vertical' || orientation === 'radius' ? tick : false}
387
474
  {motion}
388
- {...ruleProps}
389
- class={cls('stroke-surface-content/10', classes.rule, ruleProps?.class)}
475
+ {...extractLayerProps(grid, 'lc-axis-grid', classes.rule ?? '')}
390
476
  />
391
477
  {/if}
392
478
 
393
479
  {#if tickMarks}
394
- {@const tickClasses = cls(
395
- layerClass('axis-tick'),
396
- 'stroke-surface-content/50',
397
- classes.tick
398
- )}
480
+ {@const tickClasses = cls('lc-axis-tick', classes.tick)}
399
481
  {#if orientation === 'horizontal'}
400
482
  <Line
401
483
  x1={tickCoords.x}
@@ -434,3 +516,38 @@
434
516
  </Group>
435
517
  {/each}
436
518
  </Group>
519
+
520
+ <style>
521
+ @layer components {
522
+ :global(:where(.lc-axis-rule)) {
523
+ --stroke-color: color-mix(
524
+ in oklab,
525
+ var(--color-surface-content, currentColor) 50%,
526
+ transparent
527
+ );
528
+ }
529
+
530
+ :global(:where(.lc-axis-tick)) {
531
+ --stroke-color: color-mix(
532
+ in oklab,
533
+ var(--color-surface-content, currentColor) 50%,
534
+ transparent
535
+ );
536
+ }
537
+
538
+ :global(:where(.lc-axis-grid)) {
539
+ --stroke-color: color-mix(
540
+ in oklab,
541
+ var(--color-surface-content, currentColor) 10%,
542
+ transparent
543
+ );
544
+ }
545
+
546
+ :global(:where(.lc-axis-label, .lc-axis-tick-label)) {
547
+ font-size: 10px;
548
+ stroke: var(--color-surface-100, light-dark(white, black));
549
+ stroke-width: 2px;
550
+ font-weight: 300;
551
+ }
552
+ }
553
+ </style>
@@ -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 pixels (enabling responsive count)
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
  */
@@ -73,7 +83,7 @@ export type AxisPropsWithoutHTML<In extends Transition = Transition> = {
73
83
  */
74
84
  transitionInParams?: TransitionParams<In>;
75
85
  /**
76
- * Scale for the axis
86
+ * Override scale for the axis
77
87
  */
78
88
  scale?: any;
79
89
  /**
@@ -92,16 +102,23 @@ 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';
99
109
  import { type MotionProp } from '../utils/motion.svelte.js';
100
110
  import { type TicksConfig } from '../utils/ticks.js';
111
+ declare function $$render<T extends Transition = Transition>(): {
112
+ props: AxisProps<T>;
113
+ exports: {};
114
+ bindings: "";
115
+ slots: {};
116
+ events: {};
117
+ };
101
118
  declare class __sveltets_Render<T extends Transition = Transition> {
102
- props(): AxisProps<T>;
103
- events(): {};
104
- slots(): {};
119
+ props(): ReturnType<typeof $$render<T>>['props'];
120
+ events(): ReturnType<typeof $$render<T>>['events'];
121
+ slots(): ReturnType<typeof $$render<T>>['slots'];
105
122
  bindings(): "";
106
123
  exports(): {};
107
124
  }