@internetstiftelsen/charts 0.10.0 → 0.11.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 (57) hide show
  1. package/README.md +65 -1
  2. package/dist/area.d.ts +11 -1
  3. package/dist/area.js +199 -55
  4. package/dist/bar.d.ts +26 -1
  5. package/dist/bar.js +425 -306
  6. package/dist/base-chart.d.ts +5 -0
  7. package/dist/base-chart.js +91 -67
  8. package/dist/chart-group.d.ts +16 -0
  9. package/dist/chart-group.js +201 -143
  10. package/dist/donut-center-content.d.ts +1 -0
  11. package/dist/donut-center-content.js +21 -38
  12. package/dist/donut-chart.js +32 -32
  13. package/dist/gauge-chart.d.ts +23 -4
  14. package/dist/gauge-chart.js +235 -185
  15. package/dist/lazy-mount.d.ts +13 -0
  16. package/dist/lazy-mount.js +90 -0
  17. package/dist/legend.js +10 -9
  18. package/dist/line.d.ts +9 -1
  19. package/dist/line.js +144 -24
  20. package/dist/pie-chart.d.ts +3 -0
  21. package/dist/pie-chart.js +49 -47
  22. package/dist/radial-chart-base.d.ts +4 -3
  23. package/dist/radial-chart-base.js +27 -12
  24. package/dist/scatter.d.ts +5 -1
  25. package/dist/scatter.js +92 -9
  26. package/dist/theme.js +17 -0
  27. package/dist/tooltip.d.ts +55 -3
  28. package/dist/tooltip.js +968 -159
  29. package/dist/types.d.ts +23 -1
  30. package/dist/utils.js +11 -19
  31. package/dist/x-axis.d.ts +10 -0
  32. package/dist/x-axis.js +190 -149
  33. package/dist/xy-animation.d.ts +3 -0
  34. package/dist/xy-animation.js +2 -0
  35. package/dist/xy-chart.d.ts +35 -1
  36. package/dist/xy-chart.js +358 -153
  37. package/dist/xy-motion/config.d.ts +2 -0
  38. package/dist/xy-motion/config.js +177 -0
  39. package/dist/xy-motion/driver.d.ts +9 -0
  40. package/dist/xy-motion/driver.js +10 -0
  41. package/dist/xy-motion/helpers.d.ts +17 -0
  42. package/dist/xy-motion/helpers.js +105 -0
  43. package/dist/xy-motion/live-state.d.ts +8 -0
  44. package/dist/xy-motion/live-state.js +240 -0
  45. package/dist/xy-motion/noop-xy-motion-driver.d.ts +9 -0
  46. package/dist/xy-motion/noop-xy-motion-driver.js +15 -0
  47. package/dist/xy-motion/types.d.ts +85 -0
  48. package/dist/xy-motion/types.js +1 -0
  49. package/dist/xy-motion/xy-motion-driver.d.ts +19 -0
  50. package/dist/xy-motion/xy-motion-driver.js +130 -0
  51. package/dist/y-axis.d.ts +7 -2
  52. package/dist/y-axis.js +99 -10
  53. package/docs/components.md +50 -1
  54. package/docs/getting-started.md +35 -0
  55. package/docs/theming.md +14 -0
  56. package/docs/xy-chart.md +88 -7
  57. package/package.json +5 -4
package/README.md CHANGED
@@ -10,7 +10,8 @@ A framework-agnostic, composable charting library built on D3.js with TypeScript
10
10
  - **Combined Chart Layouts** - `ChartGroup` composes existing charts into shared dashboards with one coordinated legend
11
11
  - **Divergent Bar Support** - Bar charts automatically render from zero and diverge around `0` for mixed positive/negative values
12
12
  - **Mirrored Bar Sides** - Horizontal bars can mirror a series to the left for population-pyramid style charts without changing source data
