layerchart 0.53.0 → 0.54.0

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 (34) hide show
  1. package/dist/components/Axis.svelte +51 -94
  2. package/dist/components/Axis.svelte.d.ts +2 -1
  3. package/dist/components/Bars.svelte +2 -1
  4. package/dist/components/Bars.svelte.d.ts +1 -0
  5. package/dist/components/Chart.svelte +6 -4
  6. package/dist/components/Chart.svelte.d.ts +25 -8
  7. package/dist/components/ChartContext.svelte +1 -1
  8. package/dist/components/ChartContext.svelte.d.ts +1 -1
  9. package/dist/components/Grid.svelte +151 -0
  10. package/dist/components/Grid.svelte.d.ts +35 -0
  11. package/dist/components/Labels.svelte +15 -5
  12. package/dist/components/Labels.svelte.d.ts +2 -0
  13. package/dist/components/Legend.svelte +1 -1
  14. package/dist/components/Rule.svelte +20 -4
  15. package/dist/components/Rule.svelte.d.ts +2 -0
  16. package/dist/components/TransformContext.svelte +3 -1
  17. package/dist/components/charts/AreaChart.svelte +59 -35
  18. package/dist/components/charts/AreaChart.svelte.d.ts +40 -2
  19. package/dist/components/charts/BarChart.svelte +63 -29
  20. package/dist/components/charts/BarChart.svelte.d.ts +40 -2
  21. package/dist/components/charts/LineChart.svelte +44 -16
  22. package/dist/components/charts/LineChart.svelte.d.ts +40 -2
  23. package/dist/components/charts/PieChart.svelte +15 -1
  24. package/dist/components/charts/PieChart.svelte.d.ts +16 -1
  25. package/dist/components/charts/ScatterChart.svelte +31 -16
  26. package/dist/components/charts/ScatterChart.svelte.d.ts +38 -2
  27. package/dist/components/index.d.ts +1 -0
  28. package/dist/components/index.js +1 -0
  29. package/dist/components/tooltip/Tooltip.svelte +20 -5
  30. package/dist/components/tooltip/TooltipContext.svelte +2 -1
  31. package/dist/components/tooltip/TooltipContext.svelte.d.ts +7 -0
  32. package/dist/docs/Preview.svelte +24 -11
  33. package/dist/utils/scales.d.ts +1 -1
  34. package/package.json +1 -1
@@ -6,8 +6,8 @@ import { pointRadial } from 'd3-shape';
6
6
  import { format as formatValue } from '@layerstack/utils';
7
7
  import { cls } from '@layerstack/tailwind';
8
8
  import { chartContext } from './ChartContext.svelte';
9
- import Circle from './Circle.svelte';
10
9
  import Line from './Line.svelte';
10
+ import Rule from './Rule.svelte';
11
11
  import Text from './Text.svelte';
12
12
  import { isScaleBand } from '../utils/scales.js';
13
13
  const { xScale, yScale, xRange, yRange, width, height, padding } = chartContext();
