#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:
Knut Sveidqvist
2024-06-09 15:32:28 +02:00
parent 1b29135cc1
commit 7fbe1661ec
7 changed files with 119 additions and 67 deletions

View File

@@ -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 &lt;&lt;choice&gt;&gt; state if_state &lt;&lt;choice&gt;&gt;
@@ -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 },

View File

@@ -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;

View File

@@ -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,

View File

@@ -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'),
// },
]); ]);
}; };

View File

@@ -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);

View File

@@ -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');

View File

@@ -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;
/** /**