Added support for valueFormat directive

This commit is contained in:
Knut Sveidqvist
2025-05-12 17:40:23 +02:00
parent 2def5a0768
commit df1e739194
9 changed files with 249 additions and 49 deletions

View File

@@ -113,7 +113,7 @@ classDef secondary fill:#6cf,stroke:#333,stroke-dasharray:5 5;
);
});
it('8: should handle value formatting', () => {
it('8: should handle dollar value formatting with thousands separator', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '$0,0'}}}%%
treemap
@@ -130,6 +130,103 @@ treemap
);
});
it('8a: should handle percentage formatting', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '.1%'}}}%%
treemap
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
`,
{}
);
});
it('8b: should handle decimal formatting', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '.2f'}}}%%
treemap
"Metrics"
"Conversion Rate": 0.0567
"Bounce Rate": 0.6723
"Click-through Rate": 0.1289
"Engagement": 0.4521
`,
{}
);
});
it('8c: should handle dollar sign with decimal places', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '$.2f'}}}%%
treemap
"Product Prices"
"Basic": 19.99
"Standard": 49.99
"Premium": 99.99
"Enterprise": 199.99
`,
{}
);
});
it('8d: should handle dollar sign with thousands separator and decimal places', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '$,.2f'}}}%%
treemap
"Revenue"
"Q1": 1250345.75
"Q2": 1645789.25
"Q3": 1845123.50
"Q4": 2145678.75
`,
{}
);
});
it('8e: should handle simple thousands separator', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': ','}}}%%
treemap
"User Counts"
"Active Users": 1250345
"New Signups": 45789
"Churned": 12350
"Converted": 78975
`,
{}
);
});
it('8f: should handle valueFormat set via directive with dollar and thousands separator', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '$,.0f'}}}%%
treemap
"Sales by Region"
"North": 1234567
"South": 7654321
"East": 4567890
"West": 9876543
`,
{}
);
});
it('8g: should handle scientific notation format', () => {
imgSnapshotTest(
`%%{init: {'treemap': {'valueFormat': '.2e'}}}%%
treemap
"Scientific Values"
"Value 1": 1234567
"Value 2": 0.0000123
"Value 3": 1000000000
`,
{}
);
});
it('9: should handle a complex example with multiple features', () => {
imgSnapshotTest(
`%%{init: {'theme': 'dark', 'treemap': {'valueFormat': '$0,0'}}}%%

View File

@@ -130,7 +130,7 @@
</head>
<body>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
treemap
"Section 1"
"Leaf 1.1": 12
@@ -151,12 +151,12 @@ classDef class1 fill:red,color:blue,stroke:#FFD600;
treemap
"Budget"
"Operations"
"Salaries": 700000
"Equipment": 200000
"Supplies": 100000
"Salaries": 7000
"Equipment": 2000
"Supplies": 1000
"Marketing"
"Advertising": 400000
"Events": 100000
"Advertising": 4000
"Events": 1000
</pre
>

View File

@@ -91,7 +91,8 @@ mermaid.initialize({
nodeHeight: 40,
borderWidth: 1,
valueFontSize: 12,
labelFontSize: 14
labelFontSize: 14,
valueFormat: ','
}
});
```
@@ -108,6 +109,48 @@ Key configuration options:
| borderWidth | Width of node borders | 1 |
| valueFontSize| Font size for values | 12 |
| labelFontSize| Font size for node labels | 14 |
| valueFormat | Format string for values (D3 format) | ',' |
## Value Formatting
You can customize how values are displayed in the treemap using the `valueFormat` configuration option. This option primarily uses [D3's format specifiers](https://github.com/d3/d3-format#locale_format) to control how numbers are displayed, with some additional special cases for common formats.
Common format patterns:
- `,` - Thousands separator (default)
- `$` - Add dollar sign
- `.1f` - Show one decimal place
- `.1%` - Show as percentage with one decimal place
- `$0,0` - Dollar sign with thousands separator
- `$.2f` - Dollar sign with 2 decimal places
- `$,.2f` - Dollar sign with thousands separator and 2 decimal places
The treemap diagram supports both standard D3 format specifiers and some common currency formats that combine the dollar sign with other formatting options.
Example with currency formatting:
```mermaid
%%{init: {'treemap': {'valueFormat': '$0,0'}}}%%
treemap
Budget
Development
Frontend: 250000
Backend: 350000
Marketing
Digital: 150000
Print: 50000
```
Example with percentage formatting:
```mermaid
%%{init: {'treemap': {'valueFormat': '.1%'}}}%%
treemap
Market Share
Company A: 0.35
Company B: 0.25
Company C: 0.15
Others: 0.25
```
## Notes and Limitations

View File

@@ -267,6 +267,7 @@ const config: RequiredDeep<MermaidConfig> = {
borderWidth: 1,
valueFontSize: 12,
labelFontSize: 14,
valueFormat: ',',
},
};

View File

@@ -47,7 +47,33 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
configureSvgSize(svg, svgHeight, svgWidth, config.useMaxWidth);
// Format for displaying values
const valueFormat = format(',');
let valueFormat;
try {
// Handle special format patterns
const formatStr = config.valueFormat || ',';
// Handle special cases that aren't directly supported by D3 format
if (formatStr === '$0,0') {
// Currency with thousands separator
valueFormat = (value: number) => '$' + format(',')(value);
} else if (formatStr.startsWith('$') && formatStr.includes(',')) {
// Other dollar formats with commas
const precision = formatStr.match(/\.\d+/);
const precisionStr = precision ? precision[0] : '';
valueFormat = (value: number) => '$' + format(',' + precisionStr)(value);
} else if (formatStr.startsWith('$')) {
// Simple dollar sign prefix
const restOfFormat = formatStr.substring(1);
valueFormat = (value: number) => '$' + format(restOfFormat || '')(value);
} else {
// Standard D3 format
valueFormat = format(formatStr);
}
} catch (error) {
console.error('Error creating format function:', error);
// Fallback to default format
valueFormat = format(',');
}
// Create color scale
const colorScale = scaleOrdinal<string>().range([

View File

@@ -1,53 +1,51 @@
import type { DiagramStylesProvider } from '../../diagram-api/types.js';
import { cleanAndMerge } from '../../utils.js';
import type { PacketStyleOptions } from './types.js';
import type { TreemapStyleOptions } from './types.js';
const defaultPacketStyleOptions: PacketStyleOptions = {
byteFontSize: '10px',
startByteColor: 'black',
endByteColor: 'black',
const defaultTreemapStyleOptions: TreemapStyleOptions = {
sectionStrokeColor: 'black',
sectionStrokeWidth: '1',
sectionFillColor: '#efefef',
leafStrokeColor: 'black',
leafStrokeWidth: '1',
leafFillColor: '#efefef',
labelColor: 'black',
labelFontSize: '12px',
valueFontSize: '10px',
valueColor: 'black',
titleColor: 'black',
titleFontSize: '14px',
blockStrokeColor: 'black',
blockStrokeWidth: '1',
blockFillColor: '#efefef',
};
export const getStyles: DiagramStylesProvider = ({
packet,
}: { packet?: PacketStyleOptions } = {}) => {
const options = cleanAndMerge(defaultPacketStyleOptions, packet);
treemap,
}: { treemap?: TreemapStyleOptions } = {}) => {
const options = cleanAndMerge(defaultTreemapStyleOptions, treemap);
return `
.treemapNode {
// stroke: black;
// stroke-width: 1;
.treemapNode.section {
stroke: ${options.sectionStrokeColor};
stroke-width: ${options.sectionStrokeWidth};
fill: ${options.sectionFillColor};
}
.packetByte {
font-size: ${options.byteFontSize};
}
.packetByte.start {
fill: ${options.startByteColor};
}
.packetByte.end {
fill: ${options.endByteColor};
}
.packetLabel {
fill: ${options.labelColor};
font-size: ${options.labelFontSize};
}
.packetTitle {
fill: ${options.titleColor};
font-size: ${options.titleFontSize};
}
.packetBlock {
stroke: ${options.blockStrokeColor};
stroke-width: ${options.blockStrokeWidth};
fill: ${options.blockFillColor};
}
`;
.treemapNode.leaf {
stroke: ${options.leafStrokeColor};
stroke-width: ${options.leafStrokeWidth};
fill: ${options.leafFillColor};
}
.treemapLabel {
fill: ${options.labelColor};
font-size: ${options.labelFontSize};
}
.treemapValue {
fill: ${options.valueColor};
font-size: ${options.valueFontSize};
}
.treemapTitle {
fill: ${options.titleColor};
font-size: ${options.titleFontSize};
}
`;
};
export default getStyles;

View File

@@ -49,4 +49,5 @@ export interface TreemapDiagramConfig extends BaseDiagramConfig {
borderWidth?: number;
valueFontSize?: number;
labelFontSize?: number;
valueFormat?: string;
}

View File

@@ -6,7 +6,14 @@ import type { TreemapNode } from './types.js';
* @returns A hierarchical tree structure
*/
export function buildHierarchy(
items: { level: number; name: string; type: string; value?: number; classSelector?: string }[]
items: {
level: number;
name: string;
type: string;
value?: number;
classSelector?: string;
cssCompiledStyles?: string;
}[]
): TreemapNode[] {
if (!items.length) {
return [];
@@ -21,7 +28,9 @@ export function buildHierarchy(
children: item.type === 'Leaf' ? undefined : [],
};
node.classSelector = item?.classSelector;
node.cssCompiledStyles = item?.cssCompiledStyles;
if (item?.cssCompiledStyles) {
node.cssCompiledStyles = [item.cssCompiledStyles];
}
if (item.type === 'Leaf' && item.value !== undefined) {
node.value = item.value;

View File

@@ -141,7 +141,20 @@ treemap
### Value Formatting
Values in treemap diagrams can be formatted to display in different ways:
Values in treemap diagrams can be formatted to display in different ways using the `valueFormat` configuration option. This option primarily uses [D3's format specifiers](https://github.com/d3/d3-format#locale_format) to control how numbers are displayed, with some additional special cases for common formats.
Some common format patterns:
- `,` - Thousands separator (default)
- `$` - Add dollar sign
- `.1f` - Show one decimal place
- `.1%` - Show as percentage with one decimal place
- `$0,0` - Dollar sign with thousands separator
- `$.2f` - Dollar sign with 2 decimal places
- `$,.2f` - Dollar sign with thousands separator and 2 decimal places
The treemap diagram supports both standard D3 format specifiers and some common currency formats that combine the dollar sign with other formatting options.
Example with currency formatting:
```mermaid-example
%%{init: {'treemap': {'valueFormat': '$0,0'}}}%%
@@ -156,6 +169,18 @@ treemap
"Events": 100000
```
Example with percentage formatting:
```mermaid-example
%%{init: {'treemap': {'valueFormat': '.1%'}}}%%
treemap
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
```
## Common Use Cases
Treemap diagrams are commonly used for: