From 47d4929bc68f996d8a104061e9edc3d7a4bf2adf Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Fri, 17 May 2024 09:30:51 +0200 Subject: [PATCH] #5237 Handling tainted subgraphs --- cypress/platform/knsv2.html | 5 +- packages/mermaid-layout-elk/src/index.ts | 78 ++++++++++++++++-------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 529309bbc..d1926ece0 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -95,9 +95,10 @@ stateDiagram-v2 state Active { direction BT - [*] --> NumLockOff - NumLockOff --> NumLockOn : EvNumLockPressed + [*] --> Inner + Inner --> NumLockOn : EvNumLockPressed } + %% Outer --> Inner
diff --git a/packages/mermaid-layout-elk/src/index.ts b/packages/mermaid-layout-elk/src/index.ts
index 9e3165f4d..25a22c3c1 100644
--- a/packages/mermaid-layout-elk/src/index.ts
+++ b/packages/mermaid-layout-elk/src/index.ts
@@ -451,6 +451,21 @@ function dir2ElkDirection(dir) {
   }
 }
 
+function setIncludeChildrenPolicy(nodeId: string, ancestorId: string) {
+  const node = nodeDb[nodeId];
+
+  if (!node) {
+    return;
+  }
+  if (node?.layoutOptions === undefined) {
+    node.layoutOptions = {};
+  }
+  node.layoutOptions['elk.hierarchyHandling'] = 'INCLUDE_CHILDREN';
+  if (node.id !== ancestorId) {
+    setIncludeChildrenPolicy(node.parentId, ancestorId);
+  }
+}
+
 export const render = async (data4Layout, svg, element) => {
   const elk = new ELK();
 
@@ -461,7 +476,7 @@ export const render = async (data4Layout, svg, element) => {
   let elkGraph = {
     id: 'root',
     layoutOptions: {
-      // 'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
+      'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
       'org.eclipse.elk.padding': '[top=100, left=100, bottom=110, right=110]',
       'elk.layered.spacing.edgeNodeBetweenLayers': '30',
     },
@@ -516,6 +531,7 @@ export const render = async (data4Layout, svg, element) => {
       if (node.dir) {
         node.layoutOptions = {
           'elk.direction': dir2ElkDirection(node.dir),
+          'elk.hierarchyHandling': 'SEPARATE_CHILDREN',
         };
       }
       delete node.x;
@@ -524,6 +540,17 @@ export const render = async (data4Layout, svg, element) => {
       delete node.height;
     }
   });
+  elkGraph.edges.forEach((edge) => {
+    const source = edge.sources[0];
+    const target = edge.targets[0];
+
+    if (nodeDb[source].parentId !== nodeDb[target].parentId) {
+      const ancestorId = findCommonAncestor(source, target, parentLookupDb);
+      // an edge that breaks a subgraph has been identified, set configuration accordingly
+      setIncludeChildrenPolicy(source, ancestorId);
+      setIncludeChildrenPolicy(target, ancestorId);
+    }
+  });
 
   log.info('before layout', JSON.stringify(elkGraph, null, 2));
   const g = await elk.layout(elkGraph);
@@ -540,32 +567,31 @@ export const render = async (data4Layout, svg, element) => {
 
     const offset = calcOffset(sourceId, targetId, parentLookupDb);
 
-    const src = edge.sections[0].startPoint;
-    const dest = edge.sections[0].endPoint;
-    const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : [];
+    if (edge.sections) {
+      const src = edge.sections[0].startPoint;
+      const dest = edge.sections[0].endPoint;
+      const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : [];
 
-    const segPoints = segments.map((segment) => {
-      return { x: segment.x + offset.x, y: segment.y + offset.y };
-    });
-    edge.points = [
-      { x: src.x + offset.x, y: src.y + offset.y },
-      ...segPoints,
-      { x: dest.x + offset.x, y: dest.y + offset.y },
-    ];
-    console.log(
-      'DAGA org points: ',
-      [
-        { x: src.x, y: src.y },
-        { x: dest.x, y: dest.y },
-      ],
-      'points: ',
-      edge.points
-    );
+      const segPoints = segments.map((segment) => {
+        return { x: segment.x + offset.x, y: segment.y + offset.y };
+      });
+      edge.points = [
+        { x: src.x + offset.x, y: src.y + offset.y },
+        ...segPoints,
+        { x: dest.x + offset.x, y: dest.y + offset.y },
+      ];
+      const paths = insertEdge(
+        edgesEl,
+        edge,
+        clusterDb,
+        data4Layout.type,
+        g,
+        data4Layout.diagramId
+      );
 
-    const paths = insertEdge(edgesEl, edge, clusterDb, data4Layout.type, g, data4Layout.diagramId);
-
-    edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
-    edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
-    positionEdgeLabel(edge, paths);
+      edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
+      edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
+      positionEdgeLabel(edge, paths);
+    }
   });
 };