From 1b29135cc1cc2ac1a27848f514f3bca6d391cdc6 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Fri, 7 Jun 2024 20:23:44 +0200 Subject: [PATCH] #5237 Enabling subgraphs using the unified renderer for flowcharts --- cypress/platform/knsv2.html | 18 +++--- .../mermaid/src/diagrams/flowchart/flowDb.ts | 24 +++++++- .../dagre/mermaid-graphlib.js | 4 +- .../rendering-elements/clusters.js | 60 ++++++++++++++----- 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 99836dd1c..514f98409 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -84,13 +84,17 @@ stateDiagram-v2 if_state --> True : if n >= 0 -
+    
 flowchart LR
-    A[Start] --> B{Is it?} --> B1 & B2
+    subgraph Apa
+      A[Start] --> B
+    end
+    Apa --> C
+    A --> C
 
       
-
+    
       %%{init: {"layout": "dagre", "mergeEdges": false} }%%
 flowchart LR
       A ==> B(This is B)
@@ -213,12 +217,12 @@ stateDiagram-v2
       mermaid.initialize({
         // theme: 'base',
         // handdrawnSeed: 12,
-        // look: 'handdrawn',
-        'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
-        layout: 'dagre',
+        look: 'handdrawn',
+        // 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
+        // layout: 'dagre',
         // layout: 'elk',
         // layout: 'fixed',
-        htmlLabels: false,
+        // htmlLabels: false,
         flowchart: { titleTopMargin: 10 },
         // fontFamily: 'Caveat',
         fontFamily: 'Kalam',
diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
index bb4f4ecf2..b3976adf5 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts
+++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
@@ -775,20 +775,39 @@ export const getData = () => {
   // extract(getRootDocV2());
   // const diagramStates = getStates();
   const useRough = config.look === 'handdrawn';
+  const subGraphs = getSubGraphs();
+  log.info('Subgraphs - ', subGraphs);
+  const parentDB = new Map();
+  const subGraphDB = new Map();
+
+  for (let i = subGraphs.length - 1; i >= 0; i--) {
+    const subGraph = subGraphs[i];
+    if (subGraph.nodes.length > 0) {
+      subGraphDB.set(subGraph.id, true);
+    }
+    subGraph.nodes.forEach((id) => {
+      parentDB.set(id, subGraph.id);
+    });
+  }
+
   const n = getVertices();
   n.forEach((vertex) => {
+    let parentId = parentDB.get(vertex.id);
+    let isGroup = subGraphDB.get(vertex.id) || false;
+
     const node: Node = {
       id: vertex.id,
       label: vertex.text,
       labelStyle: '',
+      parentId,
       padding: config.flowchart?.padding || 8,
       cssStyles: vertex.styles.join(' '),
       cssClasses: vertex.classes.join(' '),
       shape: getTypeFromVertex(vertex),
       dir: vertex.dir,
       domId: vertex.domId,
-      type: undefined,
-      isGroup: false,
+      type: isGroup ? 'group' : undefined,
+      isGroup,
       useRough,
     };
     nodes.push(node);
@@ -823,7 +842,6 @@ export const getData = () => {
     // console.log('rawEdge SPLIT', rawEdge, index);
     edges.push(edge);
   });
-  console.log('edges SPLIT', edges);
 
   //const useRough = config.look === 'handdrawn';
 
diff --git a/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js b/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
index f56cba285..73b6797df 100644
--- a/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
+++ b/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
@@ -159,10 +159,8 @@ export const validate = (graph) => {
  * @param {any} graph
  */
 export const findNonClusterChild = (id, graph) => {
-  // const node = graph.node(id);
   log.trace('Searching', id);
-  // const children = graph.children(id).reverse();
-  const children = graph.children(id); //.reverse();
+  const children = graph.children(id).reverse();
   log.trace('Searching children of id ', id, children);
   if (children.length < 1) {
     log.trace('This is a valid node', id);
diff --git a/packages/mermaid/src/rendering-util/rendering-elements/clusters.js b/packages/mermaid/src/rendering-util/rendering-elements/clusters.js
index a4b8f896d..2a197993a 100644
--- a/packages/mermaid/src/rendering-util/rendering-elements/clusters.js
+++ b/packages/mermaid/src/rendering-util/rendering-elements/clusters.js
@@ -8,17 +8,18 @@ import { createText } from '../createText.ts';
 import intersectRect from '../rendering-elements/intersect/intersect-rect.js';
 import createLabel from './createLabel.js';
 import { createRoundedRectPathD } from './shapes/roundedRectPath.ts';
+import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
 
 const rect = (parent, node) => {
   log.info('Creating subgraph rect for ', node.id, node);
   const siteConfig = getConfig();
+  const { themeVariables, handdrawnSeed } = siteConfig;
+  const { clusterBkg, clusterBorder } = themeVariables;
+  let { useRough } = node;
 
   // Add outer g element
   const shapeSvg = parent.insert('g').attr('class', 'cluster').attr('id', node.id);
 
-  // add the rect
-  const rect = shapeSvg.insert('rect', ':first-child');
-
   const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
 
   // Create the label and insert it after the rect
@@ -44,7 +45,6 @@ const rect = (parent, node) => {
   }
 
   const padding = 0 * node.padding;
-  const halfPadding = padding / 2;
 
   const width = node.width <= bbox.width + padding ? bbox.width + padding : node.width;
   if (node.width <= bbox.width + padding) {
@@ -53,17 +53,45 @@ const rect = (parent, node) => {
     node.diff = -node.padding / 2;
   }
 
-  log.trace('Data ', node, JSON.stringify(node));
-  // center the rect around its coordinate
-  rect
-    .attr('style', node.cssStyles)
-    .attr('rx', node.rx)
-    .attr('ry', node.ry)
-    .attr('x', node.x - width / 2)
-    .attr('y', node.y - node.height / 2 - halfPadding)
-    .attr('width', width)
-    .attr('height', node.height + padding);
+  const totalWidth = width + padding;
+  const totalHeight = node.height + padding;
+  const x = node.x - totalWidth / 2;
+  const y = node.y - totalHeight / 2;
 
+  log.trace('Data ', node, JSON.stringify(node));
+  let rect;
+  if (useRough) {
+    // @ts-ignore TODO: Fix rough typings
+    const rc = rough.svg(shapeSvg);
+    const options = userNodeOverrides(node, {
+      roughness: 0.7,
+      fill: clusterBkg,
+      // fill: 'red',
+      stroke: clusterBorder,
+      fillWeight: 3,
+      seed: handdrawnSeed,
+      stroke: clusterBorder,
+    });
+    const roughNode = rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, 0), options);
+    // console.log('Rough node insert CXC', roughNode);
+
+    rect = shapeSvg.insert(() => {
+      console.log('Rough node insert CXC', roughNode);
+      return roughNode;
+    }, ':first-child');
+  } else {
+    // add the rect
+    rect = shapeSvg.insert('rect', ':first-child');
+    // center the rect around its coordinate
+    rect
+      .attr('style', node.cssStyles)
+      .attr('rx', node.rx)
+      .attr('ry', node.ry)
+      .attr('x', x)
+      .attr('y', y)
+      .attr('width', totalWidth)
+      .attr('height', totalHeight);
+  }
   const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
   if (useHtmlLabels) {
     labelEl.attr(
@@ -303,8 +331,8 @@ const divider = (parent, node) => {
 
   return { cluster: shapeSvg, labelBBox: { width: 0, height: 0 } };
 };
-
-const shapes = { rect, roundedWithTitle, noteGroup, divider };
+const squareRect = rect;
+const shapes = { rect, squareRect, roundedWithTitle, noteGroup, divider };
 
 let clusterElems = {};