@internetstiftelsen/charts 0.13.3 → 0.14.1

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.
package/dist/pie-chart.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { arc, pie, select } from 'd3';
2
2
  import { ChartValidator } from './validation.js';
3
- import { getContrastTextColor, measureTextWidth, sanitizeForCSS, } from './utils.js';
3
+ import { getContrastTextColor, sanitizeForCSS } from './utils.js';
4
4
  import { RadialChartBase } from './radial-chart-base.js';
5
+ import { buildRadialAnimatedArcData, buildRadialExitTargetPieData, createTransitionCompletionPromise, interpolateRadialArcDatum, interpolateRadialArcShape, normalizeRadialAnimationConfig, renderRadialArcDatum, RadialMotionController, } from './radial-animation.js';
5
6
  const HOVER_EXPAND_PX = 8;
6
- const ANIMATION_DURATION_MS = 150;
7
+ const HOVER_ANIMATION_DURATION_MS = 150;
7
8
  const FULL_CIRCLE_RADIANS = Math.PI * 2;
8
9
  const OUTSIDE_LABEL_TEXT_OFFSET_PX = 10;
9
10
  const OUTSIDE_LABEL_LINE_INSET_PX = 4;
@@ -15,9 +16,9 @@ const DEFAULT_PIE_VALUE_LABEL = {
15
16
  outsideOffset: 16,
16
17
  insideMargin: 8,
17
18
  minVerticalSpacing: 14,
18
- formatter: (label, value, _data, _percentage) => {
19
- return `${label}: ${value}`;
20
- },
19
+ oversizedBehavior: 'truncate',
20
+ forceVisible: false,
21
+ separator: ': ',
21
22
  };