@@ -101,35 +101,41 @@ function getDefaultTickLabelProps(tick) {
101
101
  return {
102
102
  textAnchor: 'middle',
103
103
  verticalAnchor: 'end',
104
- dy: -6, // manually adjusted until Text supports custom styles
104
+ dy: -tickLength - 2, // manually adjusted until Text supports custom styles
105
105
  };
106
106
  case 'bottom':
107
107
  return {
108
108
  textAnchor: 'middle',
109
109
  verticalAnchor: 'start',
110
- dy: 4, // manually adjusted until Text supports custom styles
110
+ dy: tickLength, // manually adjusted until Text supports custom styles
111
111
  };
112
112
  case 'left':
113
113
  return {
114
114
  textAnchor: 'end',
115
115
  verticalAnchor: 'middle',
116
- dx: -4,
116
+ dx: -tickLength,
117
117
  dy: -2, // manually adjusted until Text supports custom styles
118
118
  };
119
119
  case 'right':
120
120
  return {
121
121
  textAnchor: 'start',
122
122
  verticalAnchor: 'middle',
123
- dx: 4,
123
+ dx: tickLength,
124
124
  dy: -2, // manually adjusted until Text supports custom styles
125
125
  };
126
126
  case 'angle':
127
- const xValue = _scale(tick);
127
+ const xValue = _scale(tick); // angle in radians
128
128
  return {
129
- textAnchor: xValue === 0 || xValue === Math.PI ? 'middle' : xValue > Math.PI ? 'end' : 'start',
129
+ textAnchor: xValue === 0 ||
130
+ Math.abs(xValue - Math.PI) < 0.01 || // ~180deg
131
+ Math.abs(xValue - Math.PI * 2) < 0.01 // ~360deg
132
+ ? 'middle'
133
+ : xValue > Math.PI
134
+ ? 'end'
135
+ : 'start',
130
136
  verticalAnchor: 'middle',
131
- dx: 0,
132
- dy: -2, // manually adjusted until Text supports custom styles
137
+ dx: Math.sin(xValue) * (tickLength + 2),
138
+ dy: -Math.cos(xValue) * (tickLength + 4), // manually adjusted until Text supports custom styles
133
139
  };
134
140
  case 'radius':
135
141
  return {
@@ -173,44 +179,15 @@ $: resolvedLabelProps = {
173
179
 
174
180
  <g class={cls('Axis placement-{placement}', classes.root, $$props.class)}>
175
181
  {#if rule !== false}
176
- {@const lineProps = typeof rule === 'object' ? rule : null}
177
- {#if orientation === 'vertical'}
178
- <Line
179
- x1={placement === 'right' ? xRangeMax : xRangeMin}
180
- x2={placement === 'right' ? xRangeMax : xRangeMin}
181
- y1={$yRange[0] || 0}
182
- y2={$yRange[1] || 0}
183
- {tweened}
184
- {spring}
185
- {...lineProps}
186
- class={cls('rule stroke-surface-content/50', lineProps?.class)}
187
- />
188
- {/if}
189
-
190
- {#if orientation === 'horizontal'}
191
- <Line
192
- x1={$xRange[0] || 0}
193
- x2={$xRange[1] || 0}
194
- y1={placement === 'top' ? yRangeMin : yRangeMax}
195
- y2={placement === 'top' ? yRangeMin : yRangeMax}
196
- {tweened}
197
- {spring}
198
- {...lineProps}
199
- class={cls('rule stroke-surface-content/50', lineProps?.class)}
200
- />
201
- {/if}
202
-
203
- <!-- TODO: angle rule? -->
204
-
205
- {#if orientation === 'radius'}
206
- <Circle
207
- r={$yRange[0] || 0}
208
- {tweened}
209
- {spring}
210
- {...lineProps}
211
- class={cls('rule stroke-surface-content/20 fill-none', lineProps?.class)}
212
- />
213
- {/if}
182
+ {@const ruleProps = typeof rule === 'object' ? rule : null}
183
+ <Rule
184
+ x={placement === 'left' || placement === 'right' ? placement : placement === 'angle'}
185
+ y={placement === 'top' || placement === 'bottom' ? placement : placement === 'radius'}
186
+ {tweened}
187
+ {spring}
188
+ {...ruleProps}
189
+ class={cls('rule stroke-surface-content/50', ruleProps?.class)}
190
+ />
214
191
  {/if}
215
192
 
216
193
  {#if label}
@@ -219,10 +196,14 @@ $: resolvedLabelProps = {
219
196
 
220
197
  {#each tickVals as tick, index (tick)}
221
198
  {@const tickCoords = getCoords(tick)}
222
- {@const radialTickCoords = pointRadial(tickCoords.x, tickCoords.y)}
199
+ {@const [radialTickCoordsX, radialTickCoordsY] = pointRadial(tickCoords.x, tickCoords.y)}
200
+ {@const [radialTickMarkCoordsX, radialTickMarkCoordsY] = pointRadial(
201
+ tickCoords.x,
202
+ tickCoords.y + tickLength
203
+ )}
223
204
  {@const resolvedTickLabelProps = {
224
- x: orientation === 'angle' ? radialTickCoords[0] : tickCoords.x,
225
- y: orientation === 'angle' ? radialTickCoords[1] : tickCoords.y,
205
+ x: orientation === 'angle' ? radialTickCoordsX : tickCoords.x,
206
+ y: orientation === 'angle' ? radialTickCoordsY : tickCoords.y,
226
207
  value: formatValue(tick, format ?? _scale.tickFormat?.() ?? ((v) => v)),
227
208
  ...getDefaultTickLabelProps(tick),
228
209
  tweened,
@@ -236,50 +217,15 @@ $: resolvedLabelProps = {
236
217
 
237
218
  <g in:transitionIn={transitionInParams}>
238
219
  {#if grid !== false}
239
- {@const lineProps = typeof grid === 'object' ? grid : null}
240
- {#if orientation === 'horizontal'}
241
- <Line
242
- x1={tickCoords.x}
243
- y1={yRangeMin}
244
- x2={tickCoords.x}
245
- y2={yRangeMax}
246
- {tweened}
247
- {spring}
248
- {...lineProps}
249
- class={cls('grid stroke-surface-content/10', lineProps?.class)}
250
- />
251
- {:else if orientation === 'vertical'}
252
- <Line
253
- x1={0}
254
- y1={tickCoords.y}
255
- x2={$width}
256
- y2={tickCoords.y}
257
- {tweened}
258
- {spring}
259
- {...lineProps}
260
- class={cls('grid stroke-surface-content/10', lineProps?.class)}
261
- />
262
- {:else if orientation === 'angle'}
263
- {@const [x1, y1] = pointRadial(tickCoords.x, yRangeMin)}
264
- {@const [x2, y2] = pointRadial(tickCoords.x, yRangeMax)}
265
-
266
- <Line
267
- {x1}
268
- {y1}
269
- {x2}
270
- {y2}
271
- {tweened}
272
- {spring}
273
- {...lineProps}
274
- class={cls('grid stroke-surface-content/10', lineProps?.class)}
275
- />
276
- {:else if orientation === 'radius'}
277
- <circle
278
- r={tickCoords.y}
279
- {...lineProps}
280
- class={cls('grid stroke-surface-content/10 fill-none', lineProps?.class)}
281
- />
282
- {/if}
220
+ {@const ruleProps = typeof grid === 'object' ? grid : null}
221
+ <Rule
222
+ x={orientation === 'horizontal' || orientation === 'angle' ? tick : false}
223
+ y={orientation === 'vertical' || orientation === 'radius' ? tick : false}
224
+ {tweened}
225
+ {spring}
226
+ {...ruleProps}
227
+ class={cls('grid stroke-surface-content/10', ruleProps?.class)}
228
+ />
283
229
  {/if}
284
230
 
285
231
  <!-- Tick marks -->
@@ -303,7 +249,18 @@ $: resolvedLabelProps = {
303
249
  {spring}
304
250
  class="tick stroke-surface-content/50"
305
251
  />
252
+ {:else if orientation === 'angle'}
253
+ <Line
254
+ x1={radialTickCoordsX}
255
+ y1={radialTickCoordsY}
256
+ x2={radialTickMarkCoordsX}
257
+ y2={radialTickMarkCoordsY}
258
+ {tweened}
259
+ {spring}
260
+ class="tick stroke-surface-content/50"
261
+ />
306
262
  {/if}
263
+ <!-- TODO: Add tick marks for radial (angle)? -->
307
264
 
308
265
  <slot name="tickLabel" labelProps={resolvedTickLabelProps} {index}>
309
266
  <Text {...resolvedTickLabelProps} />
@@ -5,6 +5,7 @@ import type { SVGAttributes } from 'svelte/elements';
5
5
  import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
6
6
  import { type FormatType } from '@layerstack/utils';
7
7
  import type { TransitionParams } from 'svelte-ux';
8
+ import Rule from './Rule.svelte';
8
9
  import Text from './Text.svelte';
9
10
  import { type AnyScale } from '../utils/scales.js';
10
11
  declare const __propDef: {
@@ -14,7 +15,7 @@ declare const __propDef: {
14
15
  label?: string | undefined;
15
16
  labelPlacement?: ("start" | "middle" | "end") | undefined;
16
17
  labelProps?: Partial<ComponentProps<Text>> | undefined;
17
- rule?: (boolean | Pick<SVGAttributes<SVGElement>, "class" | "style">) | undefined;
18
+ rule?: (boolean | Partial<ComponentProps<Rule>>) | undefined;
18
19
  grid?: (boolean | Pick<SVGAttributes<SVGElement>, "class" | "style">) | undefined;
19
20
  ticks?: number | any[] | ((scale: AnyScale) => any) | null | undefined;
20
21
  tickLength?: number | undefined;
@@ -27,6 +27,7 @@ export let y1 = undefined;
27
27
  export let stroke = 'black';
28
28
  export let strokeWidth = 0;
29
29
  export let radius = 0;
30
+ export let fill = undefined;
30
31
  /** Inset the rect for amount of padding. Useful with multiple bars (bullet, overlap, etc) */
31
32
  export let inset = 0;
32
33
  export let spring = undefined;
@@ -42,7 +43,7 @@ export let tweened = undefined;
42
43
  {y}
43
44
  {x1}
44
45
  {y1}
45
- fill={$config.c ? $cGet(item) : null}
46
+ fill={fill ?? ($config.c ? $cGet(item) : null)}
46
47
  {stroke}
47
48
  {strokeWidth}
48
49
  {radius}
@@ -13,6 +13,7 @@ declare const __propDef: {
13
13
  stroke?: string | undefined;
14
14
  strokeWidth?: number | undefined;
15
15
  radius?: number | undefined;
16
+ fill?: string | undefined;
16
17
  inset?: number | undefined;
17
18
  spring?: ComponentProps<Rect>["spring"];
18
19
  tweened?: ComponentProps<Rect>["tweened"];
@@ -60,9 +60,11 @@ export let tooltip = undefined;
60
60
  export let transform = undefined;
61
61
  // @ts-expect-error will only be undefined until bind:transformContext runs
62
62
  export let transformContext = undefined;
63
- // Binded for access within TransformContext
64
- let geoProjection = undefined;
65
- // Track when mounted since LayerCake initializes width/height with `100` until binded `clientWidth`/`clientWidth` can run
63
+ /** Expose bound geo projection context */
64
+ export let geoProjection = undefined;
65
+ /** Expose bound tooltip context */
66
+ export let tooltipContext = undefined;
67
+ // Track when mounted since LayerCake initializes width/height with `100` until bound `clientWidth`/`clientWidth` can run
66
68
  // Useful to key/remount TransformContext with correct `initialTranslate` / `initialScale` values
67
69
  let isMounted = false;
68
70
  onMount(() => {
@@ -184,7 +186,7 @@ $: _yRange =
184
186
  >
185
187
  <GeoContext {...geo} bind:geo={geoProjection} let:projection>
186
188
  {@const tooltipProps = typeof tooltip === 'object' ? tooltip : {}}
187
- <TooltipContext {...tooltipProps} let:tooltip>
189
+ <TooltipContext {...tooltipProps} bind:tooltip={tooltipContext} let:tooltip>
188
190
  <slot
189
191
  {aspectRatio}
190
192
  {containerHeight}
@@ -86,40 +86,40 @@ declare class __sveltets_Render<TData> {
86
86
  y1Scale?: AnyScale;
87
87
  /** The D3 scale that should be used for the color dimension. Pass in an instantiated D3 scale if you want to override the default or you want to extra options. @default scaleOrdinal */
88
88
  cScale?: AnyScale;
89
- /** Override the default x range of `[0, width]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `xReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
89
+ /** Override the default x range of `[0, width]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `xReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
90
90
  xRange?: string[] | number[] | ((args: {
91
91
  width: number;
92
92
  height: number;
93
93
  }) => number[] | string[]) | undefined;
94
- /** Override the default y range of `[0, height]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `yReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
94
+ /** Override the default y range of `[0, height]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `yReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
95
95
  yRange?: string[] | number[] | ((args: {
96
96
  width: number;
97
97
  height: number;
98
98
  }) => number[] | string[]) | undefined;
99
- /** Override the default z range of `[0, width]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `zReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
99
+ /** Override the default z range of `[0, width]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `zReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
100
100
  zRange?: string[] | number[] | ((args: {
101
101
  width: number;
102
102
  height: number;
103
103
  }) => number[] | string[]) | undefined;
104
- /** Override the default r range of `[1, 25]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `rReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
104
+ /** Override the default r range of `[1, 25]` by setting an array or function with argument `({ width, height})` that returns an array. Setting this prop overrides `rReverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
105
105
  rRange?: string[] | number[] | ((args: {
106
106
  width: number;
107
107
  height: number;
108
108
  }) => number[] | string[]) | undefined;
109
- /** Set the x1 range by setting an array or function with argument `({ xScale, width, height})` that returns an array. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
109
+ /** Set the x1 range by setting an array or function with argument `({ xScale, width, height})` that returns an array. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
110
110
  x1Range?: string[] | number[] | ((args: {
111
111
  xScale: AnyScale;
112
112
  width: number;
113
113
  height: number;
114
114
  }) => number[] | string[]) | undefined;
115
- /** Set the y1 range by setting an array or function with argument `({ yScale, width, height})` that returns an array. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
115
+ /** Set the y1 range by setting an array or function with argument `({ yScale, width, height})` that returns an array. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
116
116
  y1Range?: string[] | number[] | ((args: {
117
117
  yScale: AnyScale;
118
118
  width: number;
119
119
  height: number;
120
120
  }) => number[] | string[]) | undefined;
121
- /** Override the default y1 range of `[0, width]` by setting an array or function with argument `({ yScale, width, height})` that returns an array. Setting this prop overrides `x1Reverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshhold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
122
- cRange?: string[];
121
+ /** Override the default y1 range of `[0, width]` by setting an array or function with argument `({ yScale, width, height})` that returns an array. Setting this prop overrides `x1Reverse`. This can also be a list of numbers or strings for scales with discrete ranges like [scaleThreshold](https://github.com/d3/d3-scale#threshold-scales) or [scaleQuantize](https://github.com/d3/d3-scale#quantize-scales). */
122
+ cRange?: string[] | readonly string[];
123
123
  /** Reverse the default x range. By default this is `false` and the range is `[0, width]`. Ignored if you set the xRange prop. @default false */
124
124
  xReverse?: boolean;
125
125
  /** Reverse the default y range. By default this is `true` and the range is `[height, 0]` unless using an ordinal scale with a `.bandwidth` method for `yScale`. Ignored if you set the `yRange` prop. @default true */
@@ -192,6 +192,13 @@ declare class __sveltets_Render<TData> {
192
192
  onClick?: ({ data }: {
193
193
  data: any;
194
194
  }) => any;
195
+ tooltip?: import("svelte/store").Writable<{
196
+ y: number;
197
+ x: number;
198
+ data: any;
199
+ show: (e: PointerEvent, tooltipData?: any) => void;
200
+ hide: () => void;
201
+ }>;
195
202
  }> | undefined;
196
203
  /** Props passed to TransformContext */
197
204
  transform?: Partial<{
@@ -242,6 +249,16 @@ declare class __sveltets_Render<TData> {
242
249
  }> | undefined;
243
250
  /** Expose to support `bind:transformContext` for imperative control (`transformContext.translate(...)`) */
244
251
  transformContext?: TransformContext;
252
+ /** Exposed via bind: to support `bind:geoProjection` for external access */
253
+ geoProjection?: import("svelte/store").Writable<import("d3-geo").GeoProjection> | undefined;
254
+ /** Exposed via bind: to support `bind:tooltipContext` for external access (ex. `tooltipContext.data) */
255
+ tooltipContext?: import("svelte/store").Writable<{
256
+ y: number;
257
+ x: number;
258
+ data: any;
259
+ show: (e: PointerEvent, tooltipData?: any) => void;
260
+ hide: () => void;
261
+ }> | undefined;
245
262
  };
246
263
  events(): {
247
264
  resize: any;
@@ -127,7 +127,7 @@ $: if (isMounted) {
127
127
  containerHeight: $containerHeight,
128
128
  });
129
129
  }
130
- // Track when mounted since LayerCake initializes width/height with `100` until binded `clientWidth`/`clientWidth` can run
130
+ // Track when mounted since LayerCake initializes width/height with `100` until bound `clientWidth`/`clientWidth` can run
131
131
  let isMounted = false;
132
132
  onMount(() => {
133
133
  isMounted = true;
@@ -115,7 +115,7 @@ declare class __sveltets_Render<TData> {
115
115
  c?: import("../utils/common.js").Accessor<TData>;
116
116
  cScale?: AnyScale<any, any, any, any> | undefined;
117
117
  cDomain?: import("../utils/scales.js").DomainType | undefined;
118
- cRange?: string[] | undefined;
118
+ cRange?: string[] | readonly string[] | undefined;
119
119
  /** Use radial instead of cartesian coordinates, mapping `x` to `angle` and `y`` to radial. Radial lines are positioned relative to the origin, use transform (ex. `<Group center>`) to change the origin */ radial?: boolean;
120
120
  data?: SankeyGraph<any, any> | TData[] | HierarchyNode<TData> | undefined;
121
121
  };
@@ -0,0 +1,151 @@
1
+ <script>import { fade } from 'svelte/transition';
2
+ import { cubicIn } from 'svelte/easing';
3
+ import { curveLinearClosed } from 'd3-shape';
4
+ import { cls } from '@layerstack/tailwind';
5
+ import { chartContext } from './ChartContext.svelte';
6
+ import { isScaleBand } from '../utils/scales.js';
7
+ import Rule from './Rule.svelte';
8
+ import Spline from './Spline.svelte';
9
+ import Circle from './Circle.svelte';
10
+ const { xScale, yScale, radial } = chartContext();
11
+ /** Draw a x-axis lines */
12
+ export let x = false;
13
+ /** Draw a y-axis lines */
14
+ export let y = false;
15
+ /** Control the number of x-axis ticks */
16
+ export let xTicks = undefined;
17
+ /** Control the number of y-axis ticks */
18
+ export let yTicks = !isScaleBand($yScale) ? 4 : undefined;
19
+ /** Line alignment when band scale is used (x or y axis) */
20
+ export let bandAlign = 'center';
21
+ /** Render `y` lines with circles or linear splines */
22
+ export let radialY = 'circle';
23
+ export let spring = undefined;
24
+ export let tweened = undefined;
25
+ export let transitionIn = tweened
26
+ ? fade
27
+ : () => {
28
+ return {};
29
+ };
30
+ export let transitionInParams = { easing: cubicIn };
31
+ export let classes = {};
32
+ function getTickVals(scale, ticks) {
33
+ return Array.isArray(ticks)
34
+ ? ticks
35
+ : typeof ticks === 'function'
36
+ ? ticks(scale)
37
+ : isScaleBand(scale)
38
+ ? ticks
39
+ ? scale.domain().filter((v, i) => i % ticks === 0)
40
+ : scale.domain()
41
+ : scale.ticks?.(ticks);
42
+ }
43
+ $: xTickVals = getTickVals($xScale, xTicks);
44
+ $: yTickVals = getTickVals($yScale, yTicks);
45
+ $: xBandOffset = isScaleBand($xScale)
46
+ ? bandAlign === 'between'
47
+ ? -($xScale.padding() * $xScale.step()) / 2 // before
48
+ : $xScale.step() / 2 - ($xScale.padding() * $xScale.step()) / 2 // center
49
+ : 0;
50
+ $: yBandOffset = isScaleBand($yScale)
51
+ ? bandAlign === 'between'
52
+ ? -($yScale.padding() * $yScale.step()) / 2 // before
53
+ : $yScale.step() / 2 - ($yScale.padding() * $yScale.step()) / 2 // center
54
+ : 0;
55
+ </script>
56
+
57
+ <g class={cls('Grid', classes.root, $$props.class)}>
58
+ {#if x}
59
+ {@const splineProps = typeof x === 'object' ? x : null}
60
+ <g in:transitionIn={transitionInParams}>
61
+ {#each xTickVals as x}
62
+ {#if $radial}
63
+ <Spline
64
+ data={yTickVals.map((y) => ({ x, y }))}
65
+ x="x"
66
+ y="y"
67
+ xOffset={xBandOffset}
68
+ curve={curveLinearClosed}
69
+ {tweened}
70
+ {spring}
71
+ {...splineProps}
72
+ class={cls('stroke-surface-content/10', classes.line, splineProps?.class)}
73
+ />
74
+ {:else}
75
+ <Rule
76
+ {x}
77
+ xOffset={xBandOffset}
78
+ {tweened}
79
+ {spring}
80
+ {...splineProps}
81
+ class={cls('stroke-surface-content/10', classes.line, splineProps?.class)}
82
+ />
83
+ {/if}
84
+ {/each}
85
+
86
+ <!-- Add extra rule after last band -->
87
+ {#if isScaleBand($xScale) && bandAlign === 'between' && !$radial && xTickVals.length}
88
+ <Rule
89
+ x={xTickVals[xTickVals.length - 1]}
90
+ xOffset={xBandOffset + $xScale.step()}
91
+ {tweened}
92
+ {spring}
93
+ {...splineProps}
94
+ class={cls('stroke-surface-content/10', classes.line, splineProps?.class)}
95
+ />
96
+ {/if}
97
+ </g>
98
+ {/if}
99
+
100
+ {#if y}
101
+ {@const splineProps = typeof y === 'object' ? y : null}
102
+ <g in:transitionIn={transitionInParams}>
103
+ {#each yTickVals as y}
104
+ {#if $radial}
105
+ {#if radialY === 'circle'}
106
+ <Circle
107
+ r={$yScale(y)}
108
+ {tweened}
109
+ {spring}
110
+ {...splineProps}
111
+ class={cls('fill-none stroke-surface-content/10', classes.line, splineProps?.class)}
112
+ />
113
+ {:else}
114
+ <Spline
115
+ data={xTickVals.map((x) => ({ x, y }))}
116
+ x="x"
117
+ y="y"
118
+ yOffset={yBandOffset}
119
+ {tweened}
120
+ {spring}
121
+ curve={curveLinearClosed}
122
+ {...splineProps}
123
+ class={cls('stroke-surface-content/10', classes.line, splineProps?.class)}
124
+ />
125
+ {/if}
126
+ {:else}
127
+ <Rule
128
+ {y}
129
+ yOffset={yBandOffset}
130
+ {tweened}
131
+ {spring}
132
+ {...splineProps}
133
+ class={cls('stroke-surface-content/10', classes.line, splineProps?.class)}
134
+ />
135
+ {/if}
136
+ {/each}
137
+
138
+ <!-- Add extra rule after last band -->
139
+ {#if isScaleBand($yScale) && bandAlign === 'between' && !$radial && yTickVals.length}
140
+ <Rule
141
+ y={yTickVals[yTickVals.length - 1]}
142
+ yOffset={yBandOffset + $yScale.step()}
143
+ {tweened}
144
+ {spring}
145
+ {...splineProps}
146
+ class={cls('stroke-surface-content/10', classes.line, splineProps?.class)}
147
+ />
148
+ {/if}
149
+ </g>
150
+ {/if}
151
+ </g>
@@ -0,0 +1,35 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import type { SVGAttributes } from 'svelte/elements';
3
+ import { fade } from 'svelte/transition';
4
+ import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
5
+ import type { TransitionParams } from 'svelte-ux';
6
+ import { type AnyScale } from '../utils/scales.js';
7
+ declare const __propDef: {
8
+ props: {
9
+ [x: string]: any;
10
+ x?: (boolean | Pick<SVGAttributes<SVGElement>, "class" | "style">) | undefined;
11
+ y?: (boolean | Pick<SVGAttributes<SVGElement>, "class" | "style">) | undefined;
12
+ xTicks?: number | any[] | ((scale: AnyScale) => any) | null | undefined;
13
+ yTicks?: number | any[] | ((scale: AnyScale) => any) | null | undefined;
14
+ bandAlign?: ("center" | "between") | undefined;
15
+ radialY?: ("circle" | "linear") | undefined;
16
+ spring?: boolean | Parameters<typeof springStore>[1];
17
+ tweened?: boolean | Parameters<typeof tweenedStore>[1];
18
+ transitionIn?: (typeof fade | (() => {})) | undefined;
19
+ transitionInParams?: TransitionParams | undefined;
20
+ classes?: {
21
+ root?: string;
22
+ line?: string;
23
+ } | undefined;
24
+ };
25
+ events: {
26
+ [evt: string]: CustomEvent<any>;
27
+ };
28
+ slots: {};
29
+ };
30
+ export type GridProps = typeof __propDef.props;
31
+ export type GridEvents = typeof __propDef.events;
32
+ export type GridSlots = typeof __propDef.slots;
33
+ export default class Grid extends SvelteComponentTyped<GridProps, GridEvents, GridSlots> {
34
+ }
35
+ export {};
@@ -5,16 +5,26 @@ import Text from './Text.svelte';
5
5
  import { isScaleBand } from '../utils/scales.js';
6
6
  import { chartContext } from './ChartContext.svelte';
7
7
  import Points, {} from './Points.svelte';
8
+ import { accessor } from '../utils/common.js';
9
+ const { xScale, yScale } = chartContext();
10
+ /** Override display value accessor. By default, uses `y` unless yScale is band scale */
11
+ export let value = undefined;
8
12
  export let placement = 'outside';
9
13
  export let offset = placement === 'center' ? 0 : 4;
10
14
  export let format = undefined;
11
- const { yScale } = chartContext();
12
15
  $: getTextProps = (point) => {
13
- const value = isScaleBand($yScale) ? point.xValue : point.yValue;
14
- const formattedValue = formatValue(value, format ?? $yScale.tickFormat?.());
16
+ // Used for positioning
17
+ const pointValue = isScaleBand($yScale) ? point.xValue : point.yValue;
18
+ const displayValue = value
19
+ ? accessor(value)(point.data)
20
+ : isScaleBand($yScale)
21
+ ? point.xValue
22
+ : point.yValue;
23
+ const formattedValue = formatValue(displayValue, format ??
24
+ (value ? undefined : isScaleBand($yScale) ? $xScale.tickFormat?.() : $yScale.tickFormat?.()));
15
25
  if (isScaleBand($yScale)) {
16
26
  // Position label left/right on horizontal bars
17
- if (value < 0) {
27
+ if (pointValue < 0) {
18
28
  // left
19
29
  return {
20
30
  value: formattedValue,
@@ -39,7 +49,7 @@ $: getTextProps = (point) => {
39
49
  }
40
50
  else {
41
51
  // Position label top/bottom on vertical bars
42
- if (value < 0) {
52
+ if (pointValue < 0) {
43
53
  // bottom
44
54
  return {
45
55
  value: formattedValue,
@@ -1,8 +1,10 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  import { type FormatType } from '@layerstack/utils';
3
+ import { type Accessor } from '../utils/common.js';
3
4
  declare const __propDef: {
4
5
  props: {
5
6
  [x: string]: any;
7
+ value?: Accessor;
6
8
  placement?: ("inside" | "outside" | "center") | undefined;
7
9
  offset?: number | undefined;
8
10
  format?: FormatType | undefined;
@@ -182,7 +182,7 @@ else {
182
182
  class={cls('h-4 w-4 rounded-full', classes.swatch)}
183
183
  style:background-color={scale(tick)}
184
184
  />
185
- <div class={cls('text-xs text-surface-content', classes.label)}>
185
+ <div class={cls('text-xs text-surface-content whitespace-nowrap', classes.label)}>
186
186
  {tickFormat ? format(tick, tickFormat) : tick}
187
187
  </div>
188
188
  </div>