mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 14:29:25 +02:00
#5237 Fix for edges in when using elk and subgraphs regarding offset and direction of marker in some edge cases
This commit is contained in:
@@ -75,22 +75,28 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid">
|
||||||
stateDiagram-v2
|
stateDiagram
|
||||||
state if_state <<choice>>
|
direction LR
|
||||||
[*] --> IsPositive
|
state Gorilla0 {
|
||||||
IsPositive --> if_state
|
state Apa0 {
|
||||||
if_state --> False: if n < 0
|
A0 --> B0
|
||||||
if_state --> True : if n >= 0
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Apa0 --> C0
|
||||||
|
A0 --> C0
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph Apa
|
subgraph Gorilla
|
||||||
A[Start] --> B
|
subgraph Apa
|
||||||
|
A[A] --- B
|
||||||
|
end
|
||||||
end
|
end
|
||||||
Apa --> C
|
Apa --- C
|
||||||
A --> C
|
A --x C
|
||||||
|
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
@@ -117,7 +123,7 @@ flowchart LR
|
|||||||
if_state --> True : if n >= 0
|
if_state --> True : if n >= 0
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid3">
|
||||||
%%{init: {"layout": "elk", "mergeEdges": false, "elk.nodePlacement.strategy": "SIMPLE"} }%%
|
%%{init: {"layout": "elk", "mergeEdges": false, "elk.nodePlacement.strategy": "SIMPLE"} }%%
|
||||||
stateDiagram
|
stateDiagram
|
||||||
state if_state <<choice>>
|
state if_state <<choice>>
|
||||||
@@ -132,8 +138,10 @@ flowchart LR
|
|||||||
stateDiagram
|
stateDiagram
|
||||||
direction TB
|
direction TB
|
||||||
State T1 {
|
State T1 {
|
||||||
T11
|
T11 --> T12
|
||||||
}
|
}
|
||||||
|
T1 --> T2
|
||||||
|
T11 --> T2
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid2">
|
||||||
@@ -220,7 +228,7 @@ stateDiagram-v2
|
|||||||
look: 'handdrawn',
|
look: 'handdrawn',
|
||||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||||
// layout: 'dagre',
|
// layout: 'dagre',
|
||||||
// layout: 'elk',
|
layout: 'elk',
|
||||||
// layout: 'fixed',
|
// layout: 'fixed',
|
||||||
// htmlLabels: false,
|
// htmlLabels: false,
|
||||||
flowchart: { titleTopMargin: 10 },
|
flowchart: { titleTopMargin: 10 },
|
||||||
|
@@ -60,7 +60,7 @@ export const addVertex = async (nodeEl, graph, nodeArr, node) => {
|
|||||||
graph.children.push(child);
|
graph.children.push(child);
|
||||||
nodeDb[node.id] = child;
|
nodeDb[node.id] = child;
|
||||||
|
|
||||||
// // Add the element to the DOM
|
// Add the element to the DOM
|
||||||
if (!node.isGroup) {
|
if (!node.isGroup) {
|
||||||
const childNodeEl = await insertNode(nodeEl, node, node.dir);
|
const childNodeEl = await insertNode(nodeEl, node, node.dir);
|
||||||
boundingBox = childNodeEl.node().getBBox();
|
boundingBox = childNodeEl.node().getBBox();
|
||||||
@@ -93,7 +93,7 @@ export const addVertex = async (nodeEl, graph, nodeArr, node) => {
|
|||||||
|
|
||||||
export const addVertices = async function (nodeEl, nodeArr, graph, parentId) {
|
export const addVertices = async function (nodeEl, nodeArr, graph, parentId) {
|
||||||
const siblings = nodeArr.filter((node) => node.parentId === parentId);
|
const siblings = nodeArr.filter((node) => node.parentId === parentId);
|
||||||
log.info('addVertices DAGA', siblings, parentId);
|
log.info('addVertices APA12', siblings, parentId);
|
||||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
siblings.map(async (node) => {
|
siblings.map(async (node) => {
|
||||||
@@ -512,9 +512,7 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
const node = nodeDb[n.id];
|
const node = nodeDb[n.id];
|
||||||
|
|
||||||
// Subgraph
|
// Subgraph
|
||||||
console.log('Subgraph XCX before');
|
|
||||||
if (parentLookupDb.childrenById[node.id] !== undefined) {
|
if (parentLookupDb.childrenById[node.id] !== undefined) {
|
||||||
console.log('Subgraph XCX', node.id, node, node.labelData);
|
|
||||||
node.labels = [
|
node.labels = [
|
||||||
{
|
{
|
||||||
text: node.labelText,
|
text: node.labelText,
|
||||||
@@ -553,9 +551,9 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('before layout', JSON.stringify(elkGraph, null, 2));
|
// log.info('before layout', JSON.stringify(elkGraph, null, 2));
|
||||||
const g = await elk.layout(elkGraph);
|
const g = await elk.layout(elkGraph);
|
||||||
log.info('after layout', JSON.stringify(g));
|
// log.info('after layout', JSON.stringify(g));
|
||||||
|
|
||||||
// debugger;
|
// debugger;
|
||||||
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
||||||
@@ -563,11 +561,11 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
// (elem, edge, clusterDb, diagramType, graph, id)
|
// (elem, edge, clusterDb, diagramType, graph, id)
|
||||||
const startNode = nodeDb[edge.sources[0]];
|
const startNode = nodeDb[edge.sources[0]];
|
||||||
const endNode = nodeDb[edge.targets[0]];
|
const endNode = nodeDb[edge.targets[0]];
|
||||||
const sourceId = edge.start.id;
|
const sourceId = edge.start;
|
||||||
const targetId = edge.end.id;
|
const targetId = edge.end;
|
||||||
|
|
||||||
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
||||||
|
log.info('APA12 offset', offset, sourceId, targetId, edge);
|
||||||
if (edge.sections) {
|
if (edge.sections) {
|
||||||
const src = edge.sections[0].startPoint;
|
const src = edge.sections[0].startPoint;
|
||||||
const dest = edge.sections[0].endPoint;
|
const dest = edge.sections[0].endPoint;
|
||||||
@@ -590,6 +588,7 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
endNode,
|
endNode,
|
||||||
data4Layout.diagramId
|
data4Layout.diagramId
|
||||||
);
|
);
|
||||||
|
log.info('APA12 edge points after insert', JSON.stringify(edge.points));
|
||||||
|
|
||||||
edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
|
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;
|
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
||||||
|
@@ -767,35 +767,22 @@ const getTypeFromVertex = (vertex: FlowVertex) => {
|
|||||||
return vertex.type || 'squareRect';
|
return vertex.type || 'squareRect';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getData = () => {
|
const findNode = (nodes: Node[], id: string) => nodes.find((node) => node.id === id);
|
||||||
const config = getConfig();
|
|
||||||
const nodes: Node[] = [];
|
|
||||||
const edges: Edge[] = [];
|
|
||||||
|
|
||||||
// extract(getRootDocV2());
|
const addNodeFromVertex = (
|
||||||
// const diagramStates = getStates();
|
vertex: FlowVertex,
|
||||||
const useRough = config.look === 'handdrawn';
|
nodes: Node[],
|
||||||
const subGraphs = getSubGraphs();
|
parentDB: Map<string, string>,
|
||||||
log.info('Subgraphs - ', subGraphs);
|
subGraphDB: Map<string, boolean>,
|
||||||
const parentDB = new Map<string, string>();
|
config: any,
|
||||||
const subGraphDB = new Map<string, boolean>();
|
useRough: boolean
|
||||||
|
): Node => {
|
||||||
|
let parentId = parentDB.get(vertex.id);
|
||||||
|
let isGroup = subGraphDB.get(vertex.id) || false;
|
||||||
|
|
||||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
let node = findNode(nodes, vertex.id);
|
||||||
const subGraph = subGraphs[i];
|
if (!node) {
|
||||||
if (subGraph.nodes.length > 0) {
|
nodes.push({
|
||||||
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,
|
id: vertex.id,
|
||||||
label: vertex.text,
|
label: vertex.text,
|
||||||
labelStyle: '',
|
labelStyle: '',
|
||||||
@@ -809,10 +796,59 @@ export const getData = () => {
|
|||||||
type: isGroup ? 'group' : undefined,
|
type: isGroup ? 'group' : undefined,
|
||||||
isGroup,
|
isGroup,
|
||||||
useRough,
|
useRough,
|
||||||
};
|
});
|
||||||
nodes.push(node);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getData = () => {
|
||||||
|
const config = getConfig();
|
||||||
|
const nodes: Node[] = [];
|
||||||
|
const edges: Edge[] = [];
|
||||||
|
|
||||||
|
// extract(getRootDocV2());
|
||||||
|
// const diagramStates = getStates();
|
||||||
|
const useRough = config.look === 'handdrawn';
|
||||||
|
const subGraphs = getSubGraphs();
|
||||||
|
log.info('Subgraphs - APA12', subGraphs);
|
||||||
|
const parentDB = new Map<string, string>();
|
||||||
|
const subGraphDB = new Map<string, boolean>();
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
nodes.push({
|
||||||
|
id: subGraph.id,
|
||||||
|
label: subGraph.title,
|
||||||
|
labelStyle: '',
|
||||||
|
parentId: parentDB.get(subGraph.id),
|
||||||
|
padding: config.flowchart?.padding || 8,
|
||||||
|
cssStyles: '',
|
||||||
|
cssClasses: '',
|
||||||
|
shape: 'rect',
|
||||||
|
dir: subGraph.dir,
|
||||||
|
domId: subGraph.domId,
|
||||||
|
type: 'group',
|
||||||
|
isGroup: true,
|
||||||
|
useRough,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log('APA12 nodes - 1', nodes.length);
|
||||||
|
|
||||||
|
const n = getVertices();
|
||||||
|
n.forEach((vertex) => {
|
||||||
|
const node = addNodeFromVertex(vertex, nodes, parentDB, subGraphDB, config, useRough);
|
||||||
|
if (node) {
|
||||||
|
nodes.push(node);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('APA12 nodes', nodes.length);
|
||||||
|
|
||||||
const e = getEdges();
|
const e = getEdges();
|
||||||
e.forEach((rawEdge, index) => {
|
e.forEach((rawEdge, index) => {
|
||||||
const edge: Edge = {
|
const edge: Edge = {
|
||||||
@@ -829,6 +865,7 @@ export const getData = () => {
|
|||||||
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link',
|
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link',
|
||||||
arrowhead: 'none',
|
arrowhead: 'none',
|
||||||
arrowTypeEnd: 'arrow_point',
|
arrowTypeEnd: 'arrow_point',
|
||||||
|
// arrowTypeEnd: 'arrow_barb',
|
||||||
arrowheadStyle: 'fill: #333',
|
arrowheadStyle: 'fill: #333',
|
||||||
// stroke: rawEdge.pattern,
|
// stroke: rawEdge.pattern,
|
||||||
pattern: rawEdge.stroke,
|
pattern: rawEdge.stroke,
|
||||||
|
@@ -24,6 +24,10 @@ const registerDefaultLayoutLoaders = () => {
|
|||||||
name: 'dagre',
|
name: 'dagre',
|
||||||
loader: async () => await import('./layout-algorithms/dagre/index.js'),
|
loader: async () => await import('./layout-algorithms/dagre/index.js'),
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// name: 'elk',
|
||||||
|
// loader: async () => await import('../../../mermaid-layout-elk/src/render.js'),
|
||||||
|
// },
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -533,14 +533,14 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
let lineData = points.filter((p) => !Number.isNaN(p.y));
|
let lineData = points.filter((p) => !Number.isNaN(p.y));
|
||||||
const { cornerPoints, cornerPointPositions } = extractCornerPoints(lineData);
|
const { cornerPoints, cornerPointPositions } = extractCornerPoints(lineData);
|
||||||
lineData = fixCorners(lineData);
|
lineData = fixCorners(lineData);
|
||||||
let lastPoint = lineData[0];
|
let lastPoint = lineData[lineData.length - 1];
|
||||||
if (lineData.length > 1) {
|
if (lineData.length > 1) {
|
||||||
lastPoint = lineData[lineData.length - 1];
|
lastPoint = lineData[lineData.length - 1];
|
||||||
const secondLastPoint = lineData[lineData.length - 2];
|
const secondLastPoint = lineData[lineData.length - 2];
|
||||||
// Calculate the mid point of the last two points
|
// Calculate the mid point of the last two points
|
||||||
const diffX = (lastPoint.x - secondLastPoint.x) / 4;
|
const diffX = (lastPoint.x - secondLastPoint.x) / 2;
|
||||||
const diffY = (lastPoint.y - secondLastPoint.y) / 4;
|
const diffY = (lastPoint.y - secondLastPoint.y) / 2;
|
||||||
const midPoint = { x: secondLastPoint.x + 3 * diffX, y: secondLastPoint.y + 3 * diffY };
|
const midPoint = { x: secondLastPoint.x + diffX, y: secondLastPoint.y + diffY };
|
||||||
lineData.splice(-1, 0, midPoint);
|
lineData.splice(-1, 0, midPoint);
|
||||||
}
|
}
|
||||||
// This is the accessor function we talked about above
|
// This is the accessor function we talked about above
|
||||||
@@ -596,11 +596,16 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
let useRough = edge.useRough;
|
let useRough = edge.useRough;
|
||||||
let svgPath;
|
let svgPath;
|
||||||
let path = '';
|
let path = '';
|
||||||
|
let linePath = lineFunction(lineData);
|
||||||
if (useRough) {
|
if (useRough) {
|
||||||
const rc = rough.svg(elem);
|
const rc = rough.svg(elem);
|
||||||
const ld = Object.assign([], lineData);
|
const ld = Object.assign([], lineData);
|
||||||
const svgPathNode = rc.path(lineFunction(ld.splice(0, ld.length - 1)), {
|
// const svgPathNode = rc.path(lineFunction(ld.splice(0, ld.length-1)), {
|
||||||
|
// const svgPathNode = rc.path(lineFunction(ld), {
|
||||||
|
// roughness: 0.3,
|
||||||
|
// seed: handdrawnSeed,
|
||||||
|
// });
|
||||||
|
const svgPathNode = rc.path(linePath, {
|
||||||
roughness: 0.3,
|
roughness: 0.3,
|
||||||
seed: handdrawnSeed,
|
seed: handdrawnSeed,
|
||||||
});
|
});
|
||||||
@@ -614,13 +619,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
||||||
.attr('style', edge.style);
|
.attr('style', edge.style);
|
||||||
let d = svgPath.attr('d');
|
let d = svgPath.attr('d');
|
||||||
d = d + ' L ' + lastPoint.x + ' ' + lastPoint.y;
|
|
||||||
svgPath.attr('d', d);
|
svgPath.attr('d', d);
|
||||||
elem.node().appendChild(svgPath.node());
|
elem.node().appendChild(svgPath.node());
|
||||||
} else {
|
} else {
|
||||||
svgPath = elem
|
svgPath = elem
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', lineFunction(lineData))
|
.attr('d', linePath)
|
||||||
.attr('id', edge.id)
|
.attr('id', edge.id)
|
||||||
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
||||||
.attr('style', edge.style);
|
.attr('style', edge.style);
|
||||||
|
@@ -159,11 +159,11 @@ const point = (elem, type, id) => {
|
|||||||
.attr('id', id + '_' + type + '-pointEnd')
|
.attr('id', id + '_' + type + '-pointEnd')
|
||||||
.attr('class', 'marker ' + type)
|
.attr('class', 'marker ' + type)
|
||||||
.attr('viewBox', '0 0 10 10')
|
.attr('viewBox', '0 0 10 10')
|
||||||
.attr('refX', 6)
|
.attr('refX', 5)
|
||||||
.attr('refY', 5)
|
.attr('refY', 5)
|
||||||
.attr('markerUnits', 'userSpaceOnUse')
|
.attr('markerUnits', 'userSpaceOnUse')
|
||||||
.attr('markerWidth', 12)
|
.attr('markerWidth', 8)
|
||||||
.attr('markerHeight', 12)
|
.attr('markerHeight', 8)
|
||||||
.attr('orient', 'auto')
|
.attr('orient', 'auto')
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
|
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
|
||||||
@@ -178,8 +178,8 @@ const point = (elem, type, id) => {
|
|||||||
.attr('refX', 4.5)
|
.attr('refX', 4.5)
|
||||||
.attr('refY', 5)
|
.attr('refY', 5)
|
||||||
.attr('markerUnits', 'userSpaceOnUse')
|
.attr('markerUnits', 'userSpaceOnUse')
|
||||||
.attr('markerWidth', 12)
|
.attr('markerWidth', 11)
|
||||||
.attr('markerHeight', 12)
|
.attr('markerHeight', 11)
|
||||||
.attr('orient', 'auto')
|
.attr('orient', 'auto')
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', 'M 0 5 L 10 10 L 10 0 z')
|
.attr('d', 'M 0 5 L 10 10 L 10 0 z')
|
||||||
@@ -272,7 +272,7 @@ const barb = (elem, type, id) => {
|
|||||||
.attr('refY', 7)
|
.attr('refY', 7)
|
||||||
.attr('markerWidth', 20)
|
.attr('markerWidth', 20)
|
||||||
.attr('markerHeight', 14)
|
.attr('markerHeight', 14)
|
||||||
.attr('markerUnits', 'strokeWidth')
|
.attr('markerUnits', 'userSpaceOnUse')
|
||||||
.attr('orient', 'auto')
|
.attr('orient', 'auto')
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', 'M 19,7 L9,13 L14,7 L9,1 Z');
|
.attr('d', 'M 19,7 L9,13 L14,7 L9,1 Z');
|
||||||
|
@@ -9,7 +9,7 @@ const markerOffsets = {
|
|||||||
composition: 18,
|
composition: 18,
|
||||||
dependency: 6,
|
dependency: 6,
|
||||||
lollipop: 13.5,
|
lollipop: 13.5,
|
||||||
arrow_point: 5.3,
|
arrow_point: 4,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user