mirror of
https://github.com/mermaid-js/mermaid.git
synced 2026-05-23 20:10:38 +00:00
fix: remove dead dagre patch and fix explicitDir false-positive with inheritDir
Agent-Logs-Url: https://github.com/sjackson0109/mermaid/sessions/6e0b59e7-9b3a-4532-bdc3-7d7893b2c0da Co-authored-by: sjackson0109 <38080190+sjackson0109@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
fc6ce97dd7
commit
c9ce128d39
+1
-2
@@ -147,8 +147,7 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"roughjs": "patches/roughjs.patch",
|
||||
"dagre-d3-es@7.0.14": "patches/dagre-d3-es@7.0.14.patch"
|
||||
"roughjs": "patches/roughjs.patch"
|
||||
},
|
||||
"onlyBuiltDependencies": [
|
||||
"canvas",
|
||||
|
||||
@@ -700,6 +700,10 @@ You have to call mermaid.initialize.`
|
||||
const result = uniq(list.flat());
|
||||
const nodeList = result.nodeList;
|
||||
let dir = result.dir;
|
||||
// Capture whether the user explicitly wrote a direction keyword BEFORE any
|
||||
// TD→TB normalisation or inheritDir override, so that explicitDir is true
|
||||
// only for user-authored direction statements.
|
||||
const hasExplicitDir = dir !== undefined;
|
||||
// Normalize TD ("top-down" alias) to the canonical TB ("top-bottom") that dagre expects,
|
||||
// mirroring the same normalisation in setDirection() for the top-level graph direction.
|
||||
if (dir === 'TD') {
|
||||
@@ -729,6 +733,7 @@ You have to call mermaid.initialize.`
|
||||
title: title.trim(),
|
||||
classes: [],
|
||||
dir,
|
||||
hasExplicitDir,
|
||||
labelType: this.sanitizeNodeLabelType(_title?.type),
|
||||
};
|
||||
|
||||
@@ -1123,7 +1128,7 @@ You have to call mermaid.initialize.`
|
||||
cssClasses: subGraph.classes.join(' '),
|
||||
shape: 'rect',
|
||||
dir: subGraph.dir,
|
||||
explicitDir: !!subGraph.dir, // true only when the user wrote an explicit 'direction X' keyword
|
||||
explicitDir: subGraph.hasExplicitDir, // true only when the user wrote an explicit 'direction X' keyword
|
||||
isGroup: true,
|
||||
look: config.look,
|
||||
});
|
||||
|
||||
@@ -78,6 +78,7 @@ export interface FlowClass {
|
||||
export interface FlowSubGraph {
|
||||
classes: string[];
|
||||
dir?: string;
|
||||
hasExplicitDir: boolean;
|
||||
id: string;
|
||||
labelType: string;
|
||||
nodes: string[];
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
diff --git a/src/dagre/layout.js b/src/dagre/layout.js
|
||||
index ee10670c600a9ac6ac6ebfa575c84a3c7e3a7621..0283ef7424ece094ffd231179537b37902b1600a 100644
|
||||
--- a/src/dagre/layout.js
|
||||
+++ b/src/dagre/layout.js
|
||||
@@ -18,6 +18,8 @@ function layout(g, opts) {
|
||||
time('layout', () => {
|
||||
var layoutGraph = time(' buildLayoutGraph', () => buildLayoutGraph(g));
|
||||
time(' runLayout', () => runLayout(layoutGraph, time));
|
||||
+ // After main layout, re-layout any clusters with their own rankdir
|
||||
+ time(' applyClusterDirections', () => applyClusterDirections(layoutGraph, time));
|
||||
time(' updateInputGraph', () => updateInputGraph(g, layoutGraph));
|
||||
});
|
||||
}
|
||||
@@ -121,7 +123,12 @@ function buildLayoutGraph(inputGraph) {
|
||||
|
||||
_.forEach(inputGraph.nodes(), function (v) {
|
||||
var node = canonicalize(inputGraph.node(v));
|
||||
- g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
|
||||
+ var nodeAttrs = _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults);
|
||||
+ // Preserve per-cluster rankdir so applyClusterDirections can use it
|
||||
+ if (node.rankdir) {
|
||||
+ nodeAttrs.rankdir = node.rankdir;
|
||||
+ }
|
||||
+ g.setNode(v, nodeAttrs);
|
||||
g.setParent(v, inputGraph.parent(v));
|
||||
});
|
||||
|
||||
@@ -393,6 +400,115 @@ function positionSelfEdges(g) {
|
||||
});
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Returns all descendant node IDs of a given cluster node (all depths).
|
||||
+ */
|
||||
+function getAllDescendants(g, v) {
|
||||
+ var result = [];
|
||||
+ function collect(node) {
|
||||
+ g.children(node).forEach(function (child) {
|
||||
+ result.push(child);
|
||||
+ if (g.children(child).length) {
|
||||
+ collect(child);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ collect(v);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * After the main layout has assigned positions to all nodes, re-layout any
|
||||
+ * clusters (compound nodes) that carry a `rankdir` different from the
|
||||
+ * top-level graph. Each such cluster's descendants are laid out in a fresh
|
||||
+ * sub-graph with the cluster's own direction, then the resulting positions are
|
||||
+ * translated so the sub-layout is centred at the cluster's main-graph position.
|
||||
+ */
|
||||
+function applyClusterDirections(g, time) {
|
||||
+ var graphRankdir = ((g.graph().rankdir) || 'TB').toUpperCase();
|
||||
+
|
||||
+ g.nodes().forEach(function (v) {
|
||||
+ if (!g.children(v).length) return;
|
||||
+ var node = g.node(v);
|
||||
+ if (!node || !node.rankdir) return;
|
||||
+ var clusterRankdir = node.rankdir.toUpperCase();
|
||||
+ if (clusterRankdir === graphRankdir) return;
|
||||
+
|
||||
+ var descendants = getAllDescendants(g, v);
|
||||
+ if (!descendants.length) return;
|
||||
+
|
||||
+ // Build a fresh sub-graph — avoid filterNodes which mutates nesting state
|
||||
+ var subGraph = new Graph({ multigraph: true, compound: true });
|
||||
+ subGraph.setGraph({
|
||||
+ rankdir: node.rankdir,
|
||||
+ ranksep: g.graph().ranksep != null ? g.graph().ranksep : 50,
|
||||
+ edgesep: g.graph().edgesep != null ? g.graph().edgesep : 20,
|
||||
+ nodesep: g.graph().nodesep != null ? g.graph().nodesep : 50,
|
||||
+ });
|
||||
+ subGraph.setDefaultEdgeLabel(function () { return {}; });
|
||||
+
|
||||
+ descendants.forEach(function (u) {
|
||||
+ var nl = g.node(u);
|
||||
+ subGraph.setNode(u, { width: (nl && nl.width != null) ? nl.width : 50,
|
||||
+ height: (nl && nl.height != null) ? nl.height : 50 });
|
||||
+ var parent = g.parent(u);
|
||||
+ if (parent && parent !== v && descendants.indexOf(parent) !== -1) {
|
||||
+ subGraph.setParent(u, parent);
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ g.edges().forEach(function (e) {
|
||||
+ if (descendants.indexOf(e.v) !== -1 && descendants.indexOf(e.w) !== -1) {
|
||||
+ var el = g.edge(e);
|
||||
+ subGraph.setEdge(e.v, e.w, {
|
||||
+ weight: (el && el.weight != null) ? el.weight : 1,
|
||||
+ minlen: (el && el.minlen != null) ? el.minlen : 1,
|
||||
+ width: (el && el.width != null) ? el.width : 0,
|
||||
+ height: (el && el.height != null) ? el.height : 0,
|
||||
+ labeloffset: (el && el.labeloffset != null) ? el.labeloffset : 10,
|
||||
+ labelpos: (el && el.labelpos) ? el.labelpos : 'r',
|
||||
+ });
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ // Layout the sub-graph with the cluster's own direction
|
||||
+ runLayout(subGraph, time);
|
||||
+
|
||||
+ // Compute the sub-graph bounding box
|
||||
+ var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
+ descendants.forEach(function (u) {
|
||||
+ var n = subGraph.node(u);
|
||||
+ if (n && n.x != null && n.y != null) {
|
||||
+ var hw = (n.width || 0) / 2;
|
||||
+ var hh = (n.height || 0) / 2;
|
||||
+ minX = Math.min(minX, n.x - hw);
|
||||
+ minY = Math.min(minY, n.y - hh);
|
||||
+ maxX = Math.max(maxX, n.x + hw);
|
||||
+ maxY = Math.max(maxY, n.y + hh);
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ // Translate sub-layout to be centred at the cluster's main-graph position
|
||||
+ var clusterNode = g.node(v);
|
||||
+ if (!clusterNode) return;
|
||||
+ var offsetX = (clusterNode.x || 0) - (maxX + minX) / 2;
|
||||
+ var offsetY = (clusterNode.y || 0) - (maxY + minY) / 2;
|
||||
+
|
||||
+ descendants.forEach(function (u) {
|
||||
+ var subNode = subGraph.node(u);
|
||||
+ var mainNode = g.node(u);
|
||||
+ if (mainNode && subNode && subNode.x != null && subNode.y != null) {
|
||||
+ mainNode.x = subNode.x + offsetX;
|
||||
+ mainNode.y = subNode.y + offsetY;
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ // Update cluster bounding box to match sub-layout
|
||||
+ clusterNode.width = Math.max(clusterNode.width || 0, maxX - minX);
|
||||
+ clusterNode.height = Math.max(clusterNode.height || 0, maxY - minY);
|
||||
+ });
|
||||
+}
|
||||
+
|
||||
function selectNumberAttrs(obj, attrs) {
|
||||
return _.mapValues(_.pick(obj, attrs), Number);
|
||||
}
|
||||
Generated
+2
-5
@@ -5,9 +5,6 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
patchedDependencies:
|
||||
dagre-d3-es@7.0.14:
|
||||
hash: 9da670a68ec3d17e16b620a8bf8f9ea88df6e8122e728e68caec8eb0cdd9b9d0
|
||||
path: patches/dagre-d3-es@7.0.14.patch
|
||||
roughjs:
|
||||
hash: 3543d47108cb41b68ec6a671c0e1f9d0cfe2ce524fea5b0992511ae84c3c6b64
|
||||
path: patches/roughjs.patch
|
||||
@@ -267,7 +264,7 @@ importers:
|
||||
version: 0.12.3
|
||||
dagre-d3-es:
|
||||
specifier: 7.0.14
|
||||
version: 7.0.14(patch_hash=9da670a68ec3d17e16b620a8bf8f9ea88df6e8122e728e68caec8eb0cdd9b9d0)
|
||||
version: 7.0.14
|
||||
dayjs:
|
||||
specifier: ^1.11.19
|
||||
version: 1.11.19
|
||||
@@ -15687,7 +15684,7 @@ snapshots:
|
||||
d3-transition: 3.0.1(d3-selection@3.0.0)
|
||||
d3-zoom: 3.0.0
|
||||
|
||||
dagre-d3-es@7.0.14(patch_hash=9da670a68ec3d17e16b620a8bf8f9ea88df6e8122e728e68caec8eb0cdd9b9d0):
|
||||
dagre-d3-es@7.0.14:
|
||||
dependencies:
|
||||
d3: 7.9.0
|
||||
lodash-es: 4.18.1
|
||||
|
||||
Reference in New Issue
Block a user