From 1a56a18f9b0f8ec4bc95fa6cd4ac41e404bf1d98 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Tue, 4 Apr 2023 12:49:14 +0200 Subject: [PATCH] Fixing issues with centering of labels for subgraphs and handling of special characters in html strings --- cypress/platform/knsv2.html | 108 +++++++++++++++--- .../mermaid/src/dagre-wrapper/clusters.js | 19 ++- .../mermaid/src/dagre-wrapper/shapes/note.js | 2 +- .../flowchart/elk/flowRenderer-elk.js | 5 +- .../mermaid/src/rendering-util/createText.js | 34 +++--- .../rendering-util/handle-markdown-text.js | 2 + 6 files changed, 127 insertions(+), 43 deletions(-) diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 936d8423f..5eaadffc4 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -57,6 +57,25 @@ +
+flowchart RL
+    subgraph "`one`"
+      a1 -- l1 --> a2
+      a1 -- l2 --> a2
+    end
+    
+
+      %%{init: {"flowchart": {"htmlLabels":false}} }%%
+flowchart RL
+    subgraph "`one`"
+      a1 -- l1 --> a2
+      a1 -- l2 --> a2
+    end
+    
+
+flowchart
+id["`A root with a long text that wraps to keep the node size in check. A root with a long text that wraps to keep the node size in check`"]
 flowchart LR
     A[A text that needs to be wrapped wraps to another line]
