layerchart 2.0.0-next.38 → 2.0.0-next.39

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 (96) hide show
  1. package/dist/components/AnnotationLine.svelte +15 -2
  2. package/dist/components/AnnotationPoint.svelte +13 -2
  3. package/dist/components/AnnotationRange.svelte +16 -2
  4. package/dist/components/Arc.svelte +3 -3
  5. package/dist/components/Area.svelte +10 -2
  6. package/dist/components/Axis.svelte +43 -26
  7. package/dist/components/Bar.svelte +6 -5
  8. package/dist/components/Bar.svelte.d.ts +2 -2
  9. package/dist/components/Bars.svelte +3 -3
  10. package/dist/components/Blur.svelte +2 -3
  11. package/dist/components/BrushContext.svelte +44 -44
  12. package/dist/components/Calendar.svelte +21 -4
  13. package/dist/components/Chart.svelte +1 -2
  14. package/dist/components/ChartClipPath.svelte +1 -1
  15. package/dist/components/Circle.svelte +44 -3
  16. package/dist/components/CircleClipPath.svelte +8 -1
  17. package/dist/components/ClipPath.svelte +1 -2
  18. package/dist/components/ColorRamp.svelte +1 -1
  19. package/dist/components/ComputedStyles.svelte +9 -2
  20. package/dist/components/Connector.svelte +1 -1
  21. package/dist/components/Ellipse.svelte +44 -3
  22. package/dist/components/Frame.svelte +1 -1
  23. package/dist/components/GeoCircle.svelte +1 -1
  24. package/dist/components/GeoEdgeFade.svelte +1 -1
  25. package/dist/components/GeoPath.svelte +18 -3
  26. package/dist/components/GeoPoint.svelte +3 -3
  27. package/dist/components/GeoSpline.svelte +1 -1
  28. package/dist/components/GeoTile.svelte +1 -1
  29. package/dist/components/Graticule.svelte +5 -5
  30. package/dist/components/Grid.svelte +57 -60
  31. package/dist/components/Group.svelte +11 -6
  32. package/dist/components/Highlight.svelte +46 -22
  33. package/dist/components/Highlight.svelte.d.ts +4 -0
  34. package/dist/components/Hull.svelte +11 -4
  35. package/dist/components/Labels.svelte +21 -11
  36. package/dist/components/Legend.svelte +133 -67
  37. package/dist/components/Legend.svelte.d.ts +7 -3
  38. package/dist/components/Line.svelte +40 -3
  39. package/dist/components/LinearGradient.svelte +35 -4
  40. package/dist/components/Link.svelte +1 -1
  41. package/dist/components/Marker.svelte +37 -26
  42. package/dist/components/MonthPath.svelte +14 -3
  43. package/dist/components/MotionPath.svelte +1 -1
  44. package/dist/components/Pattern.svelte +5 -5
  45. package/dist/components/Pie.svelte +1 -2
  46. package/dist/components/Points.svelte +1 -1
  47. package/dist/components/Polygon.svelte +27 -3
  48. package/dist/components/RadialGradient.svelte +3 -3
  49. package/dist/components/Rect.svelte +55 -5
  50. package/dist/components/Rect.svelte.d.ts +2 -2
  51. package/dist/components/RectClipPath.svelte +4 -3
  52. package/dist/components/RectClipPath.svelte.d.ts +2 -2
  53. package/dist/components/Rule.svelte +30 -23
  54. package/dist/components/Spline.svelte +29 -10
  55. package/dist/components/Text.svelte +59 -13
  56. package/dist/components/TileImage.svelte +19 -4
  57. package/dist/components/TransformContext.svelte +9 -3
  58. package/dist/components/TransformControls.svelte +72 -17
  59. package/dist/components/Voronoi.svelte +12 -13
  60. package/dist/components/charts/ArcChart.svelte +40 -69
  61. package/dist/components/charts/AreaChart.svelte +19 -42
  62. package/dist/components/charts/BarChart.svelte +7 -18
  63. package/dist/components/charts/DefaultTooltip.svelte +2 -2
  64. package/dist/components/charts/DefaultTooltip.svelte.d.ts +1 -1
  65. package/dist/components/charts/LineChart.svelte +61 -66
  66. package/dist/components/charts/LineChart.svelte.d.ts +11 -5
  67. package/dist/components/charts/PieChart.svelte +41 -69
  68. package/dist/components/charts/ScatterChart.svelte +8 -19
  69. package/dist/components/charts/utils.svelte.d.ts +1 -19
  70. package/dist/components/charts/utils.svelte.js +7 -39
  71. package/dist/components/layout/Canvas.svelte +29 -20
  72. package/dist/components/layout/Html.svelte +15 -9
  73. package/dist/components/layout/Svg.svelte +19 -11
  74. package/dist/components/layout/WebGL.svelte +26 -6
  75. package/dist/components/layout/WebGL.svelte.d.ts +5 -2
  76. package/dist/components/tooltip/Tooltip.svelte +60 -29
  77. package/dist/components/tooltip/TooltipContext.svelte +73 -36
  78. package/dist/components/tooltip/TooltipContext.svelte.d.ts +7 -0
  79. package/dist/components/tooltip/TooltipHeader.svelte +27 -14
  80. package/dist/components/tooltip/TooltipItem.svelte +41 -33
  81. package/dist/components/tooltip/TooltipList.svelte +12 -10
  82. package/dist/components/tooltip/TooltipSeparator.svelte +18 -10
  83. package/dist/states/series.svelte.d.ts +30 -0
  84. package/dist/states/series.svelte.js +54 -0
  85. package/dist/styles/daisyui-5.css +6 -0
  86. package/dist/styles/shadcn-svelte.css +11 -0
  87. package/dist/styles/skeleton-3.css +15 -0
  88. package/dist/utils/attributes.d.ts +3 -13
  89. package/dist/utils/attributes.js +4 -18
  90. package/dist/utils/common.d.ts +9 -0
  91. package/dist/utils/common.js +18 -1
  92. package/dist/utils/common.test.js +26 -1
  93. package/dist/utils/math.d.ts +17 -0
  94. package/dist/utils/math.js +17 -0
  95. package/dist/utils/types.d.ts +15 -2
  96. package/package.json +5 -1
