@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/README.md +7 -1
- package/dist/area.js +2 -1
- package/dist/bar.js +8 -4
- package/dist/base-chart.d.ts +8 -0
- package/dist/base-chart.js +79 -1
- package/dist/chart-group.d.ts +1 -0
- package/dist/chart-group.js +45 -4
- package/dist/donut-chart.d.ts +19 -3
- package/dist/donut-chart.js +129 -25
- package/dist/easing.d.ts +1 -0
- package/dist/easing.js +30 -0
- package/dist/gauge-chart.d.ts +7 -2
- package/dist/gauge-chart.js +43 -18
- package/dist/line.js +2 -1
- package/dist/pie-chart.d.ts +19 -3
- package/dist/pie-chart.js +160 -59
- package/dist/radial-animation.d.ts +69 -0
- package/dist/radial-animation.js +416 -0
- package/dist/radial-chart-base.d.ts +24 -1
- package/dist/radial-chart-base.js +181 -0
- package/dist/scatter.js +2 -1
- package/dist/theme.d.ts +15 -0
- package/dist/theme.js +90 -4
- package/dist/types.d.ts +1 -0
- package/dist/word-cloud-chart.d.ts +30 -0
- package/dist/word-cloud-chart.js +207 -7
- package/dist/xy-motion/config.js +3 -0
- package/dist/xy-motion/types.d.ts +1 -1
- package/docs/donut-chart.md +57 -14
- package/docs/gauge-chart.md +14 -0
- package/docs/getting-started.md +3 -0
- package/docs/pie-chart.md +58 -16
- package/docs/theming.md +17 -12
- package/docs/word-cloud-chart.md +43 -8
- package/docs/xy-chart.md +10 -0
- package/package.json +26 -26
package/README.md
CHANGED
|
@@ -10,8 +10,9 @@ 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
|
-
- **Custom Value Labels** - XY, pie, and
|
|
13
|
+
- **Custom Value Labels** - XY, pie, donut, and gauge charts support configurable labels with formatters, max-width overflow behavior, and forced rendering when labels would otherwise be hidden
|
|
14
14
|
- **Optional XY Animation** - Animate XY series on first render and `chart.update(...)` with `animate`
|
|
15
|
+
- **Optional Radial Animation** - Animate pie and donut segments on first render and `chart.update(...)` with `animate`
|
|
15
16
|
- **Optional Gauge Animation** - Animate gauge value transitions with `gauge.animate`
|
|
16
17
|
- **Stacking Control** - Bar and area stacking modes with optional reversed visual series order
|
|
17
18
|
- **Configurable Tooltips** - Shared or split tooltips with connectors, transitions, and default max-width wrapping
|
|
@@ -139,6 +140,8 @@ await chart.whenReady();
|
|
|
139
140
|
|
|
140
141
|
Animation is off by default, applies to XY series marks only, and visual
|
|
141
142
|
exports always render the final static state.
|
|
143
|
+
Preset easing values include `linear`, `ease-in`, `ease-out`, `ease-in-out`,
|
|
144
|
+
`bounce-out`, `elastic-out`, and `spring-out`.
|
|
142
145
|
|
|
143
146
|
## Lifecycle Events
|
|
144
147
|
|
|
@@ -359,6 +362,7 @@ const data = [
|
|
|
359
362
|
|
|
360
363
|
const chart = new WordCloudChart({
|
|
361
364
|
data,
|
|
365
|
+
animate: true,
|
|
362
366
|
wordCloud: {
|
|
363
367
|
minValue: 5,
|
|
364
368
|
minWordLength: 3,
|
|
@@ -376,6 +380,8 @@ chart.render('#word-cloud');
|
|
|
376
380
|
dimension and define the relative size range passed into `d3-cloud`. The chart
|
|
377
381
|
expects flat `{ word, count }` rows, aggregates duplicate words after trimming,
|
|
378
382
|
and maps theme typography and colors directly into the layout and rendered SVG.
|
|
383
|
+
Set `animate: true` or pass an animation config to fade and scale words from
|
|
384
|
+
their own centers on initial render and `chart.update(...)`.
|
|
379
385
|
|
|
380
386
|
## Export
|
|
381
387
|
|
package/dist/area.js
CHANGED
|
@@ -388,6 +388,7 @@ export class Area {
|
|
|
388
388
|
const border = config.border ?? theme.valueLabel.border;
|
|
389
389
|
const borderRadius = config.borderRadius ?? theme.valueLabel.borderRadius;
|
|
390
390
|
const padding = config.padding ?? theme.valueLabel.padding;
|
|
391
|
+
const forceVisible = config.forceVisible === true;
|
|
391
392
|
const labelGroup = plotGroup
|
|
392
393
|
.append('g')
|
|
393
394
|
.attr('class', `area-value-labels-${sanitizeForCSS(this.dataKey)}`);
|
|
@@ -422,7 +423,7 @@ export class Area {
|
|
|
422
423
|
if (labelY - boxHeight / 2 < plotTop + 4) {
|
|
423
424
|
labelY = yPos + boxHeight / 2 + theme.line.point.size + 4;
|
|
424
425
|
if (labelY + boxHeight / 2 > plotBottom - 4) {
|
|
425
|
-
shouldRender =
|
|
426
|
+
shouldRender = forceVisible;
|
|
426
427
|
}
|
|
427
428
|
}
|
|
428
429
|
tempText.remove();
|
package/dist/bar.js
CHANGED
|
@@ -369,6 +369,7 @@ export class Bar {
|
|
|
369
369
|
...this.resolveValueLabelStyle(config, theme),
|
|
370
370
|
formatter: config.formatter,
|
|
371
371
|
autoContrastInside: config.color === undefined,
|
|
372
|
+
forceVisible: config.forceVisible ?? false,
|
|
372
373
|
};
|
|
373
374
|
}
|
|
374
375
|
resolveValueLabelPlacement(config) {
|
|
@@ -461,7 +462,8 @@ export class Bar {
|
|
|
461
462
|
return {
|
|
462
463
|
x: input.x,
|
|
463
464
|
y,
|
|
464
|
-
shouldRender: input.
|
|
465
|
+
shouldRender: input.forceVisible ||
|
|
466
|
+
input.labelBox.height + minPadding <= input.barHeight,
|
|
465
467
|
};
|
|
466
468
|
}
|
|
467
469
|
getVerticalOutsideLabelPlacement(input) {
|
|
@@ -474,7 +476,7 @@ export class Bar {
|
|
|
474
476
|
return {
|
|
475
477
|
x: input.x,
|
|
476
478
|
y,
|
|
477
|
-
shouldRender,
|
|
479
|
+
shouldRender: input.forceVisible || shouldRender,
|
|
478
480
|
};
|
|
479
481
|
}
|
|
480
482
|
getVerticalInsideLabelY(barTop, barBottom, labelHeight, insidePosition, inset) {
|
|
@@ -506,7 +508,7 @@ export class Bar {
|
|
|
506
508
|
return {
|
|
507
509
|
x,
|
|
508
510
|
y: input.y,
|
|
509
|
-
shouldRender: fitsBar && withinBounds,
|
|
511
|
+
shouldRender: input.forceVisible || (fitsBar && withinBounds),
|
|
510
512
|
};
|
|
511
513
|
}
|
|
512
514
|
getHorizontalOutsideLabelPlacement(input) {
|
|
@@ -519,7 +521,7 @@ export class Bar {
|
|
|
519
521
|
return {
|
|
520
522
|
x,
|
|
521
523
|
y: input.y,
|
|
522
|
-
shouldRender,
|
|
524
|
+
shouldRender: input.forceVisible || shouldRender,
|
|
523
525
|
};
|
|
524
526
|
}
|
|
525
527
|
getHorizontalInsideLabelX(barLeft, barRight, labelWidth, isNegative, insidePosition, inset) {
|
|
@@ -567,6 +569,7 @@ export class Bar {
|
|
|
567
569
|
mode,
|
|
568
570
|
position: config.position,
|
|
569
571
|
insidePosition: config.insidePosition,
|
|
572
|
+
forceVisible: config.forceVisible,
|
|
570
573
|
plotTop,
|
|
571
574
|
plotBottom,
|
|
572
575
|
});
|
|
@@ -601,6 +604,7 @@ export class Bar {
|
|
|
601
604
|
mode,
|
|
602
605
|
position: config.position,
|
|
603
606
|
insidePosition: config.insidePosition,
|
|
607
|
+
forceVisible: config.forceVisible,
|
|
604
608
|
plotLeft,
|
|
605
609
|
plotRight,
|
|
606
610
|
});
|
package/dist/base-chart.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ type RenderDimensions = {
|
|
|
16
16
|
svgWidthAttr: number | string;
|
|
17
17
|
svgHeightAttr: number | string;
|
|
18
18
|
};
|
|
19
|
+
type PlotAreaOverride = Partial<Pick<PlotAreaBounds, 'top' | 'right' | 'bottom' | 'left'>>;
|
|
19
20
|
type ResponsiveOverrides = {
|
|
20
21
|
theme?: DeepPartial<ChartTheme>;
|
|
21
22
|
components: Map<ChartComponentBase, Record<string, unknown>>;
|
|
@@ -123,6 +124,7 @@ export declare abstract class BaseChart {
|
|
|
123
124
|
private disconnectedLegendContainer;
|
|
124
125
|
private renderThemeOverride;
|
|
125
126
|
private renderSizeOverride;
|
|
127
|
+
private plotAreaOverride;
|
|
126
128
|
private legendModeOverride;
|
|
127
129
|
private readonly eventListeners;
|
|
128
130
|
private renderId;
|
|
@@ -165,6 +167,10 @@ export declare abstract class BaseChart {
|
|
|
165
167
|
width?: number;
|
|
166
168
|
height?: number;
|
|
167
169
|
};
|
|
170
|
+
/** @internal */
|
|
171
|
+
measurePlotArea(width: number, height: number): PlotAreaBounds;
|
|
172
|
+
/** @internal */
|
|
173
|
+
setPlotAreaOverride(override: PlotAreaOverride | null, rerender?: boolean): this;
|
|
168
174
|
setLegendModeOverride(mode: LegendMode | null, rerender?: boolean): this;
|
|
169
175
|
on<TEventName extends ChartEventName>(eventName: TEventName, listener: ChartEventListener<TEventName>): this;
|
|
170
176
|
off<TEventName extends ChartEventName>(eventName: TEventName, listener: ChartEventListener<TEventName>): this;
|
|
@@ -199,8 +205,10 @@ export declare abstract class BaseChart {
|
|
|
199
205
|
protected filterVisibleItems<T>(items: T[], getDataKey: (item: T) => string): T[];
|
|
200
206
|
protected validateSourceData(_data: ChartData): void;
|
|
201
207
|
protected syncDerivedState(_previousData?: DataItem[]): void;
|
|
208
|
+
protected prepareForLegendChange(): void;
|
|
202
209
|
protected initializeDataState(): void;
|
|
203
210
|
protected prepareLayout(context: BaseLayoutContext): void;
|
|
211
|
+
private applyPlotAreaOverride;
|
|
204
212
|
/**
|
|
205
213
|
* Setup ResizeObserver for automatic resize handling
|
|
206
214
|
*/
|
package/dist/base-chart.js
CHANGED
|
@@ -219,6 +219,12 @@ export class BaseChart {
|
|
|
219
219
|
writable: true,
|
|
220
220
|
value: null
|
|
221
221
|
});
|
|
222
|
+
Object.defineProperty(this, "plotAreaOverride", {
|
|
223
|
+
enumerable: true,
|
|
224
|
+
configurable: true,
|
|
225
|
+
writable: true,
|
|
226
|
+
value: null
|
|
227
|
+
});
|
|
222
228
|
Object.defineProperty(this, "legendModeOverride", {
|
|
223
229
|
enumerable: true,
|
|
224
230
|
configurable: true,
|
|
@@ -268,6 +274,7 @@ export class BaseChart {
|
|
|
268
274
|
this.responsiveConfig = config.responsive;
|
|
269
275
|
this.legendState = new LegendStateController();
|
|
270
276
|
this.legendState.subscribe(() => {
|
|
277
|
+
this.prepareForLegendChange();
|
|
271
278
|
this.notifyLegendChanged();
|
|
272
279
|
this.rerender('legend');
|
|
273
280
|
});
|
|
@@ -360,7 +367,7 @@ export class BaseChart {
|
|
|
360
367
|
// Calculate layout
|
|
361
368
|
this.layoutManager = new LayoutManager(this.resolvedRenderTheme);
|
|
362
369
|
const components = this.getLayoutComponents();
|
|
363
|
-
const plotArea = this.layoutManager.calculateLayout(components);
|
|
370
|
+
const plotArea = this.applyPlotAreaOverride(this.layoutManager.calculateLayout(components));
|
|
364
371
|
this.plotArea = plotArea;
|
|
365
372
|
// Create plot group
|
|
366
373
|
const plotGroup = this.svg.append('g').attr('class', 'chart-plot');
|
|
@@ -516,6 +523,59 @@ export class BaseChart {
|
|
|
516
523
|
height: this.configuredHeight,
|
|
517
524
|
};
|
|
518
525
|
}
|
|
526
|
+
/** @internal */
|
|
527
|
+
measurePlotArea(width, height) {
|
|
528
|
+
const previousWidth = this.width;
|
|
529
|
+
const previousHeight = this.height;
|
|
530
|
+
const measurementSvg = create('svg')
|
|
531
|
+
.attr('width', width)
|
|
532
|
+
.attr('height', height)
|
|
533
|
+
.style('position', 'absolute')
|
|
534
|
+
.style('left', '-9999px')
|
|
535
|
+
.style('top', '-9999px')
|
|
536
|
+
.style('overflow', 'hidden')
|
|
537
|
+
.style('pointer-events', 'none');
|
|
538
|
+
const svgNode = measurementSvg.node();
|
|
539
|
+
if (!svgNode) {
|
|
540
|
+
throw new Error('Failed to initialize chart measurement SVG');
|
|
541
|
+
}
|
|
542
|
+
document.body.appendChild(svgNode);
|
|
543
|
+
this.width = width;
|
|
544
|
+
this.height = height;
|
|
545
|
+
const responsiveContext = this.resolveResponsiveContext({
|
|
546
|
+
width,
|
|
547
|
+
height,
|
|
548
|
+
});
|
|
549
|
+
const responsiveOverrides = this.collectResponsiveOverrides(responsiveContext);
|
|
550
|
+
const mergedComponentOverrides = this.mergeComponentOverrideMaps(responsiveOverrides.components);
|
|
551
|
+
const renderTheme = this.resolveRenderTheme(responsiveOverrides);
|
|
552
|
+
const overrideComponents = this.createOverrideComponents(mergedComponentOverrides);
|
|
553
|
+
const restoreComponents = this.applyComponentOverrides(overrideComponents);
|
|
554
|
+
const restoreTheme = this.applyRenderTheme(renderTheme);
|
|
555
|
+
try {
|
|
556
|
+
this.prepareLayout({
|
|
557
|
+
svg: measurementSvg,
|
|
558
|
+
svgNode,
|
|
559
|
+
});
|
|
560
|
+
const layoutManager = new LayoutManager(this.resolvedRenderTheme);
|
|
561
|
+
return this.applyPlotAreaOverride(layoutManager.calculateLayout(this.getLayoutComponents()));
|
|
562
|
+
}
|
|
563
|
+
finally {
|
|
564
|
+
restoreComponents();
|
|
565
|
+
restoreTheme();
|
|
566
|
+
this.width = previousWidth;
|
|
567
|
+
this.height = previousHeight;
|
|
568
|
+
svgNode.remove();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/** @internal */
|
|
572
|
+
setPlotAreaOverride(override, rerender = true) {
|
|
573
|
+
this.plotAreaOverride = override;
|
|
574
|
+
if (rerender) {
|
|
575
|
+
this.rerender('component');
|
|
576
|
+
}
|
|
577
|
+
return this;
|
|
578
|
+
}
|
|
519
579
|
setLegendModeOverride(mode, rerender = true) {
|
|
520
580
|
if (this.legendModeOverride === mode) {
|
|
521
581
|
return this;
|
|
@@ -844,6 +904,7 @@ export class BaseChart {
|
|
|
844
904
|
}
|
|
845
905
|
validateSourceData(_data) { }
|
|
846
906
|
syncDerivedState(_previousData) { }
|
|
907
|
+
prepareForLegendChange() { }
|
|
847
908
|
initializeDataState() {
|
|
848
909
|
this.validateSourceData(this.sourceData);
|
|
849
910
|
this.syncDerivedState();
|
|
@@ -852,6 +913,23 @@ export class BaseChart {
|
|
|
852
913
|
prepareLayout(context) {
|
|
853
914
|
this.measureInlineLegend(context.svgNode);
|
|
854
915
|
}
|
|
916
|
+
applyPlotAreaOverride(plotArea) {
|
|
917
|
+
if (!this.plotAreaOverride) {
|
|
918
|
+
return plotArea;
|
|
919
|
+
}
|
|
920
|
+
const left = this.plotAreaOverride.left ?? plotArea.left;
|
|
921
|
+
const right = this.plotAreaOverride.right ?? plotArea.right;
|
|
922
|
+
const top = this.plotAreaOverride.top ?? plotArea.top;
|
|
923
|
+
const bottom = this.plotAreaOverride.bottom ?? plotArea.bottom;
|
|
924
|
+
return {
|
|
925
|
+
left,
|
|
926
|
+
right,
|
|
927
|
+
top,
|
|
928
|
+
bottom,
|
|
929
|
+
width: Math.max(0, right - left),
|
|
930
|
+
height: Math.max(0, bottom - top),
|
|
931
|
+
};
|
|
932
|
+
}
|
|
855
933
|
/**
|
|
856
934
|
* Setup ResizeObserver for automatic resize handling
|
|
857
935
|
*/
|
package/dist/chart-group.d.ts
CHANGED
|
@@ -96,6 +96,7 @@ export declare class ChartGroup {
|
|
|
96
96
|
private resolveSharedYDomain;
|
|
97
97
|
private warnIncompatibleYScaleTypes;
|
|
98
98
|
private applyScaleSyncOverrides;
|
|
99
|
+
private applyPlotAreaSyncOverrides;
|
|
99
100
|
private buildRows;
|
|
100
101
|
private resolveDefaultChartHeight;
|
|
101
102
|
private resolveDefaultChartHeightForWidth;
|
package/dist/chart-group.js
CHANGED
|
@@ -291,7 +291,9 @@ export class ChartGroup {
|
|
|
291
291
|
const { width, renderedTopText, renderedBottomText, renderedLegend, layout, totalHeight, } = this.prepareRenderState(container);
|
|
292
292
|
this.isRendering = true;
|
|
293
293
|
try {
|
|
294
|
-
this.
|
|
294
|
+
const sharedYDomain = this.resolveSharedYDomain(width);
|
|
295
|
+
this.applyScaleSyncOverrides(width, sharedYDomain);
|
|
296
|
+
this.applyPlotAreaSyncOverrides(layout.items, sharedYDomain);
|
|
295
297
|
container.innerHTML = '';
|
|
296
298
|
const { root, chartLayer } = this.createRenderHosts(totalHeight, layout.chartHeight);
|
|
297
299
|
this.appendRenderedTextSections(root, renderedTopText);
|
|
@@ -376,6 +378,7 @@ export class ChartGroup {
|
|
|
376
378
|
chart.setLegendModeOverride(null, false);
|
|
377
379
|
if (chart instanceof XYChart) {
|
|
378
380
|
chart.setScaleConfigOverride(null, false);
|
|
381
|
+
chart.setPlotAreaOverride(null, false);
|
|
379
382
|
}
|
|
380
383
|
chart.destroy();
|
|
381
384
|
});
|
|
@@ -508,9 +511,8 @@ export class ChartGroup {
|
|
|
508
511
|
this.hasWarnedIncompatibleYScaleTypes = true;
|
|
509
512
|
ChartValidator.warn('ChartGroup: syncY requires all synced XY child charts to use the same vertical numeric scale type');
|
|
510
513
|
}
|
|
511
|
-
applyScaleSyncOverrides(width) {
|
|
514
|
+
applyScaleSyncOverrides(width, sharedDomain) {
|
|
512
515
|
const syncedCharts = new Set(this.getVerticalXYCharts(width));
|
|
513
|
-
const sharedDomain = this.resolveSharedYDomain(width);
|
|
514
516
|
this.getAllVerticalXYCharts().forEach((chart) => {
|
|
515
517
|
if (!sharedDomain || !syncedCharts.has(chart)) {
|
|
516
518
|
chart.setScaleConfigOverride(null, false);
|
|
@@ -524,6 +526,43 @@ export class ChartGroup {
|
|
|
524
526
|
}, false);
|
|
525
527
|
});
|
|
526
528
|
}
|
|
529
|
+
applyPlotAreaSyncOverrides(items, sharedDomain) {
|
|
530
|
+
this.getAllVerticalXYCharts().forEach((chart) => {
|
|
531
|
+
chart.setPlotAreaOverride(null, false);
|
|
532
|
+
});
|
|
533
|
+
if (!sharedDomain) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const rowItems = new Map();
|
|
537
|
+
items.forEach((item) => {
|
|
538
|
+
if (!(item.chart instanceof XYChart) ||
|
|
539
|
+
item.chart.getOrientation() !== 'vertical') {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const row = rowItems.get(item.y) ?? [];
|
|
543
|
+
row.push(item);
|
|
544
|
+
rowItems.set(item.y, row);
|
|
545
|
+
});
|
|
546
|
+
rowItems.forEach((row) => {
|
|
547
|
+
if (row.length < 2) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const measuredPlotAreas = row.map((item) => {
|
|
551
|
+
return {
|
|
552
|
+
chart: item.chart,
|
|
553
|
+
plotArea: item.chart.measurePlotArea(item.width, item.height),
|
|
554
|
+
};
|
|
555
|
+
});
|
|
556
|
+
const top = Math.max(...measuredPlotAreas.map(({ plotArea }) => plotArea.top));
|
|
557
|
+
const bottom = Math.min(...measuredPlotAreas.map(({ plotArea }) => plotArea.bottom));
|
|
558
|
+
if (bottom <= top) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
measuredPlotAreas.forEach(({ chart }) => {
|
|
562
|
+
chart.setPlotAreaOverride({ top, bottom }, false);
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
}
|
|
527
566
|
buildRows(entries, width, cols, gap) {
|
|
528
567
|
const availableWidth = Math.max(1, width - gap * Math.max(0, cols - 1));
|
|
529
568
|
const columnWidth = availableWidth / cols;
|
|
@@ -802,10 +841,12 @@ export class ChartGroup {
|
|
|
802
841
|
this.resizeObserver.observe(this.container);
|
|
803
842
|
}
|
|
804
843
|
async exportSVG(format, width, options) {
|
|
805
|
-
this.
|
|
844
|
+
const sharedYDomain = this.resolveSharedYDomain(width);
|
|
845
|
+
this.applyScaleSyncOverrides(width, sharedYDomain);
|
|
806
846
|
const baseContext = this.createExportRenderContext(format, width, options);
|
|
807
847
|
const exportLayoutState = this.resolveExportLayoutState(width, baseContext);
|
|
808
848
|
const layout = this.calculateLayout(width, exportLayoutState.chartAreaHeight, exportLayoutState.defaultChartHeightOverride);
|
|
849
|
+
this.applyPlotAreaSyncOverrides(layout.items, sharedYDomain);
|
|
809
850
|
const childSvgs = await this.exportLayoutItems(layout.items, options);
|
|
810
851
|
const totalHeight = exportLayoutState.topTextHeight +
|
|
811
852
|
layout.chartHeight +
|
package/dist/donut-chart.d.ts
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
import type { DataItem, LegendSeries } from './types.js';
|
|
1
|
+
import type { DataItem, LabelOversizedBehavior, LegendSeries } from './types.js';
|
|
2
2
|
import { type BaseChartConfig, type BaseRenderContext } from './base-chart.js';
|
|
3
3
|
import type { ChartComponentBase } from './chart-interface.js';
|
|
4
4
|
import { RadialChartBase } from './radial-chart-base.js';
|
|
5
|
+
import { type RadialAnimationConfig, type RadialAnimationEasingPreset } from './radial-animation.js';
|
|
6
|
+
export type DonutAnimationConfig = RadialAnimationConfig;
|
|
7
|
+
export type DonutAnimationEasingPreset = RadialAnimationEasingPreset;
|
|
5
8
|
export type DonutConfig = {
|
|
6
9
|
innerRadius?: number;
|
|
7
10
|
padAngle?: number;
|
|
8
11
|
cornerRadius?: number;
|
|
9
12
|
};
|
|
10
13
|
export type DonutValueLabelPosition = 'outside' | 'auto';
|
|
14
|
+
export type DonutValueLabelFormatter = (label: string, value: number, data: DataItem, percentage: number) => string;
|
|
11
15
|
export type DonutValueLabelConfig = {
|
|
12
16
|
show?: boolean;
|
|
13
17
|
position?: DonutValueLabelPosition;
|
|
14
18
|
outsideOffset?: number;
|
|
15
19
|
minVerticalSpacing?: number;
|
|
16
|
-
|
|
20
|
+
maxLabelWidth?: number;
|
|
21
|
+
oversizedBehavior?: LabelOversizedBehavior;
|
|
22
|
+
forceVisible?: boolean;
|
|
23
|
+
labelFormatter?: DonutValueLabelFormatter;
|
|
24
|
+
valueFormatter?: DonutValueLabelFormatter;
|
|
25
|
+
separator?: string;
|
|
26
|
+
formatter?: DonutValueLabelFormatter;
|
|
17
27
|
};
|
|
18
28
|
export type DonutChartConfig = BaseChartConfig & {
|
|
19
29
|
donut?: DonutConfig;
|
|
20
30
|
valueLabel?: DonutValueLabelConfig;
|
|
31
|
+
animate?: boolean | DonutAnimationConfig;
|
|
21
32
|
valueKey?: string;
|
|
22
33
|
labelKey?: string;
|
|
23
34
|
};
|
|
@@ -28,6 +39,7 @@ export declare class DonutChart extends RadialChartBase {
|
|
|
28
39
|
private readonly valueKey;
|
|
29
40
|
private readonly labelKey;
|
|
30
41
|
private readonly valueLabel;
|
|
42
|
+
private readonly motionController;
|
|
31
43
|
private segments;
|
|
32
44
|
private centerContent;
|
|
33
45
|
constructor(config: DonutChartConfig);
|
|
@@ -36,16 +48,20 @@ export declare class DonutChart extends RadialChartBase {
|
|
|
36
48
|
addChild(component: ChartComponentBase): this;
|
|
37
49
|
protected getExportComponents(): ChartComponentBase[];
|
|
38
50
|
update(data: DataItem[]): void;
|
|
51
|
+
protected prepareForLegendChange(): void;
|
|
39
52
|
protected createExportChart(): RadialChartBase;
|
|
40
53
|
protected applyComponentOverrides(overrides: Map<ChartComponentBase, ChartComponentBase>): () => void;
|
|
41
54
|
protected syncDerivedState(): void;
|
|
42
55
|
protected renderChart({ svg, plotGroup, plotArea, }: BaseRenderContext): void;
|
|
43
56
|
protected getLegendSeries(): LegendSeries[];
|
|
44
57
|
private buildTooltipContent;
|
|
45
|
-
private
|
|
58
|
+
private resolveValueLabelText;
|
|
59
|
+
private getValueLabelPercentage;
|
|
46
60
|
private renderSegments;
|
|
47
61
|
private renderLabels;
|
|
48
62
|
private getArcPoint;
|
|
49
63
|
private resolveOutsideLabel;
|
|
64
|
+
private measureValueLabelDimensions;
|
|
50
65
|
private adjustOutsideLabelPositions;
|
|
66
|
+
private getOutsideLabelSpacing;
|
|
51
67
|
}
|