From c6acf84e43782152ddec38166091b6e687c6077a Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Tue, 20 Aug 2024 13:35:40 +0200 Subject: [PATCH] Mermaid version 11.0.0-b.74, handling of default positions in subgraphs for fixed layout --- cypress/platform/knsv-pos.html | 9 ++- packages/mermaid/package.json | 2 +- .../layout-algorithms/fixed/index.js | 75 ++++++++++++++----- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/cypress/platform/knsv-pos.html b/cypress/platform/knsv-pos.html index e3789f8c0..e45fdb65b 100644 --- a/cypress/platform/knsv-pos.html +++ b/cypress/platform/knsv-pos.html @@ -122,7 +122,14 @@ `; code = ` stateDiagram - A --> B: Hello + A0 + state subbe { + subState + B + } + C + D + E `; let positions = { diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index d45db409c..66fc11dd7 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -1,6 +1,6 @@ { "name": "@mermaid-chart/mermaid", - "version": "11.0.0-b.73", + "version": "11.0.0-b.74", "description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "type": "module", "module": "./dist/mermaid.core.mjs", diff --git a/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js b/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js index 3b8de448d..da98d6bd3 100644 --- a/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js +++ b/packages/mermaid/src/rendering-util/layout-algorithms/fixed/index.js @@ -83,7 +83,17 @@ const doRender = async (_elem, data4Layout, siteConfig, positions) => { positions.edges = {}; } } - // Add positions for nodes that lack them + // Extract children info + const childDB = new Map(); + data4Layout.nodes.map(function (node) { + if (node.parentId) { + const children = childDB.get(node.parentId) || []; + children.push(node); + childDB.set(node.parentId, children); + } + }); + + // calculate next available position let maxY = 0; data4Layout.nodes.map(function (node) { const pos = positions.nodes[node.id]; @@ -99,17 +109,49 @@ const doRender = async (_elem, data4Layout, siteConfig, positions) => { } }); - let cnt = 0; - data4Layout.nodes.map(function (node) { - let pos; - if (!positions.nodes[node.id]) { - positions.nodes[node.id] = { x: cnt * 75, y: maxY + 20 }; - cnt = cnt + 1; + // Add positions for nodes that lack them + let xPos = 0; + function calculatePosition(node, positions, childDB) { + const children = childDB.get(node.id) || []; + // log.info('STO calculatePosition', node.id, children.length); + // We have a subgraph without position + if (children.length > 0) { + let minX = 10000; + let maxX = -10000; + let minYP = 10000; + let maxYP = -10000; + for (const child of children) { + const width = child.width || 50; + const height = child.height || 50; + // log.info('STO node child 1', child.id, width, height); + calculatePosition(child, positions, childDB); + // log.info( + // 'STO node child 2', + // child.id, + // positions.nodes[child.id].x, + // positions.nodes[child.id].y + // ); + minX = Math.min(positions.nodes[child.id].x - width / 2, minX); + maxX = Math.max(positions.nodes[child.id].x + width / 2, maxX); + minYP = Math.min(positions.nodes[child.id].y - height / 2, minYP); + maxYP = Math.max(positions.nodes[child.id].y + height / 2, maxYP); + } + positions.nodes[node.id] = { + x: minX + (maxX - minX) / 2 - 5, + y: maxY + 15, + width: maxX - minX + 20, + height: maxYP - minYP + 30, + }; + } else { + // Simple case + positions.nodes[node.id] = { x: xPos, y: maxY + 20 }; + xPos = xPos + 75; + } + } + data4Layout.nodes.map(function (node) { + if (!node.parentId) { + calculatePosition(node, positions, childDB); } - // if (node.x === undefined || node.y === undefined) { - pos = positions.nodes[node.id] || { x: 0, y: 0, width: 100, height: 100 }; - node.height = pos?.height || 50; - node.width = pos?.width || 50; }); // Insert nodes, this will insert them into the dom and each node will get a size. The size is updated @@ -117,16 +159,11 @@ const doRender = async (_elem, data4Layout, siteConfig, positions) => { nodeDB = new Map(); await Promise.all( - data4Layout.nodes.map(async function (node, i) { - let pos; - if (!positions.nodes[node.id]) { - positions.nodes[node.id] = { x: i * 100, y: maxY + 10, width: 50, height: 50 }; - } - // if (node.x === undefined || node.y === undefined) { - pos = positions.nodes[node.id] || { x: 0, y: 0, width: 100, height: 100 }; + data4Layout.nodes.map(async function (node) { + let pos = positions.nodes[node.id]; node.height = pos?.height || 50; node.width = pos?.width || 50; - // } + if (node.isGroup) { node.x = 0; node.y = 0;