@@ -44,12 +44,11 @@
44
44
  LineChartExtraSnippetProps<TData>
45
45
  > & {
46
46
  /**
47
- * The event to be dispatched when the point is clicked.
47
+ * The orientation of the line chart.
48
+ *
49
+ * @default 'horizontal'
48
50
  */
49
- onPointClick?: (
50
- e: MouseEvent,
51
- details: { data: HighlightPointData; series: SeriesData<TData, typeof Spline> }
52
- ) => void;
51
+ orientation?: 'vertical' | 'horizontal';
53
52
 
54
53
  props?: LineChartPropsObjProp;
55
54
 
@@ -64,6 +63,14 @@
64
63
  seriesIndex: number;
65
64
  }
66
65
  >;
66
+
67
+ /**
68
+ * The event to be dispatched when the point is clicked.
69
+ */
70
+ onPointClick?: (
71
+ e: MouseEvent,
72
+ details: { data: HighlightPointData; series: SeriesData<TData, typeof Spline> }
73
+ ) => void;
67
74
  };
68
75
  </script>
69
76
 
@@ -83,12 +90,7 @@
83
90
  import Rule from '../Rule.svelte';
84
91
  import Spline from '../Spline.svelte';
85
92
 
86
- import {
87
- accessor,
88
- chartDataArray,
89
- defaultChartPadding,
90
- findRelatedData,
91
- } from '../../utils/common.js';
93
+ import { chartDataArray, defaultChartPadding, findRelatedData } from '../../utils/common.js';
92
94
  import { asAny } from '../../utils/types.js';
93
95
  import type {
94
96
  SeriesData,
@@ -96,18 +98,22 @@
96
98
  SimplifiedChartPropsObject,
97
99
  SimplifiedChartSnippet,
98
100
  } from './types.js';
99
- import { createLegendProps, SeriesState } from './utils.svelte.js';
101
+ import { SeriesState } from '../../states/series.svelte.js';
102
+ import { createLegendProps } from './utils.svelte.js';
100
103
  import { setTooltipMetaContext } from '../tooltip/tooltipMetaContext.js';
101
- import { layerClass } from '../../utils/attributes.js';
102
104
  import DefaultTooltip from './DefaultTooltip.svelte';
103
105
  import ChartAnnotations from './ChartAnnotations.svelte';
106
+ import { isScaleTime } from '../../utils/scales.svelte.js';
104
107
 