@@ -71,13 +90,18 @@ flowchart LR
         way`"]
   
-
+    
+      classDiagram-v2
+        note "I love this diagram!\nDo you love it?"
+
+
 mindmap
 root
   Child3(A node with an icon and with a long text that wraps to keep the node size in check)
 
-
+    
       %%{init: {"theme": "forest"} }%%
 mindmap
     id1[**Start2**
end] @@ -88,16 +112,16 @@ mindmap
 mindmap
-    id1[`**Start2**
-    second line 😎 with long text that is wrapping to the next line`]
-      id2[`Child **with bold** text`]
-      id3[`Children of which some
-      is using *italic type of* text`]
+    id1["`**Start2**
+    second line 😎 with long text that is wrapping to the next line`"]
+      id2["`Child **with bold** text`"]
+      id3["`Children of which some
+      is using *italic type of* text`"]
       id4[Child]
-      id5[`Child
+      id5["`Child
       Row
       and another
-      `]
+      `"]
     
 mindmap
@@ -108,7 +132,7 @@ mindmap
       शान्तिः سلام  和平 `"]
 
     
-
+    
 %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
 flowchart TB
   %% I could not figure out how to use double quotes in labels in Mermaid
@@ -124,7 +148,7 @@ flowchart TB
     rom --> core2
   end
 
-  subgraph amd[AMD Latte GPU]
+  subgraph amd["`**AMD** Latte GPU`"]
     mem[Memory & I/O Bridge]
     dram[DRAM Controller]
     edram[32 MB EDRAM MEM1]
@@ -163,8 +187,64 @@ flowchart TB
   rtc{{rtc}}
 
+
+%%{init: {"flowchart": {"defaultRenderer": "elk", "htmlLabels": false}} }%%
+flowchart TB
+  %% I could not figure out how to use double quotes in labels in Mermaid
+  subgraph ibm[IBM Espresso CPU]
+    core0[IBM PowerPC Broadway Core 0]
+    core1[IBM PowerPC Broadway Core 1]
+    core2[IBM PowerPC Broadway Core 2]
+
+    rom[16 KB ROM]
+
+    core0 --- core2
+
+    rom --> core2
+  end
+
+  subgraph amd["`**AMD** Latte GPU`"]
+    mem[Memory & I/O Bridge]
+    dram[DRAM Controller]
+    edram[32 MB EDRAM MEM1]
+    rom[512 B SEEPROM]
+
+    sata[SATA IF]
+    exi[EXI]
+
+    subgraph gx[GX]
+      sram[3 MB 1T-SRAM]
+    end
+
+    radeon[AMD Radeon R7xx GX2]
+
+    mem --- gx
+    mem --- radeon
+
+    rom --- mem
+
+    mem --- sata
+    mem --- exi
+
+    dram --- sata
+    dram --- exi
+  end
+
+  ddr3[2 GB DDR3 RAM MEM2]
+
+  mem --- ddr3
+  dram --- ddr3
+  edram --- ddr3
+
+  core1 --- mem
+
+  exi --- rtc
+  rtc{{rtc}}
+
+
-
+    
 flowchart TB
   %% I could not figure out how to use double quotes in labels in Mermaid
   subgraph ibm[IBM Espresso CPU]
@@ -220,7 +300,7 @@ flowchart TB
     >
     
  -
+    
       flowchart LR
   B1 --be be--x B2
   B1 --bo bo--o B3
@@ -311,7 +391,7 @@ mindmap
         flowchart: {
           // defaultRenderer: 'elk',
           useMaxWidth: false,
-          htmlLabels: false,
+          htmlLabels: true,
           // htmlLabels: true,
         },
         // htmlLabels: true,
diff --git a/packages/mermaid/src/dagre-wrapper/clusters.js b/packages/mermaid/src/dagre-wrapper/clusters.js
index 453fcb8f5..2b87b91a6 100644
--- a/packages/mermaid/src/dagre-wrapper/clusters.js
+++ b/packages/mermaid/src/dagre-wrapper/clusters.js
@@ -63,13 +63,20 @@ const rect = (parent, node) => {
     .attr('width', width)
     .attr('height', node.height + padding);
 
+  if (useHtmlLabels) {
+    label.attr(
+      'transform',
+      // This puts the labal on top of the box instead of inside it
+      'translate(' + (node.x - bbox.width / 2) + ', ' + (node.y - node.height / 2) + ')'
+    );
+  } else {
+    label.attr(
+      'transform',
+      // This puts the labal on top of the box instead of inside it
+      'translate(' + node.x + ', ' + (node.y - node.height / 2) + ')'
+    );
+  }
   // Center the label
-  label.attr(
-    'transform',
-    // This puts the labal on top of the box instead of inside it
-    // 'translate(' + (node.x - bbox.width / 2) + ', ' + (node.y - node.height / 2 - bbox.height) + ')'
-    'translate(' + node.x + ', ' + (node.y - node.height / 2) + ')'
-  );
 
   const rectBox = rect.node().getBBox();
   node.width = rectBox.width;
diff --git a/packages/mermaid/src/dagre-wrapper/shapes/note.js b/packages/mermaid/src/dagre-wrapper/shapes/note.js
index 6b693fdf6..c7ebb6c22 100644
--- a/packages/mermaid/src/dagre-wrapper/shapes/note.js
+++ b/packages/mermaid/src/dagre-wrapper/shapes/note.js
@@ -12,7 +12,7 @@ const note = (parent, node) => {
   rect
     .attr('rx', node.rx)
     .attr('ry', node.ry)
-    .attr('x', -bbox.width / 2 - halfPadding)
+    .attr('x', -halfPadding)
     .attr('y', -bbox.height / 2 - halfPadding)
     .attr('width', bbox.width + node.padding)
     .attr('height', bbox.height + node.padding);
diff --git a/packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js b/packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js
index 5849177b9..4748807d1 100644
--- a/packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js
+++ b/packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js
@@ -934,9 +934,12 @@ const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj, depth) => {
           .attr('width', node.width)
           .attr('height', node.height);
         const label = subgraphEl.insert('g').attr('class', 'label');
+        const labelCentering = getConfig().flowchart.htmlLabels ? node.labelData.width / 2 : 0;
         label.attr(
           'transform',
-          `translate(${node.labels[0].x + relX + node.x}, ${node.labels[0].y + relY + node.y})`
+          `translate(${node.labels[0].x + relX + node.x + labelCentering}, ${
+            node.labels[0].y + relY + node.y + 3
+          })`
         );
         label.node().appendChild(node.labelData.labelNode);
 
diff --git a/packages/mermaid/src/rendering-util/createText.js b/packages/mermaid/src/rendering-util/createText.js
index 1097cd0df..f20736f3a 100644
--- a/packages/mermaid/src/rendering-util/createText.js
+++ b/packages/mermaid/src/rendering-util/createText.js
@@ -152,26 +152,8 @@ function updateTextContentAndStyles(tspan, wrappedLine) {
       .attr('font-style', word.type === 'em' ? 'italic' : 'normal')
       .attr('class', 'text-inner-tspan')
       .attr('font-weight', word.type === 'strong' ? 'bold' : 'normal');
-    const special = [
-      '<',
-      '>',
-      '&',
-      '"',
-      "'",
-      '.',
-      ',',
-      ':',
-      ';',
-      '!',
-      '?',
-      '(',
-      ')',
-      '[',
-      ']',
-      '{',
-      '}',
-    ];
-    if (index !== 0 && special.includes(word.content)) {
+    const special = ['"', "'", '.', ',', ':', ';', '!', '?', '(', ')', '[', ']', '{', '}'];
+    if (index === 0) {
       innerTspan.text(word.content);
     } else {
       innerTspan.text(' ' + word.content);
@@ -225,7 +207,17 @@ export const createText = (
     return vertexNode;
   } else {
     const structuredText = markdownToLines(text);
-
+    const special = ['"', "'", '.', ',', ':', ';', '!', '?', '(', ')', '[', ']', '{', '}'];
+    let lastWord;
+    structuredText.forEach((line) => {
+      line.forEach((word) => {
+        if (special.includes(word.content) && lastWord) {
+          lastWord.content += word.content;
+          word.content = '';
+        }
+        lastWord = word;
+      });
+    });
     const svgLabel = createFormattedText(width, el, structuredText, addSvgBackground);
     return svgLabel;
   }
diff --git a/packages/mermaid/src/rendering-util/handle-markdown-text.js b/packages/mermaid/src/rendering-util/handle-markdown-text.js
index cd79623fe..93704b2fe 100644
--- a/packages/mermaid/src/rendering-util/handle-markdown-text.js
+++ b/packages/mermaid/src/rendering-util/handle-markdown-text.js
@@ -38,6 +38,8 @@ export function markdownToLines(markdown) {
           currentLine++;
           lines.push([]);
         }
+
+        // textLine.split(/ (?=[^!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]+)/).forEach((word) => {
         textLine.split(' ').forEach((word) => {
           if (word) {
             lines[currentLine].push({ content: word, type: parentType || 'normal' });