13
- - **Radial Value Labels** - Pie and donut charts support optional on-chart labels with custom formatters
13
+ - **Custom Value Labels** - XY, pie, and donut charts support optional on-chart labels with custom formatters
14
+ - **Optional XY Animation** - Animate XY series on first render and `chart.update(...)` with `animate`
14
15
  - **Optional Gauge Animation** - Animate gauge value transitions with `gauge.animate`
15
16
  - **Stacking Control** - Bar stacking modes with optional reversed visual series order
16
17
  - **Axis Direction Control** - Use `scales.x.reverse` / `scales.y.reverse` to flip an axis when needed
@@ -18,6 +19,7 @@ A framework-agnostic, composable charting library built on D3.js with TypeScript
18
19
  - **Explicit or Responsive Sizing** - Set top-level `width`/`height` or let the container drive size
19
20
  - **Auto Resize** - Built-in ResizeObserver handles responsive behavior
20
21
  - **Responsive Policy** - Chart-level container-query overrides for theme and components
22
+ - **Lazy Mount Utility** - Observe a container and defer chart imports until it approaches the viewport
21
23
  - **Type Safe** - Written in TypeScript with full type definitions
22
24
  - **Data Validation** - Built-in validation with helpful error messages
23
25
  - **Auto Colors** - Smart color palette with sensible defaults
@@ -110,6 +112,68 @@ from the render container.
110
112
  Theme overrides are deep-partial, so nested overrides like
111
113
  `theme.axis.fontSize` preserve the rest of the theme defaults.
112
114
 
115
+ ## XY Animation
116
+
117
+ Enable `animate` on `XYChart` when you want series marks to animate on the
118
+ first render and on later `chart.update(...)` calls.
119
+
120
+ ```typescript
121
+ const chart = new XYChart({
122
+ data,
123
+ animate: {
124
+ duration: 700,
125
+ easing: 'ease-in-out',
126
+ },
127
+ });
128
+
129
+ chart
130
+ .addChild(new XAxis({ dataKey: 'month' }))
131
+ .addChild(new YAxis())
132
+ .addChild(new Line({ dataKey: 'value' }));
133
+
134
+ chart.render('#chart-container');
135
+
136
+ await chart.whenReady();
137
+ ```
138
+
139
+ Animation is off by default, applies to XY series marks only, and visual
140
+ exports always render the final static state.
141
+
142
+ ## Lazy Loading
143
+
144
+ Use `mountChartWhenVisible` when you want the page to wait until a chart is
145
+ near the viewport before importing chart code and rendering it.
146
+
147
+ ```typescript
148
+ import { mountChartWhenVisible } from '@internetstiftelsen/charts/lazy-mount';
149
+
150
+ const lazyChart = mountChartWhenVisible(
151
+ '#chart-container',
152
+ async (container) => {
153
+ const [{ XYChart }, { Line }, { XAxis }, { YAxis }] = await Promise.all([import('@internetstiftelsen/charts/xy-chart'), import('@internetstiftelsen/charts/line'), import('@internetstiftelsen/charts/x-axis'), import('@internetstiftelsen/charts/y-axis')]);
154
+
155
+ const chart = new XYChart({ data });
156
+ chart
157
+ .addChild(new XAxis({ dataKey: 'month' }))
158
+ .addChild(new YAxis())
159
+ .addChild(new Line({ dataKey: 'value' }));
160
+
161
+ chart.render(container);
162
+ return chart;
163
+ },
164
+ {
165
+ rootMargin: '240px 0px',
166
+ },
167
+ );
168
+
169
+ // Optional: preload manually before it scrolls into view
170
+ await lazyChart.load();
171
+ ```
172
+
173
+ The utility is intentionally small: it observes the container, calls your async
174
+ factory once, and gives you `load()` plus `destroy()` so higher-level DOM
175
+ conventions such as `data-chart` scanners can build on top of it.
176
+
113
177
  ## Chart Groups
114
178
 
115
179
  Use `ChartGroup` when you want to combine existing charts into one layout while
package/dist/area.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type Selection } from 'd3';
2
2
  import type { AreaConfig, AreaCurveType, AreaConfigBase, AreaStackingContext, ChartTheme, D3Scale, DataItem, ExportHooks, LineValueLabelConfig, ScaleType } from './types.js';
3
3
  import type { ChartComponent } from './chart-interface.js';
4
+ import type { XYAreaAnimationContext, XYAreaPointSnapshot, XYSeriesRenderResult } from './xy-motion/types.js';
4
5
  export declare class Area implements ChartComponent<AreaConfigBase> {
5
6
  readonly type: "area";
6
7
  readonly dataKey: string;
@@ -20,6 +21,15 @@ export declare class Area implements ChartComponent<AreaConfigBase> {
20
21
  getExportConfig(): AreaConfigBase;
21
22
  createExportComponent(override?: Partial<AreaConfigBase>): ChartComponent<AreaConfigBase>;
22
23
  private getStackValues;
23
- render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType: ScaleType | undefined, theme: ChartTheme, stackingContext?: AreaStackingContext, valueLabelLayer?: Selection<SVGGElement, undefined, null, undefined>): void;
24
+ render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType: ScaleType | undefined, theme: ChartTheme, stackingContext?: AreaStackingContext, valueLabelLayer?: Selection<SVGGElement, undefined, null, undefined>, animation?: XYAreaAnimationContext): XYSeriesRenderResult<XYAreaPointSnapshot>;
25
+ private buildAreaData;
26
+ private buildAnimatedAreaData;
27
+ private createSnapshot;
28
+ private renderAreaFill;
29
+ private renderLinePath;
30
+ private getInitialAreaPathValue;
31
+ private getInitialLinePathValue;
32
+ private createRevealTransitions;
33
+ private renderPoints;
24
34
  private renderValueLabels;
25
35
  }
package/dist/area.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { area, curveBasis, curveCardinal, curveLinear, curveMonotoneX, curveNatural, curveStep, line, } from 'd3';
2
2
  import { mergeDeep, sanitizeForCSS } from './utils.js';
3
3
  import { getScalePosition } from './scale-utils.js';
4
+ import { buildXYDatumSnapshotKeys, createTransitionCompletionPromise, createLeftToRightRevealTransition, getEnterStaggerTiming, } from './xy-motion/helpers.js';
4
5
  const AREA_CURVE_FACTORIES = {
5
6
  linear: curveLinear,
6
7
  monotone: curveMonotoneX,
@@ -157,9 +158,9 @@ export class Area {
157
158
  y1: cumulative + value,
158
159
  };
159
160
  }
