diff --git a/cypress/integration/rendering/treemap.spec.ts b/cypress/integration/rendering/treemap.spec.ts index 05dce09ff..8b8203c24 100644 --- a/cypress/integration/rendering/treemap.spec.ts +++ b/cypress/integration/rendering/treemap.spec.ts @@ -3,7 +3,7 @@ import { imgSnapshotTest } from '../../helpers/util.ts'; describe('Treemap Diagram', () => { it('1: should render a basic treemap', () => { imgSnapshotTest( - `treemap + `treemap-beta "Category A" "Item A1": 10 "Item A2": 20 @@ -17,7 +17,7 @@ describe('Treemap Diagram', () => { it('2: should render a hierarchical treemap', () => { imgSnapshotTest( - `treemap + `treemap-beta "Products" "Electronics" "Phones": 50 @@ -37,7 +37,7 @@ describe('Treemap Diagram', () => { it('3: should render a treemap with styling using classDef', () => { imgSnapshotTest( - `treemap + `treemap-beta "Section 1" "Leaf 1.1": 12 "Section 1.2":::class1 @@ -55,7 +55,7 @@ classDef class1 fill:red,color:blue,stroke:#FFD600; it('4: should handle long text that wraps', () => { imgSnapshotTest( - `treemap + `treemap-beta "Main Category" "This is a very long item name that should wrap to the next line when rendered in the treemap diagram": 50 "Short item": 20 @@ -67,7 +67,7 @@ classDef class1 fill:red,color:blue,stroke:#FFD600; it('5: should render with a forest theme', () => { imgSnapshotTest( `%%{init: {'theme': 'forest'}}%% -treemap +treemap-beta "Category A" "Item A1": 10 "Item A2": 20 @@ -81,7 +81,7 @@ treemap it('6: should handle multiple levels of nesting', () => { imgSnapshotTest( - `treemap + `treemap-beta "Level 1" "Level 2A" "Level 3A": 10 @@ -98,7 +98,7 @@ treemap it('7: should handle classDef with multiple styles', () => { imgSnapshotTest( - `treemap + `treemap-beta "Main" "A": 20 "B":::important @@ -133,7 +133,7 @@ treemap it('8a: should handle percentage formatting', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': '.1%'}}}%% -treemap +treemap-beta "Market Share" "Company A": 0.35 "Company B": 0.25 @@ -147,7 +147,7 @@ treemap it('8b: should handle decimal formatting', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': '.2f'}}}%% -treemap +treemap-beta "Metrics" "Conversion Rate": 0.0567 "Bounce Rate": 0.6723 @@ -161,7 +161,7 @@ treemap it('8c: should handle dollar sign with decimal places', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': '$.2f'}}}%% -treemap +treemap-beta "Product Prices" "Basic": 19.99 "Standard": 49.99 @@ -175,7 +175,7 @@ treemap it('8d: should handle dollar sign with thousands separator and decimal places', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': '$,.2f'}}}%% -treemap +treemap-beta "Revenue" "Q1": 1250345.75 "Q2": 1645789.25 @@ -189,7 +189,7 @@ treemap it('8e: should handle simple thousands separator', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': ','}}}%% -treemap +treemap-beta "User Counts" "Active Users": 1250345 "New Signups": 45789 @@ -203,7 +203,7 @@ treemap it('8f: should handle valueFormat set via directive with dollar and thousands separator', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': '$,.0f'}}}%% -treemap +treemap-beta "Sales by Region" "North": 1234567 "South": 7654321 @@ -217,7 +217,7 @@ treemap it('8g: should handle scientific notation format', () => { imgSnapshotTest( `%%{init: {'treemap': {'valueFormat': '.2e'}}}%% -treemap +treemap-beta "Scientific Values" "Value 1": 1234567 "Value 2": 0.0000123 @@ -230,7 +230,7 @@ treemap it('9: should handle a complex example with multiple features', () => { imgSnapshotTest( `%%{init: {'theme': 'dark', 'treemap': {'valueFormat': '$0,0'}}}%% -treemap +treemap-beta "Company Budget" "Engineering":::engineering "Frontend": 300000 @@ -255,7 +255,7 @@ classDef sales fill:#c3a66b,stroke:#333; it('10: should render the example from documentation', () => { imgSnapshotTest( ` - treemap + treemap-beta "Section 1" "Leaf 1.1": 12 "Section 1.2":::class1 @@ -274,7 +274,7 @@ classDef sales fill:#c3a66b,stroke:#333; it('11: should handle comments', () => { imgSnapshotTest( ` - treemap + treemap-beta %% This is a comment "Category A" "Item A1": 10 @@ -288,10 +288,10 @@ classDef sales fill:#c3a66b,stroke:#333; ); }); - it('12: should render a treemap with title', () => { + it.skip('12: should render a treemap with title', () => { imgSnapshotTest( ` - treemap + treemap-beta title Treemap with Title "Category A" "Item A1": 10 @@ -304,10 +304,10 @@ classDef sales fill:#c3a66b,stroke:#333; ); }); - it('13: should render a treemap with accessibility attributes', () => { + it.skip('13: should render a treemap with accessibility attributes', () => { imgSnapshotTest( ` - treemap + treemap-beta accTitle: Accessible Treemap Title accDescr: This is a description of the treemap for accessibility purposes "Category A" @@ -321,7 +321,7 @@ classDef sales fill:#c3a66b,stroke:#333; ); }); - it('14: should render a treemap with title and accessibility attributes', () => { + it.skip('14: should render a treemap with title and accessibility attributes', () => { imgSnapshotTest( ` treemap diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 24ad332e6..ab7ded0c2 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -146,7 +146,7 @@ classDef class1 fill:red,color:blue,stroke:#FFD600; -
+    
 ---
 config:
   treemap:
@@ -166,7 +166,7 @@ treemap
     >
     
     treemap
-      title Treemap with Title
+      title Accessible Treemap Title
       "Category A"
           "Item A1": 10
           "Item A2": 20
@@ -507,7 +507,7 @@ kanban
         alert('It worked');
       }
       await mermaid.initialize({
-        theme: 'forest',
+        // theme: 'forest',
         // theme: 'default',
         // theme: 'forest',
         // handDrawnSeed: 12,
diff --git a/docs/syntax/treemap.md b/docs/syntax/treemap.md
index ee8daec61..aa579e60b 100644
--- a/docs/syntax/treemap.md
+++ b/docs/syntax/treemap.md
@@ -25,7 +25,7 @@ Treemap diagrams are particularly useful for:
 ## Syntax
 
 ```
-treemap
+treemap-beta
 "Section 1"
     "Leaf 1.1": 12
     "Section 1.2"
@@ -49,7 +49,7 @@ Nodes in a treemap are defined using the following syntax:
 ### Basic Treemap
 
 ```mermaid-example
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -59,7 +59,7 @@ treemap
 ```
 
 ```mermaid
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -71,7 +71,7 @@ treemap
 ### Hierarchical Treemap
 
 ```mermaid-example
-treemap
+treemap-beta
 "Products"
     "Electronics"
         "Phones": 50
@@ -83,7 +83,7 @@ treemap
 ```
 
 ```mermaid
-treemap
+treemap-beta
 "Products"
     "Electronics"
         "Phones": 50
@@ -97,7 +97,7 @@ treemap
 ### Treemap with Styling
 
 ```mermaid-example
-treemap
+treemap-beta
 "Section 1"
     "Leaf 1.1": 12
     "Section 1.2":::class1
@@ -111,7 +111,7 @@ classDef class1 fill:red,color:blue,stroke:#FFD600;
 ```
 
 ```mermaid
-treemap
+treemap-beta
 "Section 1"
     "Leaf 1.1": 12
     "Section 1.2":::class1
@@ -133,7 +133,7 @@ Treemap diagrams can be customized using Mermaid's styling and configuration opt
 You can define custom styles for nodes using the `classDef` syntax, which is a standard feature across many Mermaid diagram types:
 
 ```mermaid-example
-treemap
+treemap-beta
 "Main"
     "A": 20
     "B":::important
@@ -145,7 +145,7 @@ classDef important fill:#f96,stroke:#333,stroke-width:2px;
 ```
 
 ```mermaid
-treemap
+treemap-beta
 "Main"
     "A": 20
     "B":::important
@@ -165,7 +165,7 @@ You can customize the colors of your treemap using the theme configuration:
 config:
     theme: 'forest'
 ---
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -179,7 +179,7 @@ treemap
 config:
     theme: 'forest'
 ---
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -198,7 +198,7 @@ config:
   treemap:
     diagramPadding: 200
 ---
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -213,7 +213,7 @@ config:
   treemap:
     diagramPadding: 200
 ---
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -265,7 +265,7 @@ config:
   treemap:
     valueFormat: '$0,0'
 ---
-treemap
+treemap-beta
 "Budget"
     "Operations"
         "Salaries": 700000
@@ -282,7 +282,7 @@ config:
   treemap:
     valueFormat: '$0,0'
 ---
-treemap
+treemap-beta
 "Budget"
     "Operations"
         "Salaries": 700000
@@ -301,7 +301,7 @@ config:
   treemap:
     valueFormat: '$.1%'
 ---
-treemap
+treemap-beta
 "Market Share"
     "Company A": 0.35
     "Company B": 0.25
@@ -315,7 +315,7 @@ config:
   treemap:
     valueFormat: '$.1%'
 ---
-treemap
+treemap-beta
 "Market Share"
     "Company A": 0.35
     "Company B": 0.25
diff --git a/packages/mermaid/src/diagrams/treemap/renderer.ts b/packages/mermaid/src/diagrams/treemap/renderer.ts
index 57de7e5f9..6c5f8efd2 100644
--- a/packages/mermaid/src/diagrams/treemap/renderer.ts
+++ b/packages/mermaid/src/diagrams/treemap/renderer.ts
@@ -78,6 +78,7 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
 
   // Create color scale
   const colorScale = scaleOrdinal().range([
+    'transparent',
     themeVariables.cScale0,
     themeVariables.cScale1,
     themeVariables.cScale2,
@@ -92,6 +93,7 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
     themeVariables.cScale11,
   ]);
   const colorScalePeer = scaleOrdinal().range([
+    'transparent',
     themeVariables.cScalePeer0,
     themeVariables.cScalePeer1,
     themeVariables.cScalePeer2,
@@ -158,10 +160,8 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
   // Apply the treemap layout to the hierarchy
   const treemapData = treemapLayout(hierarchyRoot);
 
-  // Draw section nodes (branches - nodes with children), excluding the root node
-  const branchNodes = treemapData
-    .descendants()
-    .filter((d) => d.children && d.children.length > 0 && d.depth > 0);
+  // Draw section nodes (branches - nodes with children)
+  const branchNodes = treemapData.descendants().filter((d) => d.children && d.children.length > 0);
   const sections = g
     .selectAll('.treemapSection')
     .data(branchNodes)
@@ -177,9 +177,15 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
     .attr('height', SECTION_HEADER_HEIGHT)
     .attr('class', 'treemapSectionHeader')
     .attr('fill', 'none')
-    .attr('fill-opacity', (d) => (d.depth === 0 ? 0 : 0.6))
-    .attr('stroke-width', (d) => (d.depth === 0 ? 0 : 0.6))
-    .attr('style', (d) => (d.depth === 0 ? 'display: none;' : ''));
+    .attr('fill-opacity', 0.6)
+    .attr('stroke-width', 0.6)
+    .attr('style', (d) => {
+      // Hide the label for the root section
+      if (d.depth === 0) {
+        return 'display: none;';
+      }
+      return '';
+    });
 
   // Add clip paths for section headers to prevent text overflow
   sections
@@ -196,12 +202,16 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
     .attr('class', (_d, i) => {
       return `treemapSection section${i}`;
     })
-
-    .attr('fill-opacity', (d) => (d.depth === 0 ? 0 : 0.6))
-    .attr('stroke', (d) => (d.depth === 0 ? 'transparent' : colorScalePeer(d.data.name)))
+    .attr('fill', (d) => colorScale(d.data.name))
+    .attr('fill-opacity', 0.6)
+    .attr('stroke', (d) => colorScalePeer(d.data.name))
     .attr('stroke-width', 2.0)
-    .attr('stroke-opacity', (d) => (d.depth === 0 ? 0 : 0.4))
+    .attr('stroke-opacity', 0.4)
     .attr('style', (d) => {
+      // Hide the label for the root section
+      if (d.depth === 0) {
+        return 'display: none;';
+      }
       const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
       return styles.nodeStyles + ';' + styles.borderStyles.join(';');
     });
@@ -281,7 +291,7 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
       .attr('y', SECTION_HEADER_HEIGHT / 2)
       .attr('text-anchor', 'end')
       .attr('dominant-baseline', 'middle')
-      .text((d) => (d.depth === 0 ? '' : d.value ? valueFormat(d.value) : '')) // Skip value for root section
+      .text((d) => (d.value ? valueFormat(d.value) : ''))
       .attr('font-style', 'italic')
       .attr('style', (d) => {
         // Hide the value for the root section
@@ -297,8 +307,8 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
       });
   }
 
-  // Draw the leaf nodes, excluding the root node
-  const leafNodes = treemapData.leaves().filter((d) => d.depth > 0);
+  // Draw the leaf nodes
+  const leafNodes = treemapData.leaves();
   const cell = g
     .selectAll('.treemapLeafGroup')
     .data(leafNodes)
@@ -316,10 +326,6 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
     .attr('height', (d) => d.y1 - d.y0)
     .attr('class', 'treemapLeaf')
     .attr('fill', (d) => {
-      // Make the root rectangle transparent
-      if (d.depth === 0) {
-        return 'transparent';
-      }
       // Leaves inherit color from their immediate parent section's name.
       // If a leaf is the root itself (no parent), it uses its own name.
       return d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name);
@@ -328,18 +334,13 @@ const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
       const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
       return styles.nodeStyles;
     })
-    .attr('fill-opacity', (d) => (d.depth === 0 ? 0 : 0.2))
+    .attr('fill-opacity', 0.3)
     .attr('stroke', (d) => {
-      // Make the root rectangle transparent
-      if (d.depth === 0) {
-        return 'transparent';
-      }
       // Leaves inherit color from their immediate parent section's name.
       // If a leaf is the root itself (no parent), it uses its own name.
       return d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name);
     })
-    .attr('stroke-width', 2.0)
-    .attr('stroke-opacity', (d) => (d.depth === 0 ? 0 : 0.3));
+    .attr('stroke-width', 3.0);
 
   // Add clip paths to prevent text from extending outside nodes
   cell
diff --git a/packages/mermaid/src/docs/syntax/treemap.md b/packages/mermaid/src/docs/syntax/treemap.md
index 2b4a49780..a82825a91 100644
--- a/packages/mermaid/src/docs/syntax/treemap.md
+++ b/packages/mermaid/src/docs/syntax/treemap.md
@@ -25,7 +25,7 @@ Treemap diagrams are particularly useful for:
 ## Syntax
 
 ```
-treemap
+treemap-beta
 "Section 1"
     "Leaf 1.1": 12
     "Section 1.2"
@@ -49,7 +49,7 @@ Nodes in a treemap are defined using the following syntax:
 ### Basic Treemap
 
 ```mermaid-example
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -61,7 +61,7 @@ treemap
 ### Hierarchical Treemap
 
 ```mermaid-example
-treemap
+treemap-beta
 "Products"
     "Electronics"
         "Phones": 50
@@ -75,7 +75,7 @@ treemap
 ### Treemap with Styling
 
 ```mermaid-example
-treemap
+treemap-beta
 "Section 1"
     "Leaf 1.1": 12
     "Section 1.2":::class1
@@ -97,7 +97,7 @@ Treemap diagrams can be customized using Mermaid's styling and configuration opt
 You can define custom styles for nodes using the `classDef` syntax, which is a standard feature across many Mermaid diagram types:
 
 ```mermaid-example
-treemap
+treemap-beta
 "Main"
     "A": 20
     "B":::important
@@ -117,7 +117,7 @@ You can customize the colors of your treemap using the theme configuration:
 config:
     theme: 'forest'
 ---
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -136,7 +136,7 @@ config:
   treemap:
     diagramPadding: 200
 ---
-treemap
+treemap-beta
 "Category A"
     "Item A1": 10
     "Item A2": 20
@@ -188,7 +188,7 @@ config:
   treemap:
     valueFormat: '$0,0'
 ---
-treemap
+treemap-beta
 "Budget"
     "Operations"
         "Salaries": 700000
@@ -207,7 +207,7 @@ config:
   treemap:
     valueFormat: '$.1%'
 ---
-treemap
+treemap-beta
 "Market Share"
     "Company A": 0.35
     "Company B": 0.25
diff --git a/packages/parser/src/language/treemap/treemap.langium b/packages/parser/src/language/treemap/treemap.langium
index 856ea802a..45ee2588f 100644
--- a/packages/parser/src/language/treemap/treemap.langium
+++ b/packages/parser/src/language/treemap/treemap.langium
@@ -7,7 +7,18 @@
  * treemap declaration.
  */
 grammar Treemap
-import "../common/common";
+
+
+
+fragment TitleAndAccessibilities:
+  ((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE))+
+;
+
+terminal BOOLEAN returns boolean: 'true' | 'false';
+
+terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/;
+terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/;
+terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/;
 
 // Interface declarations for data types
 interface Item {
@@ -31,13 +42,12 @@ interface TreemapDoc {
 }
 
 entry TreemapDoc returns TreemapDoc:
-    NEWLINE*
     TREEMAP_KEYWORD
     (
         TitleAndAccessibilities
         | TreemapRows+=TreemapRow
-        | NEWLINE
     )*;
+terminal TREEMAP_KEYWORD:  'treemap-beta' | 'treemap';
 
 terminal CLASS_DEF: /classDef\s+([a-zA-Z_][a-zA-Z0-9_]+)(?:\s+([^;\r\n]*))?(?:;)?/;
 terminal STYLE_SEPARATOR: ':::';
@@ -46,6 +56,7 @@ terminal COMMA: ',';
 
 hidden terminal WS: /[ \t]+/;  // One or more spaces or tabs for hidden whitespace
 hidden terminal ML_COMMENT: /\%\%[^\n]*/;
+hidden terminal NL: /\r?\n/;
 
 TreemapRow:
     indent=INDENTATION? (item=Item | ClassDef);
@@ -59,17 +70,21 @@ Item returns Item:
 
 // Use a special rule order to handle the parsing precedence
 Section returns Section:
-    name=STRING (STYLE_SEPARATOR classSelector=ID)?;
+    name=STRING2 (STYLE_SEPARATOR classSelector=ID2)?;
 
 Leaf returns Leaf:
-    name=STRING INDENTATION? (SEPARATOR | COMMA) INDENTATION? value=MyNumber (STYLE_SEPARATOR classSelector=ID)?;
+    name=STRING2 INDENTATION? (SEPARATOR | COMMA) INDENTATION? value=MyNumber (STYLE_SEPARATOR classSelector=ID2)?;
 
 // This should be processed before whitespace is ignored
 terminal INDENTATION: /[ \t]{1,}/;  // One or more spaces/tabs for indentation
 
 // Keywords with fixed text patterns
-terminal TREEMAP_KEYWORD:  'treemap';
+terminal ID2: /[a-zA-Z_][a-zA-Z0-9_]*/;
+// Define as a terminal rule
+terminal NUMBER2: /[0-9_\.\,]+/;
 
 // Then create a data type rule that uses it
-MyNumber returns number: NUMBER;
+MyNumber returns number: NUMBER2;
+
+terminal STRING2: /"[^"]*"|'[^']*'/;
 // Modified indentation rule to have higher priority than WS
diff --git a/packages/parser/src/language/treemap/valueConverter.ts b/packages/parser/src/language/treemap/valueConverter.ts
index 1f977cac2..653433c50 100644
--- a/packages/parser/src/language/treemap/valueConverter.ts
+++ b/packages/parser/src/language/treemap/valueConverter.ts
@@ -10,13 +10,13 @@ export class TreemapValueConverter extends AbstractMermaidValueConverter {
     input: string,
     _cstNode: CstNode
   ): ValueType | undefined {
-    if (rule.name === 'NUMBER') {
+    if (rule.name === 'NUMBER2') {
       // Convert to a number by removing any commas and converting to float
       return parseFloat(input.replace(/,/g, ''));
     } else if (rule.name === 'SEPARATOR') {
       // Remove quotes
       return input.substring(1, input.length - 1);
-    } else if (rule.name === 'STRING') {
+    } else if (rule.name === 'STRING2') {
       // Remove quotes
       return input.substring(1, input.length - 1);
     } else if (rule.name === 'INDENTATION') {