diff --git a/cypress/integration/rendering/pie.spec.ts b/cypress/integration/rendering/pie.spec.ts index 4a1d774c0a..9771c32a5a 100644 --- a/cypress/integration/rendering/pie.spec.ts +++ b/cypress/integration/rendering/pie.spec.ts @@ -74,6 +74,17 @@ describe('pie chart', () => { ); }); + it('should render a pie diagram when percentageDecimals is setted', () => { + imgSnapshotTest( + `pie + "Dogs" : 80 + "Cats" : 86 + "Rats" : 80 + `, + { logLevel: 1, pie: { percentageDecimals: 2 } } + ); + }); + it('should render a pie diagram with showData', () => { imgSnapshotTest( `pie showData @@ -82,4 +93,15 @@ describe('pie chart', () => { ` ); }); + + it('should render a pie diagram and use half even rounding by default', () => { + // depending on the rounding method, the sum of the percentages can be 101 (default rounding), or 99 (half even) + imgSnapshotTest( + `pie + "Dogs" : 80 + "Cats" : 86 + "Rats" : 80 + ` + ); + }); }); diff --git a/docs/syntax/pie.md b/docs/syntax/pie.md index 8b1de3856a..0f81bcae3f 100644 --- a/docs/syntax/pie.md +++ b/docs/syntax/pie.md @@ -71,6 +71,7 @@ pie showData Possible pie diagram configuration parameters: -| Parameter | Description | Default value | -| -------------- | ------------------------------------------------------------------------------------------------------------ | ------------- | -| `textPosition` | The axial position of the pie slice labels, from 0.0 at the center to 1.0 at the outside edge of the circle. | `0.75` | +| Parameter | Description | Default value | +| -------------------- | ------------------------------------------------------------------------------------------------------------ | ------------- | +| `textPosition` | The axial position of the pie slice labels, from 0.0 at the center to 1.0 at the outside edge of the circle. | `0.75` | +| `percentageDecimals` | The number of decimal places to show in the percentage label, from 0 to 20. (v\+) | `0` | diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index 889e5ff254..45217c08db 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -641,6 +641,11 @@ export interface PieDiagramConfig extends BaseDiagramConfig { * */ textPosition?: number; + /** + * The number of decimal places to show in the percentage label. + * + */ + percentageDecimals?: number; } /** * This interface was referenced by `MermaidConfig`'s JSON-Schema diff --git a/packages/mermaid/src/diagrams/pie/pie.spec.ts b/packages/mermaid/src/diagrams/pie/pie.spec.ts index 47a9a95f55..fed60c6695 100644 --- a/packages/mermaid/src/diagrams/pie/pie.spec.ts +++ b/packages/mermaid/src/diagrams/pie/pie.spec.ts @@ -164,6 +164,9 @@ describe('pie', () => { // db.setConfig({ textPosition: 0 }); // db.resetConfig(); expect(db.getConfig().textPosition).toStrictEqual(DEFAULT_PIE_DB.config.textPosition); + expect(db.getConfig().percentageDecimals).toStrictEqual( + DEFAULT_PIE_DB.config.percentageDecimals + ); }); }); }); diff --git a/packages/mermaid/src/diagrams/pie/pieRenderer.ts b/packages/mermaid/src/diagrams/pie/pieRenderer.ts index a24bcb532b..5e8d4c9268 100644 --- a/packages/mermaid/src/diagrams/pie/pieRenderer.ts +++ b/packages/mermaid/src/diagrams/pie/pieRenderer.ts @@ -50,6 +50,12 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { const sections: Sections = db.getSections(); group.attr('transform', 'translate(' + pieWidth / 2 + ',' + height / 2 + ')'); + const percentFormatter = new Intl.NumberFormat('en-US', { + style: 'percent', + roundingMode: 'halfEven', // Half even rounding is used to avoid the sum of the percentages to be greater than 100%. + minimumFractionDigits: pieConfig.percentageDecimals, + } as Intl.NumberFormatOptions); + const { themeVariables } = globalConfig; let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth); outerStrokeWidth ??= 2; @@ -118,7 +124,15 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { .enter() .append('text') .text((datum: d3.PieArcDatum): string => { - return ((datum.data.value / sum) * 100).toFixed(0) + '%'; + let num = datum.data.value / sum; + + // "Half even" rounding mode rounds exactly .5 to the nearest, even number. + // By using 3 decimal places, we can round "close to .5" to the nearest even number too. + if (pieConfig.percentageDecimals === 0) { + num = Number(num.toFixed(3)); + } + + return percentFormatter.format(num); }) .attr('transform', (datum: d3.PieArcDatum): string => { return 'translate(' + labelArcGenerator.centroid(datum) + ')'; diff --git a/packages/mermaid/src/docs/syntax/pie.md b/packages/mermaid/src/docs/syntax/pie.md index 81ec720c4f..e10ce4dab3 100644 --- a/packages/mermaid/src/docs/syntax/pie.md +++ b/packages/mermaid/src/docs/syntax/pie.md @@ -48,6 +48,7 @@ pie showData Possible pie diagram configuration parameters: -| Parameter | Description | Default value | -| -------------- | ------------------------------------------------------------------------------------------------------------ | ------------- | -| `textPosition` | The axial position of the pie slice labels, from 0.0 at the center to 1.0 at the outside edge of the circle. | `0.75` | +| Parameter | Description | Default value | +| -------------------- | ------------------------------------------------------------------------------------------------------------ | ------------- | +| `textPosition` | The axial position of the pie slice labels, from 0.0 at the center to 1.0 at the outside edge of the circle. | `0.75` | +| `percentageDecimals` | The number of decimal places to show in the percentage label, from 0 to 20. (v+) | `0` | diff --git a/packages/mermaid/src/schemas/config.schema.yaml b/packages/mermaid/src/schemas/config.schema.yaml index 415af63f69..bc5bcd539e 100644 --- a/packages/mermaid/src/schemas/config.schema.yaml +++ b/packages/mermaid/src/schemas/config.schema.yaml @@ -876,6 +876,13 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) description: | Axial position of slice's label from zero at the center to 1 at the outside edges. default: 0.75 + percentageDecimals: + type: integer + minimum: 0 + maximum: 20 + description: | + The number of decimal places to show in the percentage label. + default: 0 QuadrantChartConfig: title: Quadrant Chart Config