160
- render(plotGroup, data, xKey, x, y, parseValue, xScaleType = 'band', theme, stackingContext, valueLabelLayer) {
161
- const getXPosition = (d) => {
162
- const scaled = getScalePosition(x, d.data[xKey], xScaleType);
161
+ render(plotGroup, data, xKey, x, y, parseValue, xScaleType = 'band', theme, stackingContext, valueLabelLayer, animation) {
162
+ const getXPosition = (dataPoint) => {
163
+ const scaled = getScalePosition(x, dataPoint[xKey], xScaleType);
163
164
  return scaled + (x.bandwidth ? x.bandwidth() / 2 : 0);
164
165
  };
165
166
  const hasValidValue = (d) => {
@@ -169,74 +170,215 @@ export class Area {
169
170
  }
170
171
  return Number.isFinite(parseValue(value));
171
172
  };
172
- const areaData = data.map((d) => {
173
- const valid = hasValidValue(d);
173
+ const snapshotKeys = buildXYDatumSnapshotKeys(data, xKey);
174
+ const areaData = this.buildAreaData(data, xKey, snapshotKeys, y, parseValue, stackingContext, getXPosition, hasValidValue);
175
+ const animatedAreaData = this.buildAnimatedAreaData(areaData, animation);
176
+ const curveFactory = AREA_CURVE_FACTORIES[this.curve] || curveLinear;
177
+ const sanitizedKey = sanitizeForCSS(this.dataKey);
178
+ const transitions = this.renderAreaFill(plotGroup, areaData, animatedAreaData, curveFactory, sanitizedKey, animation);
179
+ const snapshot = this.createSnapshot(areaData);
180
+ if (this.showLine) {
181
+ const lineTransitions = this.renderLinePath(plotGroup, areaData, animatedAreaData, curveFactory, theme, sanitizedKey, animation);
182
+ transitions.push(...lineTransitions);
183
+ }
184
+ if (this.showPoints) {
185
+ const pointTransitions = this.renderPoints(plotGroup, areaData, animatedAreaData, theme, sanitizedKey, animation);
186
+ transitions.push(...pointTransitions);
187
+ }
188
+ if (this.valueLabel?.show) {
189
+ this.renderValueLabels(valueLabelLayer ?? plotGroup, areaData.filter((d) => d.valid), y, parseValue, theme);
190
+ }
191
+ return {
192
+ snapshot,
193
+ transitions,
194
+ };
195
+ }
196
+ buildAreaData(data, xKey, snapshotKeys, y, parseValue, stackingContext, getXPosition, hasValidValue) {
197
+ return data.map((entry, index) => {
198
+ const valid = hasValidValue(entry);
174
199
  const stackValues = valid
175
- ? this.getStackValues(d, xKey, parseValue, stackingContext)
200
+ ? this.getStackValues(entry, xKey, parseValue, stackingContext)
176
201
  : { y0: this.baseline, y1: this.baseline };
177
202
  return {
178
- data: d,
203
+ data: entry,
179
204
  valid,
180
- y0: stackValues.y0,
181
- y1: stackValues.y1,
205
+ snapshotKey: snapshotKeys[index] ?? String(index),
206
+ x: getXPosition(entry),
207
+ y0: y(stackValues.y0) ?? 0,
208
+ y1: y(stackValues.y1) ?? 0,
182
209
  };
183
210
  });
184
- const curveFactory = AREA_CURVE_FACTORIES[this.curve] || curveLinear;
211
+ }
212
+ buildAnimatedAreaData(areaData, animation) {
213
+ return areaData.map((entry) => {
214
+ if (!animation || !entry.valid) {
215
+ return entry;
216
+ }
217
+ const previousSnapshot = animation.previousSnapshot?.get(entry.snapshotKey);
218
+ return {
219
+ ...entry,
220
+ x: previousSnapshot?.x ?? entry.x,
221
+ y0: previousSnapshot?.y0 ?? entry.y0,
222
+ y1: previousSnapshot?.y1 ?? entry.y0,
223
+ };
224
+ });
225
+ }
226
+ createSnapshot(areaData) {
227
+ const snapshot = new Map();
228
+ areaData.forEach((entry) => {
229
+ if (!entry.valid) {
230
+ return;
231
+ }
232
+ snapshot.set(entry.snapshotKey, {
233
+ x: entry.x,
234
+ y0: entry.y0,
235
+ y1: entry.y1,
236
+ });
237
+ });
238
+ return snapshot;
239
+ }
240
+ renderAreaFill(plotGroup, areaData, animatedAreaData, curveFactory, sanitizedKey, animation) {
241
+ const areaOpacity = Math.max(0, Math.min(1, this.opacity));
185
242
  const areaGenerator = area()
186
243
  .defined((d) => d.valid)
187
244
  .curve(curveFactory)
188
- .x(getXPosition)
189
- .y0((d) => y(d.y0) || 0)
190
- .y1((d) => y(d.y1) || 0);
191
- const areaOpacity = Math.max(0, Math.min(1, this.opacity));
192
- const sanitizedKey = sanitizeForCSS(this.dataKey);
193
- plotGroup
245
+ .x((entry) => entry.x)
246
+ .y0((entry) => entry.y0)
247
+ .y1((entry) => entry.y1);
248
+ const finalAreaPath = areaGenerator(areaData);
249
+ const areaPath = plotGroup
194
250
  .append('path')
195
251
  .datum(areaData)
196
252
  .attr('class', `area-${sanitizedKey}`)
197
253
  .attr('fill', this.fill)
198
254
  .attr('fill-opacity', areaOpacity)
199
255
  .attr('stroke', 'none')
200
- .attr('d', areaGenerator);
201
- if (this.showLine) {
202
- const lineGenerator = line()
203
- .defined((d) => d.valid)
204
- .curve(curveFactory)
205
- .x(getXPosition)
206
- .y((d) => y(d.y1) || 0);
207
- const lineStrokeWidth = this.strokeWidth ?? theme.line.strokeWidth;
208
- plotGroup
209
- .append('path')
210
- .datum(areaData)
211
- .attr('class', `area-line-${sanitizedKey}`)
212
- .attr('fill', 'none')
213
- .attr('stroke', this.stroke)
214
- .attr('stroke-width', lineStrokeWidth)
215
- .attr('d', lineGenerator);
256
+ .attr('d', this.getInitialAreaPathValue(finalAreaPath, areaData, animatedAreaData, areaGenerator, animation));
257
+ if (!animation || !finalAreaPath) {
258
+ return [];
216
259
  }
217
- if (this.showPoints) {
218
- const validData = areaData.filter((d) => d.valid);
219
- const pointSize = this.pointSize ?? theme.line.point.size;
220
- const pointStrokeWidth = theme.line.point.strokeWidth;
221
- const pointStrokeColor = theme.line.point.strokeColor || this.stroke;
222
- const pointColor = theme.line.point.color || this.stroke;
223
- plotGroup
224
- .selectAll(`.area-point-${sanitizedKey}`)
225
- .data(validData)
226
- .join('circle')
227
- .attr('class', `area-point-${sanitizedKey}`)
228
- .attr('cx', getXPosition)
229
- .attr('cy', (d) => y(d.y1) || 0)
230
- .attr('r', pointSize)
231
- .attr('fill', pointColor)
232
- .attr('stroke', pointStrokeColor)
233
- .attr('stroke-width', pointStrokeWidth);
260
+ const revealTransitions = this.createRevealTransitions(areaPath.node(), `area-${sanitizedKey}-reveal`, animation, animation.previousAreaRevealProgress);
261
+ const transition = areaPath
262
+ .transition()
263
+ .duration(animation.duration)
264
+ .ease(animation.easing)
265
+ .attr('d', finalAreaPath);
266
+ return [
267
+ ...revealTransitions,
268
+ createTransitionCompletionPromise(transition),
269
+ ];
270
+ }
271
+ renderLinePath(plotGroup, areaData, animatedAreaData, curveFactory, theme, sanitizedKey, animation) {
272
+ const lineGenerator = line()
273
+ .defined((d) => d.valid)
274
+ .curve(curveFactory)
275
+ .x((entry) => entry.x)
276
+ .y((entry) => entry.y1);
277
+ const lineStrokeWidth = this.strokeWidth ?? theme.line.strokeWidth;
278
+ const finalPath = lineGenerator(areaData);
279
+ const linePath = plotGroup
280
+ .append('path')
281
+ .datum(areaData)
282
+ .attr('class', `area-line-${sanitizedKey}`)
283
+ .attr('fill', 'none')
284
+ .attr('stroke', this.stroke)
285
+ .attr('stroke-width', lineStrokeWidth)
286
+ .attr('d', this.getInitialLinePathValue(finalPath, areaData, animatedAreaData, lineGenerator, animation));
287
+ if (!animation || !finalPath) {
288
+ return [];
234
289
  }
235
- if (this.valueLabel?.show) {
236
- this.renderValueLabels(valueLabelLayer ?? plotGroup, areaData.filter((d) => d.valid), y, parseValue, theme, getXPosition);
290
+ const revealTransitions = this.createRevealTransitions(linePath.node(), `area-line-${sanitizedKey}-reveal`, animation, animation.previousLineRevealProgress, lineStrokeWidth);
291
+ const transition = linePath
292
+ .transition()
293
+ .duration(animation.duration)
294
+ .ease(animation.easing)
295
+ .attr('d', finalPath);
296
+ return [
297
+ ...revealTransitions,
298
+ createTransitionCompletionPromise(transition),
299
+ ];
300
+ }
301
+ getInitialAreaPathValue(finalAreaPath, areaData, animatedAreaData, areaGenerator, animation) {
302
+ if (animation?.mode === 'initial') {
303
+ return finalAreaPath;
304
+ }
305
+ if (!animation) {
306
+ return finalAreaPath;
307
+ }
308
+ return (animation.previousAreaPath ??
309
+ areaGenerator(animation ? animatedAreaData : areaData));
310
+ }
311
+ getInitialLinePathValue(finalPath, areaData, animatedAreaData, lineGenerator, animation) {
312
+ if (animation?.mode === 'initial') {
313
+ return finalPath;
314
+ }
315
+ if (!animation) {
316
+ return finalPath;
317
+ }
318
+ return (animation.previousLinePath ??
319
+ lineGenerator(animation ? animatedAreaData : areaData));
320
+ }
321
+ createRevealTransitions(path, revealId, animation, previousRevealProgress, padding = 0) {
322
+ if (animation.mode === 'initial') {
323
+ return createLeftToRightRevealTransition(path, animation.duration, animation.easing, revealId, padding);
324
+ }
325
+ if (previousRevealProgress == null) {
326
+ return [];
327
+ }
328
+ return createLeftToRightRevealTransition(path, animation.duration, animation.easing, revealId, padding, previousRevealProgress);
329
+ }
330
+ renderPoints(plotGroup, areaData, animatedAreaData, theme, sanitizedKey, animation) {
331
+ const validData = areaData.filter((d) => d.valid);
332
+ const validAnimatedData = animatedAreaData.filter((d) => d.valid);
333
+ const pointSize = this.pointSize ?? theme.line.point.size;
334
+ const pointStrokeWidth = theme.line.point.strokeWidth;
335
+ const pointStrokeColor = theme.line.point.strokeColor || this.stroke;
336
+ const pointColor = theme.line.point.color || this.stroke;
337
+ const isInitialAnimation = animation?.mode === 'initial';
338
+ const circles = plotGroup
339
+ .selectAll(`.area-point-${sanitizedKey}`)
340
+ .data(validData)
341
+ .join('circle')
342
+ .attr('class', `area-point-${sanitizedKey}`)
343
+ .attr('cx', (_, index) => (isInitialAnimation
344
+ ? validData[index]?.x
345
+ : animation
346
+ ? validAnimatedData[index]?.x
347
+ : validData[index]?.x) ?? 0)
348
+ .attr('cy', (_, index) => (isInitialAnimation
349
+ ? validData[index]?.y1
350
+ : animation
351
+ ? validAnimatedData[index]?.y1
352
+ : validData[index]?.y1) ?? 0)
353
+ .attr('r', isInitialAnimation ? 0 : pointSize)
354
+ .attr('fill', pointColor)
355
+ .attr('stroke', pointStrokeColor)
356
+ .attr('stroke-width', pointStrokeWidth);
357
+ if (!animation) {
358
+ return [];
359
+ }
360
+ if (isInitialAnimation) {
361
+ const transition = circles
362
+ .transition()
363
+ .delay((_, index) => {
364
+ return getEnterStaggerTiming(index, validData.length, animation.duration).delay;
365
+ })
366
+ .duration((_, index) => {
367
+ return getEnterStaggerTiming(index, validData.length, animation.duration).duration;
368
+ })
369
+ .ease(animation.easing)
370
+ .attr('r', pointSize);
371
+ return [createTransitionCompletionPromise(transition)];
237
372
  }
373
+ const transition = circles
374
+ .transition()
375
+ .duration(animation.duration)
376
+ .ease(animation.easing)
377
+ .attr('cx', (_, index) => validData[index]?.x ?? 0)
378
+ .attr('cy', (_, index) => validData[index]?.y1 ?? 0);
379
+ return [createTransitionCompletionPromise(transition)];
238
380
  }
239
- renderValueLabels(plotGroup, data, y, parseValue, theme, getXPosition) {
381
+ renderValueLabels(plotGroup, data, y, parseValue, theme) {
240
382
  const config = this.valueLabel;
241
383
  const fontSize = config.fontSize ?? theme.valueLabel.fontSize;
242
384
  const fontFamily = config.fontFamily ?? theme.valueLabel.fontFamily;
@@ -260,9 +402,11 @@ export class Area {
260
402
  if (!Number.isFinite(parsedValue)) {
261
403
  return;
262
404
  }
263
- const valueText = String(parsedValue);
264
- const xPos = getXPosition(d);
265
- const yPos = y(d.y1) || 0;
405
+ const valueText = config.formatter
406
+ ? config.formatter(this.dataKey, parsedValue, d.data)
407
+ : String(parsedValue);
408
+ const xPos = d.x;
409
+ const yPos = d.y1;
266
410
  const tempText = labelGroup
267
411
  .append('text')
268
412
  .style('font-size', `${fontSize}px`)
package/dist/bar.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Selection } from 'd3';
2
2
  import type { BarConfig, BarStackingContext, BarSide, BarValueLabelConfig, ChartTheme, D3Scale, DataItem, Orientation, ScaleType, ExportHooks, BarConfigBase } from './types.js';
3
3
  import type { ChartComponent } from './chart-interface.js';
4
+ import type { XYBarAnimationContext, XYBarSnapshot, XYSeriesRenderResult } from './xy-motion/types.js';
4
5
  export declare class Bar implements ChartComponent<BarConfigBase> {
5
6
  readonly type: "bar";
6
7
  readonly dataKey: string;
@@ -14,9 +15,33 @@ export declare class Bar implements ChartComponent<BarConfigBase> {
14
15
  getExportConfig(): BarConfigBase;
15
16
  createExportComponent(override?: Partial<BarConfigBase>): ChartComponent<BarConfigBase>;
16
17
  getRenderedValue(value: number, orientation?: Orientation): number;
17
- render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType?: ScaleType, theme?: ChartTheme, stackingContext?: BarStackingContext, orientation?: 'vertical' | 'horizontal'): void;
18
+ render(plotGroup: Selection<SVGGElement, undefined, null, undefined>, data: DataItem[], xKey: string, x: D3Scale, y: D3Scale, parseValue: (value: unknown) => number, xScaleType?: ScaleType, theme?: ChartTheme, stackingContext?: BarStackingContext, orientation?: 'vertical' | 'horizontal', animation?: XYBarAnimationContext): XYSeriesRenderResult<XYBarSnapshot>;
18
19
  private renderVertical;
19
20
  private renderHorizontal;
21
+ private createVerticalLayoutData;
22
+ private createHorizontalLayoutData;
23
+ private createAnimatedVerticalLayoutData;
24
+ private createAnimatedHorizontalLayoutData;
25
+ private resolveAnimatedLayoutDatum;
26
+ private createSnapshot;
27
+ private renderBars;
28
+ private resolveValueLabelConfig;
29
+ private resolveValueLabelPlacement;
30
+ private resolveValueLabelStyle;
31
+ private getValueLabelText;
32
+ private getBarColor;
33
+ private measureLabelBox;
34
+ private getLabelColor;
35
+ private appendValueLabel;
36
+ private getVerticalLabelPlacement;
37
+ private getVerticalOutsideLabelPlacement;
38
+ private getVerticalInsideLabelY;
39
+ private getHorizontalLabelPlacement;
40
+ private getHorizontalOutsideLabelPlacement;
41
+ private getHorizontalInsideLabelX;
42
+ private isHorizontalLabelWithinBounds;
43
+ private renderVerticalValueLabel;
44
+ private renderHorizontalValueLabel;
20
45
  private renderVerticalValueLabels;
21
46
  private renderHorizontalValueLabels;
22
47
  }