105
108
  let {
106
109
  data = [],
107
110
  x: xProp,
108
- y: yProp,
111
+ xScale,
109
112
  xDomain,
113
+ y: yProp,
114
+ yScale,
110
115
  radial = false,
116
+ orientation = 'horizontal',
111
117
  series: seriesProp,
112
118
  seriesLayout = 'overlap',
113
119
  axis = true,
@@ -137,14 +143,23 @@
137
143
  ...restProps
138
144
  }: LineChartProps<TData> = $props();
139
145
 
146
+ const isVertical = $derived(orientation === 'vertical');
147
+
140
148
  const series = $derived(
141
149
  seriesProp === undefined
142
150
  ? [
143
151
  {
144
152
  key: 'default',
145
- label: typeof yProp === 'string' ? yProp : 'value',
146
- value: yProp,
147
- color: 'var(--color-primary)',
153
+
154
+ label: isVertical
155
+ ? typeof xProp === 'string'
156
+ ? xProp
157
+ : 'value'
158
+ : typeof yProp === 'string'
159
+ ? yProp
160
+ : 'value',
161
+ value: isVertical ? xProp : yProp,
162
+ color: 'var(--color-primary, currentColor)',
148
163
  },
149
164
  ]
150
165
  : seriesProp
@@ -160,21 +175,15 @@
160
175
  function getSplineProps(s: SeriesData<TData, typeof Spline>, i: number) {
161
176
  const splineProps: ComponentProps<typeof Spline> = {
162
177
  data: s.data,
163
- y: s.value ?? (s.data ? undefined : s.key),
178
+ x: isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
179
+ y: !isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
164
180
  stroke: s.color,
181
+ opacity:
182
+ // Checking `visibleSeries.length <= 1` fixes re-animated tweened areas on hover
183
+ seriesState.visibleSeries.length <= 1 || seriesState.isHighlighted(s.key, true) ? 1 : 0.1,
165
184
  ...props.spline,
166
185
  ...s.props,
167
- class: cls(
168
- layerClass('line-chart-line'),
169
- 'transition-opacity',
170
- // Checking `visibleSeries.length > 1` fixes re-animated tweened areas on hover
171
- seriesState.visibleSeries.length > 1 &&
172
- seriesState.highlightKey.current &&
173
- seriesState.highlightKey.current !== s.key &&
174
- 'opacity-10',
175
- props.spline?.class,
176
- s.props?.class
177
- ),
186
+ class: cls(props.spline?.class, s.props?.class),
178
187
  };
179
188
 
180
189
  return splineProps;
@@ -183,18 +192,14 @@
183
192
  function getPointsProps(s: SeriesData<TData, typeof Spline>, i: number) {
184
193
  const pointsProps: ComponentProps<typeof Points> = {
185
194
  data: s.data,
186
- y: s.value ?? (s.data ? undefined : s.key),
195
+ x: isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
196
+ y: !isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
187
197
  fill: s.color,
198
+ stroke: 'var(--color-surface-100, light-dark(white, black))',
199
+ opacity: seriesState.isHighlighted(s.key, true) ? 1 : 0.1,
188
200
  ...props.points,
189
201
  ...(typeof points === 'object' ? points : null),
190
- class: cls(
191
- 'stroke-surface-200 transition-opacity',
192
- seriesState.highlightKey.current &&
193
- seriesState.highlightKey.current !== s.key &&
194
- 'opacity-10',
195
- props.points?.class,
196
- typeof points === 'object' && points.class
197
- ),
202
+ class: cls(props.points?.class, typeof points === 'object' && points.class),
198
203
  };
199
204
 
200
205
  return pointsProps;
@@ -203,26 +208,17 @@
203
208
  function getLabelsProps(s: SeriesData<TData, typeof Spline>, i: number) {
204
209
  const labelsProps: ComponentProps<typeof Labels<TData>> = {
205
210
  data: s.data,
206
- y: s.value ?? (s.data ? undefined : s.key),
211
+ x: isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
212
+ y: !isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
213
+ opacity: seriesState.isHighlighted(s.key, true) ? 1 : 0.1,
207
214
  ...props.labels,
208
215
  ...(typeof labels === 'object' ? labels : null),
209
- class: cls(
210
- 'stroke-surface-200 transition-opacity',
211
- seriesState.highlightKey.current &&
212
- seriesState.highlightKey.current !== s.key &&
213
- 'opacity-10',
214
- props.labels?.class,
215
- typeof labels === 'object' && labels.class
216
- ),
216
+ class: cls(props.labels?.class, typeof labels === 'object' && labels.class),
217
217
  };
218
218
 
219
219
  return labelsProps;
220
220
  }
221
221
 
222
- const highlightPointsProps = $derived(
223
- typeof props.highlight?.points === 'object' ? props.highlight.points : null
224
- );
225
-
226
222
  function getHighlightProps(
227
223
  s: SeriesData<TData, typeof Spline>,
228
224
  i: number
@@ -230,18 +226,22 @@
230
226
  if (!context || !context.tooltip.data) return {};
231
227
  const seriesTooltipData =
232
228
  s.data && context.tooltip.data
233
- ? findRelatedData(s.data, context.tooltip.data, context.x)
229
+ ? (findRelatedData(s.data, context.tooltip.data, context.x) ?? {})
234
230
  : null;
231
+ const highlightPointsProps =
232
+ typeof props.highlight?.points === 'object' ? props.highlight.points : null;
235
233
 
236
234
  return {
237
235
  data: seriesTooltipData,
238
- y: s.value ?? (s.data ? undefined : s.key),
236
+ x: isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
237
+ y: !isVertical ? (s.value ?? (s.data ? undefined : s.key)) : undefined,
239
238
  lines: i === 0,
240
239
  onPointClick: onPointClick
241
240
  ? (e, detail) => onPointClick(e, { ...detail, series: s })
242
241
  : undefined,
243
242
  onPointEnter: () => (seriesState.highlightKey.current = s.key),
244
243
  onPointLeave: () => (seriesState.highlightKey.current = null),
244
+ opacity: seriesState.isHighlighted(s.key, true) ? 1 : 0.1,
245
245
  ...props.highlight,
246
246
  points:
247
247
  props.highlight?.points == false
@@ -249,13 +249,6 @@
249
249
  : {
250
250
  ...highlightPointsProps,
251
251
  fill: s.color,
252
- class: cls(
253
- 'transition-opacity',
254
- seriesState.highlightKey.current &&
255
- seriesState.highlightKey.current !== s.key &&
256
- 'opacity-10',
257
- highlightPointsProps?.class
258
- ),
259
252
  },
260
253
  };
261
254
  }
@@ -264,8 +257,8 @@
264
257
  return createLegendProps({
265
258
  seriesState,
266
259
  props: {
267
- ...props.legend,
268
260
  ...(typeof legend === 'object' ? legend : null),
261
+ ...props.legend,
269
262
  },
270
263
  });
271
264
  }
@@ -324,18 +317,20 @@
324
317
  <Chart
325
318
  bind:context
326
319
  data={chartData}
327
- x={xProp}
320
+ x={xProp ?? (isVertical ? series.map((s) => s.value ?? s.key) : undefined)}
328
321
  {xDomain}
329
- y={yProp ?? series.map((s) => s.value ?? s.key)}
330
- yBaseline={0}
331
- yNice
322
+ xBaseline={!isVertical || (xScale && isScaleTime(xScale)) ? undefined : 0}
323
+ xNice={orientation === 'vertical'}
324
+ y={yProp ?? (isVertical ? undefined : series.map((s) => s.value ?? s.key))}
325
+ yBaseline={isVertical || (yScale && isScaleTime(yScale)) ? undefined : 0}
326
+ yNice={orientation === 'horizontal'}
332
327
  {radial}
333
328
  padding={radial ? undefined : defaultChartPadding(axis, legend)}
334
329
  {...restProps}
335
330
  tooltip={tooltip === false
336
331
  ? false
337
332
  : {
338
- mode: 'quadtree-x',
333
+ mode: isVertical ? 'quadtree-y' : 'quadtree-x',
339
334
  onclick: onTooltipClick,
340
335
  debug,
341
336
  ...props.tooltip?.context,
@@ -10,12 +10,11 @@ export type LineChartExtraSnippetProps<TData> = {
10
10
  export type LineChartPropsObjProp = Pick<SimplifiedChartPropsObject, 'brush' | 'canvas' | 'grid' | 'highlight' | 'labels' | 'legend' | 'points' | 'rule' | 'spline' | 'svg' | 'tooltip' | 'xAxis' | 'yAxis'>;
11
11
  export type LineChartProps<TData> = SimplifiedChartProps<TData, typeof Spline, LineChartExtraSnippetProps<TData>> & {
12
12
  /**
13
- * The event to be dispatched when the point is clicked.
13
+ * The orientation of the line chart.
14
+ *
15
+ * @default 'horizontal'
14
16
  */
15
- onPointClick?: (e: MouseEvent, details: {
16
- data: HighlightPointData;
17
- series: SeriesData<TData, typeof Spline>;
18
- }) => void;
17
+ orientation?: 'vertical' | 'horizontal';
19
18
  props?: LineChartPropsObjProp;
20
19
  spline?: SimplifiedChartSnippet<TData, typeof Spline, LineChartExtraSnippetProps<TData> & {
21
20
  props: ComponentProps<typeof Spline>;
@@ -24,6 +23,13 @@ export type LineChartProps<TData> = SimplifiedChartProps<TData, typeof Spline, L
24
23
  */
25
24
  seriesIndex: number;
26
25
  }>;
26
+ /**
27
+ * The event to be dispatched when the point is clicked.
28
+ */
29
+ onPointClick?: (e: MouseEvent, details: {
30
+ data: HighlightPointData;
31
+ series: SeriesData<TData, typeof Spline>;
32
+ }) => void;
27
33
  };
28
34
  import { type ComponentProps } from 'svelte';
29
35
  import Axis from '../Axis.svelte';
@@ -172,11 +172,11 @@
172
172
  </script>
173
173
 
174
174
  <script lang="ts" generics="TData">
175
- import { onMount, type ComponentProps, type Snippet } from 'svelte';
175
+ import { onMount, type ComponentProps } from 'svelte';
176
176
  import { format } from '@layerstack/utils';
177
- import { cls } from '@layerstack/tailwind';
178
- import { SelectionState } from '@layerstack/svelte-state';
179
177
  import type { PieArcDatum } from 'd3-shape';
178
+ import { schemeObservable10 } from 'd3-scale-chromatic';
179
+ import { getObjectOrNull } from '../../utils/common.js';
180
180
 
181
181
  import Arc from '../Arc.svelte';
182
182
  import Chart from '../Chart.svelte';
@@ -194,7 +194,8 @@
194
194
  SimplifiedChartPropsObject,
195
195
  SimplifiedChartSnippet,
196
196
  } from './types.js';
197
- import { HighlightKey } from './utils.svelte.js';
197
+ import { SeriesState } from '../../states/series.svelte.js';
198
+ import { createLegendProps } from './utils.svelte.js';
198
199
  import { setTooltipMetaContext } from '../tooltip/tooltipMetaContext.js';
199
200
 
200
201
  let {
@@ -237,67 +238,37 @@
237
238
  const series = $derived(
238
239
  seriesProp === undefined ? [{ key: 'default', value: value }] : seriesProp
239
240
  );
241
+ const seriesState = new SeriesState(() => series);
240
242
 
241
243
  const keyAccessor = $derived(accessor(key));
242
244
  const labelAccessor = $derived(accessor(label));
243
245
  const valueAccessor = $derived(accessor(value));
244
246
  const cAccessor = $derived(accessor(c));
245
247
 
246
- const allSeriesData = $derived(
247
- series
248
- .flatMap((s) => s.data?.map((d) => ({ seriesKey: s.key, ...d })))
249
- .filter((d) => d) as Array<TData>
250
- );
251
-
252
248
  const chartData = $derived(
253
- allSeriesData.length ? allSeriesData : chartDataArray(data)
249
+ seriesState.allSeriesData.length ? seriesState.allSeriesData : chartDataArray(data)
254
250
  ) as Array<TData>;
255
251
 
256
- const seriesColors = $derived(series.map((s) => s.color).filter((d) => d != null));
257
-
258
- const highlightKey = new HighlightKey<TData, typeof Arc>();
259
- const selectedKeys = new SelectionState();
260
- const selectedSeries = new SelectionState();
261
-
262
252
  const visibleData = $derived(
263
253
  chartData.filter((d) => {
264
254
  const dataKey = keyAccessor(d);
265
- return selectedKeys.isEmpty() || selectedKeys.isSelected(dataKey);
255
+ return seriesState.selectedKeys.isEmpty() || seriesState.selectedKeys.isSelected(dataKey);
266
256
  })
267
257
  );
268
258
 
269
- // TODO: note, I added this because it wasn't consistent with all the other charts
270
- // unsure if it is correct but will validate with Sean
271
- const visibleSeries = $derived(
272
- series.filter((s) => selectedSeries.isEmpty() || selectedSeries.isSelected(s.key))
273
- );
274
-
275
259
  function getLegendProps(): ComponentProps<typeof Legend> {
276
- return {
277
- tickFormat: (tick) => {
278
- const item = chartData.find((d) => keyAccessor(d) === tick);
279
- return item ? (labelAccessor(item) ?? tick) : tick;
280
- },
281
- placement: 'bottom',
282
- variant: 'swatches',
283
- onclick: (e, item) => {
284
- selectedKeys.toggle(item.value);
285
- // TODO: investigate
286
- // selectedSeries.toggle(item.value);
287
- },
288
- onpointerenter: (e, item) => (highlightKey.current = item.value),
289
- onpointerleave: (e) => (highlightKey.current = null),
290
- ...props.legend,
291
- ...(typeof legend === 'object' ? legend : null),
292
- classes: {
293
- item: (item) =>
294
- visibleData.length && !visibleData.some((d) => keyAccessor(d) === item.value)
295
- ? 'opacity-50'
296
- : '',
297
- ...props.legend?.classes,
298
- ...(typeof legend === 'object' ? legend.classes : null),
260
+ return createLegendProps({
261
+ seriesState,
262
+ props: {
263
+ tickFormat: (tick) => {
264
+ // Use data label instead of series label
265
+ const item = chartData.find((d) => keyAccessor(d) === tick);
266
+ return item ? (labelAccessor(item) ?? tick) : tick;
267
+ },
268
+ ...props.legend,
269
+ ...getObjectOrNull(legend),
299
270
  },
300
- };
271
+ });
301
272
  }
302
273
 
303
274
  function getGroupProps(): ComponentProps<typeof Group> {
@@ -338,7 +309,8 @@
338
309
  return {
339
310
  startAngle: arc.startAngle,
340
311
  endAngle: arc.endAngle,
341
- outerRadius: visibleSeries.length > 1 ? seriesIndex * (outerRadius ?? 0) : outerRadius,
312
+ outerRadius:
313
+ seriesState.visibleSeries.length > 1 ? seriesIndex * (outerRadius ?? 0) : outerRadius,
342
314
  innerRadius,
343
315
  cornerRadius,
344
316
  padAngle,
@@ -350,10 +322,7 @@
350
322
  // Workaround for `tooltip={{ mode: 'manual' }}
351
323
  onTooltipClick(e, { data: arc.data });
352
324
  },
353
- class: cls(
354
- 'transition-opacity',
355
- highlightKey.current && highlightKey.current !== keyAccessor(arc.data) && 'opacity-50'
356
- ),
325
+ opacity: seriesState.isHighlighted(keyAccessor(arc.data), true) ? 1 : 0.5,
357
326
  ...props.arc,
358
327
  ...s.props,
359
328
  ...arcDataProps,
@@ -382,7 +351,7 @@
382
351
  return key;
383
352
  },
384
353
  get visibleSeries() {
385
- return visibleSeries;
354
+ return seriesState.visibleSeries;
386
355
  },
387
356
  });
388
357
  </script>
@@ -394,19 +363,21 @@
394
363
  x={value}
395
364
  c={key}
396
365
  cDomain={chartData.map(keyAccessor)}
397
- cRange={seriesColors.length
398
- ? seriesColors
366
+ cRange={seriesState.allSeriesColors.length
367
+ ? seriesState.allSeriesColors
399
368
  : c !== key
400
369
  ? chartData.map((d) => cAccessor(d))
401
370
  : [
402
- 'var(--color-primary)',
403
- 'var(--color-secondary)',
404
- 'var(--color-info)',
405
- 'var(--color-success)',
406
- 'var(--color-warning)',
407
- 'var(--color-danger)',
371
+ `var(--color-primary, ${schemeObservable10[0]})`,
372
+ `var(--color-secondary, ${schemeObservable10[1]})`,
373
+ `var(--color-info, ${schemeObservable10[2]})`,
374
+ `var(--color-success, ${schemeObservable10[3]})`,
375
+ `var(--color-warning, ${schemeObservable10[4]})`,
376
+ `var(--color-danger, ${schemeObservable10[5]})`,
408
377
  ]}
409
- padding={{ bottom: legend === true ? 32 : 0 }}
378
+ padding={{
379
+ bottom: legend === true || getObjectOrNull(legend)?.placement?.includes('bottom') ? 32 : 0,
380
+ }}
410
381
  {...restProps}
411
382
  tooltip={tooltip === false
412
383
  ? false
@@ -420,10 +391,10 @@
420
391
  color: cAccessor,
421
392
  context,
422
393
  series,
423
- visibleSeries,
394
+ visibleSeries: seriesState.visibleSeries,
424
395
  visibleData,
425
- highlightKey: highlightKey.current,
426
- setHighlightKey: highlightKey.set,
396
+ highlightKey: seriesState.highlightKey.current,
397
+ setHighlightKey: seriesState.highlightKey.set,
427
398
  getLegendProps,
428
399
  getGroupProps,
429
400
  }}
@@ -444,7 +415,8 @@
444
415
  {@render marks(snippetProps)}
445
416
  {:else}
446
417
  <Group {...getGroupProps()}>
447
- {#each visibleSeries as s, seriesIdx (s.key)}
418
+ <!-- Use `series` instead of `visibleSeries` since data is filtered (legend) instead of series -->
419
+ {#each series as s, seriesIdx (s.key)}
448
420
  {#if typeof pie === 'function'}
449
421
  {@render pie({
450
422
  ...snippetProps,
@@ -496,8 +468,8 @@
496
468
  value={valueAccessor(data)}
497
469
  color={context.cScale?.(context.c(data))}
498
470
  {format}
499
- onpointerenter={() => (highlightKey.current = keyAccessor(data))}
500
- onpointerleave={() => (highlightKey.current = null)}
471
+ onpointerenter={() => (seriesState.highlightKey.current = keyAccessor(data))}
472
+ onpointerleave={() => (seriesState.highlightKey.current = null)}
501
473
  {...props.tooltip?.item}
502
474
  />
503
475
  </Tooltip.List>
@@ -61,9 +61,10 @@
61
61
  import Rule from '../Rule.svelte';
62
62
  import * as Tooltip from '../tooltip/index.js';
63
63
 
64
- import { accessor, chartDataArray, defaultChartPadding } from '../../utils/common.js';
64
+ import { chartDataArray, defaultChartPadding } from '../../utils/common.js';
65
65
  import { asAny } from '../../utils/types.js';
66
- import { createLegendProps, SeriesState } from './utils.svelte.js';
66
+ import { SeriesState } from '../../states/series.svelte.js';
67
+ import { createLegendProps } from './utils.svelte.js';
67
68
 
68
69
  let {
69
70
  data = [],
@@ -117,16 +118,10 @@
117
118
  return {
118
119
  data: s.data,
119
120
  fill: s.color,
121
+ opacity: seriesState.isHighlighted(s.key, true) ? 1 : 0.1,
120
122
  ...props.points,
121
123
  ...s.props,
122
- class: cls(
123
- 'transition-opacity',
124
- seriesState.highlightKey.current &&
125
- seriesState.highlightKey.current !== s.key &&
126
- 'opacity-10',
127
- props.points?.class,
128
- s.props?.class
129
- ),
124
+ class: cls(props.points?.class, s.props?.class),
130
125
  };
131
126
  }
132
127
 
@@ -136,16 +131,10 @@
136
131
  ): ComponentProps<typeof Labels<TData>> {
137
132
  return {
138
133
  data: s.data,
134
+ opacity: seriesState.isHighlighted(s.key, true) ? 1 : 0.1,
139
135
  ...props.labels,
140
136
  ...(typeof labels === 'object' ? labels : null),
141
- class: cls(
142
- 'stroke-surface-200 transition-opacity',
143
- seriesState.highlightKey.current &&
144
- seriesState.highlightKey.current !== s.key &&
145
- 'opacity-10',
146
- props.labels?.class,
147
- typeof labels === 'object' && labels.class
148
- ),
137
+ class: cls(props.labels?.class, typeof labels === 'object' && labels.class),
149
138
  };
150
139
  }
151
140
 
@@ -230,7 +219,7 @@
230
219
  {yDomain}
231
220
  yNice
232
221
  c={yProp}
233
- cRange={['var(--color-primary)']}
222
+ cRange={['var(--color-primary, currentColor)']}
234
223
  padding={defaultChartPadding(axis, legend)}
235
224
  {...restProps}
236
225
  tooltip={tooltip === false
@@ -1,24 +1,6 @@
1
1
  import type { Component, ComponentProps } from 'svelte';
2
- import { SelectionState } from '@layerstack/svelte-state';
3
- import type { SeriesData } from './types.js';
4
2
  import type Legend from '../Legend.svelte';
5
- export declare class HighlightKey<TData, SeriesComponent extends Component> {
6
- current: string | null;
7
- set: (seriesKey: typeof this.current) => void;
8
- }
9
- export declare class SeriesState<TData, TComponent extends Component> {
10
- #private;
11
- selectedSeries: SelectionState<unknown, false>;
12
- selectedKeys: SelectionState<unknown, false>;
13
- highlightKey: HighlightKey<TData, TComponent>;
14
- constructor(getSeries: () => SeriesData<TData, TComponent>[]);
15
- get series(): SeriesData<TData, TComponent>[];
16
- get isDefaultSeries(): boolean;
17
- get allSeriesData(): Array<TData & {
18
- seriesKey: string;
19
- }>;
20
- get visibleSeries(): SeriesData<TData, TComponent>[];
21
- }
3
+ import type { SeriesState } from '../../states/series.svelte.js';
22
4
  type CreateLegendPropsOptions<TData, TComponent extends Component> = {
23
5
  seriesState: SeriesState<TData, TComponent>;
24
6
  props: Partial<ComponentProps<typeof Legend>>;
@@ -1,38 +1,6 @@
1
- import { SelectionState } from '@layerstack/svelte-state';
2
1
  import { scaleOrdinal } from 'd3-scale';
3
- export class HighlightKey {
4
- current = $state(null);
5
- set = (seriesKey) => {
6
- this.current = seriesKey;
7
- };
8
- }
9
- export class SeriesState {
10
- #series = $state.raw([]);
11
- selectedSeries = new SelectionState();
12
- selectedKeys = new SelectionState();
13
- highlightKey = new HighlightKey();
14
- constructor(getSeries) {
15
- this.#series = getSeries();
16
- $effect.pre(() => {
17
- // keep series state in sync with the prop
18
- this.#series = getSeries();
19
- });
20
- }
21
- get series() {
22
- return this.#series;
23
- }
24
- get isDefaultSeries() {
25
- return this.#series.length === 1 && this.#series[0].key === 'default';
26
- }
27
- get allSeriesData() {
28
- return this.#series
29
- .flatMap((s) => s.data?.map((d) => ({ seriesKey: s.key, ...d })))
30
- .filter((d) => d);
31
- }
32
- get visibleSeries() {
33
- return this.#series.filter((s) => this.selectedSeries.isEmpty() || this.selectedSeries.isSelected(s.key));
34
- }
35
- }
2
+ import { cls } from '@layerstack/tailwind';
3
+ import { resolveMaybeFn } from '../../utils/common.js';
36
4
  /**
37
5
  * A prop builder for the legend component shared between the simplified charts.
38
6
  */
@@ -44,15 +12,15 @@ export function createLegendProps(opts) {
44
12
  tickFormat: (key) => opts.seriesState.series.find((s) => s.key === key)?.label ?? key,
45
13
  placement: 'bottom',
46
14
  variant: 'swatches',
47
- onclick: (_, item) => opts.seriesState.selectedSeries.toggle(item.value),
15
+ selected: opts.seriesState.selectedKeys.current,
16
+ onclick: (_, item) => opts.seriesState.selectedKeys.toggle(item.value),
48
17
  onpointerenter: (_, item) => (opts.seriesState.highlightKey.current = item.value),
49
18
  onpointerleave: () => (opts.seriesState.highlightKey.current = null),
50
19
  ...opts.props,
51
20
  classes: {
52
- item: (item) => opts.seriesState.visibleSeries.length &&
53
- !opts.seriesState.visibleSeries.some((s) => s.key === item.value)
54
- ? 'opacity-50'
55
- : '',
21
+ item: (item) => {
22
+ return cls(resolveMaybeFn(opts.props?.classes?.item, item));
23
+ },
56
24
  ...opts.props?.classes,
57
25
  },
58
26
  };