22
23
  export class PieChart extends RadialChartBase {
23
24
  constructor(config) {
@@ -76,6 +77,12 @@ export class PieChart extends RadialChartBase {
76
77
  writable: true,
77
78
  value: void 0
78
79
  });
80
+ Object.defineProperty(this, "motionController", {
81
+ enumerable: true,
82
+ configurable: true,
83
+ writable: true,
84
+ value: void 0
85
+ });
79
86
  Object.defineProperty(this, "segments", {
80
87
  enumerable: true,
81
88
  configurable: true,
@@ -108,6 +115,7 @@ export class PieChart extends RadialChartBase {
108
115
  ...DEFAULT_PIE_VALUE_LABEL,
109
116
  ...config.valueLabel,
110
117
  };
118
+ this.motionController = new RadialMotionController(normalizeRadialAnimationConfig(config.animate, 'PieChart'));
111
119
  this.initializeDataState();
112
120
  }
113
121
  validatePieData() {
@@ -203,10 +211,36 @@ export class PieChart extends RadialChartBase {
203
211
  });
204
212
  }
205
213
  update(data) {
214
+ this.motionController.prepareForUpdate();
206
215
  super.update(data);
207
216
  }
208
- formatValueLabelText(segment, total) {
209
- return this.valueLabel.formatter(segment.label, segment.value, segment.source, total > 0 ? (segment.value / total) * 100 : 0);
217
+ prepareForLegendChange() {
218
+ this.motionController.prepareForUpdate();
219
+ }
220
+ resolveValueLabelText(segment, total) {
221
+ const percentage = this.getValueLabelPercentage(segment, total);
222
+ if (this.valueLabel.formatter) {
223
+ const fullText = this.valueLabel.formatter(segment.label, segment.value, segment.source, percentage);
224
+ return {
225
+ label: fullText,
226
+ value: '',
227
+ separator: '',
228
+ fullText,
229
+ isCustom: true,
230
+ };
231
+ }
232
+ const label = this.valueLabel.labelFormatter?.(segment.label, segment.value, segment.source, percentage) ?? segment.label;
233
+ const value = this.valueLabel.valueFormatter?.(segment.label, segment.value, segment.source, percentage) ?? String(segment.value);
234
+ return {
235
+ label,
236
+ value,
237
+ separator: this.valueLabel.separator,
238
+ fullText: `${label}${this.valueLabel.separator}${value}`,
239
+ isCustom: false,
240
+ };
241
+ }
242
+ getValueLabelPercentage(segment, total) {
243
+ return total > 0 ? (segment.value / total) * 100 : 0;
210
244
  }
211
245
  createExportChart() {
212
246
  return new PieChart({
@@ -224,6 +258,7 @@ export class PieChart extends RadialChartBase {
224
258
  sort: this.sort,
225
259
  },
226
260
  valueLabel: this.valueLabel,
261
+ animate: false,
227
262
  valueKey: this.valueKey,
228
263
  labelKey: this.labelKey,
229
264
  });
@@ -235,16 +270,16 @@ export class PieChart extends RadialChartBase {
235
270
  renderChart({ svg, plotGroup, plotArea, }) {
236
271
  this.renderTitle(svg);
237
272
  const visibleSegments = this.getVisibleRadialItems(this.segments);
273
+ const animationContext = this.motionController.getAnimationContext();
274
+ const { cx, cy, outerRadius, innerRadius, fontScale } = this.getRadialLayout(plotArea, this.innerRadiusRatio);
238
275
  this.initializeTooltip();
239
- if (visibleSegments.length > 0) {
240
- const { cx, cy, outerRadius, innerRadius, fontScale } = this.getRadialLayout(plotArea, this.innerRadiusRatio);
241
- const { segmentGroup, pieData } = this.renderSegments(plotGroup, visibleSegments, cx, cy, innerRadius, outerRadius);
242
- if (this.valueLabel.show) {
243
- this.renderLabels(segmentGroup, pieData, innerRadius, outerRadius, visibleSegments.reduce((sum, segment) => {
244
- return sum + segment.value;
245
- }, 0), fontScale);
246
- }
276
+ const { segmentGroup, pieData, transitions } = this.renderSegments(plotGroup, visibleSegments, cx, cy, innerRadius, outerRadius, animationContext, this.segments);
277
+ if (this.valueLabel.show && visibleSegments.length > 0) {
278
+ this.renderLabels(segmentGroup, pieData, innerRadius, outerRadius, visibleSegments.reduce((sum, segment) => {
279
+ return sum + segment.value;
280
+ }, 0), fontScale);
247
281
  }
282
+ this.setReadyPromise(this.motionController.completeRender(pieData, transitions));
248
283
  this.renderInlineLegend(svg);
249
284
  }
250
285
  getLegendSeries() {
@@ -262,7 +297,7 @@ export class PieChart extends RadialChartBase {
262
297
  }
263
298
  return null;
264
299
  }
265
- renderSegments(plotGroup, segments, cx, cy, innerRadius, outerRadius) {
300
+ renderSegments(plotGroup, segments, cx, cy, innerRadius, outerRadius, animationContext, allSegments) {
266
301
  const pieGenerator = pie()
267
302
  .value((d) => d.value)
268
303
  .startAngle(this.startAngle)
@@ -284,30 +319,72 @@ export class PieChart extends RadialChartBase {
284
319
  .outerRadius(outerRadius + HOVER_EXPAND_PX)
285
320
  .cornerRadius(this.cornerRadius);
286
321
  const pieData = pieGenerator(segments);
322
+ const exitTargetPieData = buildRadialExitTargetPieData(pieGenerator, segments, allSegments, animationContext, pieData);
323
+ const arcShape = {
324
+ innerRadius,
325
+ outerRadius,
326
+ cornerRadius: this.cornerRadius,
327
+ };
287
328
  const segmentGroup = plotGroup
288
329
  .append('g')
289
330
  .attr('class', 'pie-segments')
290
331
  .attr('transform', `translate(${cx}, ${cy})`);
291
332
  const total = segments.reduce((sum, segment) => sum + segment.value, 0);
333
+ const animatedArcData = buildRadialAnimatedArcData(pieData, allSegments, animationContext, arcShape, exitTargetPieData);
334
+ const animationByDatum = new Map(animatedArcData.map((entry) => [entry.datum, entry]));
335
+ const getAnimation = (datum) => {
336
+ return animationByDatum.get(datum);
337
+ };
338
+ const renderedArcData = animatedArcData.map((entry) => entry.datum);
339
+ const transitions = [];
292
340
  const segmentSelection = segmentGroup
293
341
  .selectAll('.pie-segment')
294
- .data(pieData)
342
+ .data(renderedArcData, (d) => getAnimation(d).key)
295
343
  .join('path')
296
344
  .attr('class', (d) => `pie-segment segment-${sanitizeForCSS(d.data.label)}`)
297
- .attr('d', arcGenerator)
345
+ .attr('d', (d) => {
346
+ const animation = getAnimation(d);
347
+ return renderRadialArcDatum(animation.startDatum, animation.startShape);
348
+ })
298
349
  .attr('fill', (d) => d.data.color)
299
- .attr('tabindex', 0)
300
- .attr('aria-label', (d) => this.buildAriaLabel(d, total))
301
- .style('cursor', 'pointer')
350
+ .attr('opacity', (d) => getAnimation(d).initialOpacity)
351
+ .attr('tabindex', (d) => (getAnimation(d).interactive ? 0 : null))
352
+ .attr('aria-hidden', (d) => getAnimation(d).interactive ? null : 'true')
353
+ .attr('aria-label', (d) => {
354
+ return getAnimation(d).interactive
355
+ ? this.buildAriaLabel(d, total)
356
+ : null;
357
+ })
358
+ .style('cursor', (d) => getAnimation(d).interactive ? 'pointer' : 'default')
359
+ .style('pointer-events', (d) => getAnimation(d).interactive ? 'all' : 'none')
302
360
  .style('transition', 'opacity 0.15s ease');
303
- segmentSelection
361
+ if (animationContext) {
362
+ const transition = segmentSelection
363
+ .transition()
364
+ .duration(animationContext.duration)
365
+ .ease(animationContext.easing)
366
+ .attrTween('d', (d) => {
367
+ const animation = getAnimation(d);
368
+ const datumInterpolator = interpolateRadialArcDatum(animation.startDatum, animation.endDatum);
369
+ const shapeInterpolator = interpolateRadialArcShape(animation.startShape, animation.endShape);
370
+ return (progress) => {
371
+ return renderRadialArcDatum(datumInterpolator(progress), shapeInterpolator(progress));
372
+ };
373
+ })
374
+ .attr('opacity', (d) => getAnimation(d).finalOpacity);
375
+ transitions.push(createTransitionCompletionPromise(transition));
376
+ }
377
+ const interactiveSegmentSelection = segmentSelection.filter((d) => {
378
+ return getAnimation(d).interactive;
379
+ });
380
+ interactiveSegmentSelection
304
381
  .on('mouseenter', (event, d) => {
305
382
  const target = event.currentTarget;
306
383
  select(target)
307
384
  .transition()
308
- .duration(ANIMATION_DURATION_MS)
385
+ .duration(HOVER_ANIMATION_DURATION_MS)
309
386
  .attr('d', hoverArcGenerator(d));
310
- segmentSelection
387
+ interactiveSegmentSelection
311
388
  .filter((_, i, nodes) => nodes[i] !== target)
312
389
  .style('opacity', 0.5);
313
390
  this.showTooltipFromPointer(event, this.buildTooltipContent(d, segments));
@@ -319,18 +396,18 @@ export class PieChart extends RadialChartBase {
319
396
  const target = event.currentTarget;
320
397
  select(target)
321
398
  .transition()
322
- .duration(ANIMATION_DURATION_MS)
399
+ .duration(HOVER_ANIMATION_DURATION_MS)
323
400
  .attr('d', arcGenerator(d));
324
- segmentSelection.style('opacity', 1);
401
+ interactiveSegmentSelection.style('opacity', 1);
325
402
  this.hideTooltip();
326
403
  })
327
404
  .on('focus', (event, d) => {
328
405
  const target = event.currentTarget;
329
406
  select(target)
330
407
  .transition()
331
- .duration(ANIMATION_DURATION_MS)
408
+ .duration(HOVER_ANIMATION_DURATION_MS)
332
409
  .attr('d', hoverArcGenerator(d));
333
- segmentSelection
410
+ interactiveSegmentSelection
334
411
  .filter((_, i, nodes) => nodes[i] !== target)
335
412
  .style('opacity', 0.5);
336
413
  this.showTooltipAtElement(target, this.buildTooltipContent(d, segments));
@@ -339,9 +416,9 @@ export class PieChart extends RadialChartBase {
339
416
  const target = event.currentTarget;
340
417
  select(target)
341
418
  .transition()
342
- .duration(ANIMATION_DURATION_MS)
419
+ .duration(HOVER_ANIMATION_DURATION_MS)
343
420
  .attr('d', arcGenerator(d));
344
- segmentSelection.style('opacity', 1);
421
+ interactiveSegmentSelection.style('opacity', 1);
345
422
  this.hideTooltip();
346
423
  })
347
424
  .on('keydown', (event) => {
@@ -350,6 +427,7 @@ export class PieChart extends RadialChartBase {
350
427
  return {
351
428
  segmentGroup,
352
429
  pieData,
430
+ transitions,
353
431
  };
354
432
  }
355
433
  handleSegmentKeyNavigation(event) {
@@ -415,30 +493,44 @@ export class PieChart extends RadialChartBase {
415
493
  .innerRadius(insideLabelRadius)
416
494
  .outerRadius(insideLabelRadius);
417
495
  const fontSize = this.renderTheme.legend.fontSize * fontScale;
496
+ const fontFamily = this.renderTheme.axis.fontFamily;
418
497
  const fontWeight = this.renderTheme.axis.fontWeight ?? 'normal';
498
+ const labelOverflowOptions = {
499
+ maxLabelWidth: this.valueLabel.maxLabelWidth,
500
+ oversizedBehavior: this.valueLabel.oversizedBehavior,
501
+ forceVisible: this.valueLabel.forceVisible,
502
+ fontSize,
503
+ fontFamily,
504
+ fontWeight,
505
+ };
419
506
  const outsideLabels = [];
420
507
  pieData.forEach((d) => {
421
508
  const percentage = total > 0 ? (d.data.value / total) * 100 : 0;
422
- const labelText = this.formatValueLabelText(d.data, total);
423
- const placement = this.resolveValueLabelPlacement(d, labelText, percentage, innerRadius, outerRadius, insideLabelRadius, fontSize, fontWeight);
509
+ const valueLabel = this.resolveValueLabelText(d.data, total);
510
+ const labelDimensions = this.measureValueLabelDimensions(valueLabel, labelOverflowOptions);
511
+ const placement = this.resolveValueLabelPlacement(d, labelDimensions, percentage, innerRadius, outerRadius, insideLabelRadius);
424
512
  if (placement === 'inside') {
425
513
  const [x, y] = insideArc.centroid(d);
426
- labelGroup
514
+ const textElement = labelGroup
427
515
  .append('text')
428
516
  .attr('class', `pie-label pie-label--inside pie-label-${sanitizeForCSS(d.data.label)}`)
429
517
  .attr('x', x)
430
518
  .attr('y', y)
431
519
  .attr('text-anchor', 'middle')
432
520
  .attr('dominant-baseline', 'middle')
433
- .attr('font-family', this.renderTheme.axis.fontFamily)
521
+ .attr('font-family', fontFamily)
434
522
  .attr('font-size', `${fontSize}px`)
435
523
  .attr('font-weight', fontWeight)
436
- .attr('fill', getContrastTextColor(d.data.color))
437
- .text(labelText);
524
+ .attr('fill', getContrastTextColor(d.data.color));
525
+ if (valueLabel.isCustom) {
526
+ this.renderRadialLabelText(textElement, valueLabel.fullText, labelOverflowOptions);
527
+ return;
528
+ }
529
+ this.renderRadialStructuredLabelText(textElement, valueLabel.label, valueLabel.value, valueLabel.separator, labelOverflowOptions);
438
530
  return;
439
531
  }
440
532
  if (placement === 'outside') {
441
- outsideLabels.push(this.resolveOutsideLabel(d, outerRadius));
533
+ outsideLabels.push(this.resolveOutsideLabel(d, outerRadius, valueLabel, labelDimensions.height));
442
534
  }
443
535
  });
444
536
  if (outsideLabels.length === 0) {
@@ -468,24 +560,30 @@ export class PieChart extends RadialChartBase {
468
560
  .attr('fill', 'none')
469
561
  .attr('stroke', '#9ca3af')
470
562
  .attr('stroke-width', 1);
471
- labelGroup
563
+ const textElement = labelGroup
472
564
  .append('text')
473
565
  .attr('class', `pie-label pie-label--outside pie-label-${sanitizeForCSS(outsideLabel.datum.data.label)}`)
474
566
  .attr('x', textX)
475
567
  .attr('y', outsideLabel.y)
476
568
  .attr('text-anchor', outsideLabel.textAnchor)
477
569
  .attr('dominant-baseline', 'middle')
478
- .attr('font-family', this.renderTheme.axis.fontFamily)
570
+ .attr('font-family', fontFamily)
479
571
  .attr('font-size', `${fontSize}px`)
480
572
  .attr('font-weight', fontWeight)
481
- .attr('fill', this.renderTheme.valueLabel.color)
482
- .text(this.formatValueLabelText(outsideLabel.datum.data, total));
573
+ .attr('fill', this.renderTheme.valueLabel.color);
574
+ if (outsideLabel.valueLabel.isCustom) {
575
+ this.renderRadialLabelText(textElement, outsideLabel.valueLabel.fullText, labelOverflowOptions);
576
+ return;
577
+ }
578
+ this.renderRadialStructuredLabelText(textElement, outsideLabel.valueLabel.label, outsideLabel.valueLabel.value, outsideLabel.valueLabel.separator, labelOverflowOptions);
483
579
  });
484
580
  }
485
- resolveValueLabelPlacement(datum, labelText, percentage, innerRadius, outerRadius, insideLabelRadius, fontSize, fontWeight) {
486
- const fitsInside = this.canFitInsideLabel(datum, labelText, innerRadius, outerRadius, insideLabelRadius, fontSize, fontWeight);
581
+ resolveValueLabelPlacement(datum, labelDimensions, percentage, innerRadius, outerRadius, insideLabelRadius) {
582
+ const fitsInside = this.canFitInsideLabel(datum, labelDimensions, innerRadius, outerRadius, insideLabelRadius);
487
583
  if (this.valueLabel.position === 'inside') {
488
- return fitsInside ? 'inside' : 'hidden';
584
+ return fitsInside || this.valueLabel.forceVisible
585
+ ? 'inside'
586
+ : 'hidden';
489
587
  }
490
588
  if (this.valueLabel.position === 'outside') {
491
589
  return 'outside';
@@ -498,23 +596,14 @@ export class PieChart extends RadialChartBase {
498
596
  }
499
597
  return 'inside';
500
598
  }
501
- canFitInsideLabel(datum, labelText, innerRadius, outerRadius, insideLabelRadius, fontSize, fontWeight) {
502
- if (!this.svg) {
503
- return false;
504
- }
505
- const svgNode = this.svg.node();
506
- if (!svgNode) {
507
- return false;
508
- }
509
- const textWidth = measureTextWidth(labelText, fontSize, this.renderTheme.axis.fontFamily, fontWeight, svgNode);
599
+ canFitInsideLabel(datum, labelDimensions, innerRadius, outerRadius, insideLabelRadius) {
510
600
  const angle = Math.max(0, datum.endAngle - datum.startAngle);
511
601
  const availableArcLength = angle * insideLabelRadius - this.valueLabel.insideMargin * 2;
512
602
  const availableRadialThickness = outerRadius - innerRadius - this.valueLabel.insideMargin * 2;
513
- const verticalFitThreshold = fontSize * 1.15;
514
- return (availableArcLength >= textWidth &&
515
- availableRadialThickness >= verticalFitThreshold);
603
+ return (availableArcLength >= labelDimensions.width &&
604
+ availableRadialThickness >= labelDimensions.height);
516
605
  }
517
- resolveOutsideLabel(datum, outerRadius) {
606
+ resolveOutsideLabel(datum, outerRadius, valueLabel, height) {
518
607
  const midAngle = (datum.startAngle + datum.endAngle) / 2;
519
608
  const point = this.getArcPoint(midAngle, outerRadius + this.valueLabel.outsideOffset);
520
609
  const side = point.x >= 0 ? 'right' : 'left';
@@ -523,8 +612,16 @@ export class PieChart extends RadialChartBase {
523
612
  y: point.y,
524
613
  side,
525
614
  textAnchor: side === 'right' ? 'start' : 'end',
615
+ valueLabel,
616
+ height,
526
617
  };
527
618
  }
619
+ measureValueLabelDimensions(valueLabel, labelOverflowOptions) {
620
+ if (valueLabel.isCustom) {
621
+ return this.measureRadialLabelDimensions(valueLabel.fullText, labelOverflowOptions);
622
+ }
623
+ return this.measureRadialStructuredLabelDimensions(valueLabel.label, valueLabel.value, valueLabel.separator, labelOverflowOptions);
624
+ }
528
625
  adjustOutsideLabelPositions(labels, outerRadius) {
529
626
  const adjustForSide = (side) => {
530
627
  const sideLabels = labels
@@ -537,7 +634,8 @@ export class PieChart extends RadialChartBase {
537
634
  const bottomLimit = outerRadius;
538
635
  sideLabels[0].y = Math.max(topLimit, sideLabels[0].y);
539
636
  for (let i = 1; i < sideLabels.length; i++) {
540
- const minY = sideLabels[i - 1].y + this.valueLabel.minVerticalSpacing;
637
+ const minY = sideLabels[i - 1].y +
638
+ this.getOutsideLabelSpacing(sideLabels[i - 1], sideLabels[i]);
541
639
  sideLabels[i].y = Math.max(sideLabels[i].y, minY);
542
640
  }
543
641
  const overflow = sideLabels[sideLabels.length - 1].y - bottomLimit;
@@ -545,7 +643,7 @@ export class PieChart extends RadialChartBase {
545
643
  sideLabels[sideLabels.length - 1].y -= overflow;
546
644
  for (let i = sideLabels.length - 2; i >= 0; i--) {
547
645
  const maxY = sideLabels[i + 1].y -
548
- this.valueLabel.minVerticalSpacing;
646
+ this.getOutsideLabelSpacing(sideLabels[i], sideLabels[i + 1]);
549
647
  sideLabels[i].y = Math.min(sideLabels[i].y, maxY);
550
648
  }
551
649
  const underflow = topLimit - sideLabels[0].y;
@@ -564,4 +662,7 @@ export class PieChart extends RadialChartBase {
564
662
  const leftLabels = adjustForSide('left');
565
663
  return [...rightLabels, ...leftLabels];
566
664
  }
665
+ getOutsideLabelSpacing(previousLabel, currentLabel) {
666
+ return Math.max(this.valueLabel.minVerticalSpacing, (previousLabel.height + currentLabel.height) / 2);
667
+ }
567
668
  }
@@ -0,0 +1,69 @@
1
+ import { type PieArcDatum } from 'd3';
2
+ export type RadialAnimationEasingPreset = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'bounce-out' | 'elastic-out' | 'spring-out';
3
+ export type RadialAnimationConfig = {
4
+ show?: boolean;
5
+ duration?: number;
6
+ easing?: RadialAnimationEasingPreset | `linear(${string})` | ((progress: number) => number);
7
+ };
8
+ export type NormalizedRadialAnimation = {
9
+ show: boolean;
10
+ duration: number;
11
+ easing: (progress: number) => number;
12
+ };
13
+ export type RadialRenderAnimationMode = 'none' | 'initial' | 'update';
14
+ export type RadialSegmentAnimationData = {
15
+ label: string;
16
+ value: number;
17
+ };
18
+ type RadialSegmentSnapshot = {
19
+ startAngle: number;
20
+ endAngle: number;
21
+ padAngle: number;
22
+ value: number;
23
+ index: number;
24
+ };
25
+ export type RadialSegmentSnapshotCollection = Map<string, RadialSegmentSnapshot>;
26
+ export type RadialAnimationContext = {
27
+ mode: Exclude<RadialRenderAnimationMode, 'none'>;
28
+ duration: number;
29
+ easing: (progress: number) => number;
30
+ previousSnapshot?: RadialSegmentSnapshotCollection;
31
+ };
32
+ export type RadialArcShape = {
33
+ innerRadius: number;
34
+ outerRadius: number;
35
+ cornerRadius: number;
36
+ };
37
+ export type RadialAnimatedArcDatum<TData extends RadialSegmentAnimationData> = {
38
+ key: string;
39
+ datum: PieArcDatum<TData>;
40
+ startDatum: PieArcDatum<TData>;
41
+ endDatum: PieArcDatum<TData>;
42
+ startShape: RadialArcShape;
43
+ endShape: RadialArcShape;
44
+ initialOpacity: number;
45
+ finalOpacity: number;
46
+ interactive: boolean;
47
+ };
48
+ export declare function normalizeRadialAnimationConfig(config: boolean | RadialAnimationConfig | undefined, chartName: string): NormalizedRadialAnimation;
49
+ export declare class RadialMotionController {
50
+ private readonly animation;
51
+ private hasRenderedLive;
52
+ private nextRenderAnimationMode;
53
+ private pendingAnimationSnapshot;
54
+ private lastSegmentSnapshot;
55
+ constructor(animation: NormalizedRadialAnimation);
56
+ prepareForUpdate(): void;
57
+ getAnimationContext(): RadialAnimationContext | undefined;
58
+ completeRender<TData extends RadialSegmentAnimationData>(pieData: Array<PieArcDatum<TData>>, transitions: Promise<void>[]): Promise<void>;
59
+ }
60
+ export declare function buildRadialSegmentKeys<TData extends RadialSegmentAnimationData>(pieData: Array<PieArcDatum<TData>>): string[];
61
+ export declare function buildRadialAnimatedArcData<TData extends RadialSegmentAnimationData>(pieData: Array<PieArcDatum<TData>>, allSegments: TData[], context: RadialAnimationContext | undefined, shape: RadialArcShape, exitTargetPieData?: Array<PieArcDatum<TData>>): Array<RadialAnimatedArcDatum<TData>>;
62
+ export declare function buildRadialExitTargetPieData<TData extends RadialSegmentAnimationData>(pieGenerator: (segments: TData[]) => Array<PieArcDatum<TData>>, visibleSegments: TData[], allSegments: TData[], context: RadialAnimationContext | undefined, currentPieData: Array<PieArcDatum<TData>>): Array<PieArcDatum<TData>>;
63
+ export declare function renderRadialArcDatum<TData extends RadialSegmentAnimationData>(datum: PieArcDatum<TData>, shape: RadialArcShape): string;
64
+ export declare function interpolateRadialArcDatum<TData extends RadialSegmentAnimationData>(startDatum: PieArcDatum<TData>, endDatum: PieArcDatum<TData>): (progress: number) => PieArcDatum<TData>;
65
+ export declare function interpolateRadialArcShape(startShape: RadialArcShape, endShape: RadialArcShape): (progress: number) => RadialArcShape;
66
+ export declare function createTransitionCompletionPromise(transition: {
67
+ end: () => Promise<unknown>;
68
+ }): Promise<void>;
69
+ export {};