#5237 Recusive structuture refactoring for subgraphs

This commit is contained in:
Knut Sveidqvist
2024-05-03 15:58:39 +02:00
parent 024bffd683
commit b2c286ff1d
5 changed files with 244 additions and 169 deletions

View File

@@ -74,19 +74,24 @@
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
stateDiagram-v2 stateDiagram-v2
[*] --> First Chimp --> A
state First {
[*] --> second
second --> [*]
}
</pre </pre
> >
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
stateDiagram-v2 stateDiagram-v2
Second state First {
second --> third
}
</pre
>
<pre id="diagram" class="mermaid2">
stateDiagram-v2
[*] --> First
state First {
[*] --> second
second --> [*]
}
</pre </pre
> >
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">

View File

@@ -574,16 +574,6 @@ const setDirection = (dir) => {
const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim()); const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim());
const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, altFlag, useRough) => { const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, altFlag, useRough) => {
console.log(
'abc88 parent, parsedItemm, diagramStates, nodes, edges, altFlag, useRough:',
parent,
parsedItem,
diagramStates,
nodes,
edges,
altFlag,
useRough
);
const itemId = parsedItem.id; const itemId = parsedItem.id;
const classStr = getClassesFromDbInfo(diagramStates[itemId]); const classStr = getClassesFromDbInfo(diagramStates[itemId]);
@@ -758,6 +748,11 @@ const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, altFlag, u
} }
}; };
/**
*
* @param nodes
* @param nodeData
*/
function insertOrUpdateNode(nodes, nodeData) { function insertOrUpdateNode(nodes, nodeData) {
const existingNodeData = nodes.find((node) => node.id === nodeData.id); const existingNodeData = nodes.find((node) => node.id === nodeData.id);
if (existingNodeData) { if (existingNodeData) {

View File

@@ -87,8 +87,8 @@ export const draw = async function (text: string, id: string, _version: string,
// performRender(data4Rendering); // performRender(data4Rendering);
data4Layout.type = diag.type; data4Layout.type = diag.type;
data4Layout.layoutAlgorithm = 'dagre-wrapper'; // data4Layout.layoutAlgorithm = 'dagre-wrapper';
//data4Layout.layoutAlgorithm = 'elk'; data4Layout.layoutAlgorithm = 'elk';
data4Layout.direction = DIR; data4Layout.direction = DIR;
data4Layout.nodeSpacing = conf.nodeSpacing || 50; data4Layout.nodeSpacing = conf.nodeSpacing || 50;
data4Layout.rankSpacing = conf.rankSpacing || 50; data4Layout.rankSpacing = conf.rankSpacing || 50;

View File

@@ -21,6 +21,7 @@ import { log } from '$root/logger.js';
import ELK from 'elkjs/lib/elk.bundled.js'; import ELK from 'elkjs/lib/elk.bundled.js';
const nodeDb = {}; const nodeDb = {};
let portPos = {};
let clusterDb = {}; let clusterDb = {};
const addSubGraphs = function (db) { const addSubGraphs = function (db) {
@@ -46,24 +47,8 @@ const addSubGraphs = function (db) {
return parentLookupDb; return parentLookupDb;
}; };
// /** export const addVertex = async (nodeEl, graph, nodeArr, node) => {
// * Function that adds the vertices found during parsing to the graph to be rendered. console.log('addVertex abc88', node.id);
// *
// * @param vert Object containing the vertices.
// * @param g The graph that is to be drawn.
// * @param svgId
// * @param root
// * @param doc
// * @param diagObj
// */
export const addVertices = async function (svg, data4Layout, parentLookupDb, graph) {
const nodes = svg.insert('g').attr('class', 'nodes');
console.log('data4Layout (node)', data4Layout);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
await Promise.all(
data4Layout.nodes.map(async (node) => {
console.log('node', node);
// const node = vert[id]; // const node = vert[id];
// /** // /**
@@ -113,17 +98,24 @@ export const addVertices = async function (svg, data4Layout, parentLookupDb, gra
]; ];
let boundingBox; let boundingBox;
let nodeEl; const child = {
...node,
ports: node.shape === 'diamond' ? ports : [],
};
graph.children.push(child);
// // Add the element to the DOM // // Add the element to the DOM
if (node.type !== 'group') { if (node.type !== 'group') {
nodeEl = await insertNode(nodes, node, node.dir); const childNodeEl = await insertNode(nodeEl, node, node.dir);
boundingBox = nodeEl.node().getBBox(); boundingBox = childNodeEl.node().getBBox();
graph.children.push({ child.domId = childNodeEl;
...node, child.width = boundingBox.width;
domId: nodeEl, child.height = boundingBox.height;
}); } else {
child.children = [];
await addVertices(nodeEl, nodeArr, child, node.id);
} }
// else { // else {
// const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text'); // const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
// // svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:')); // // svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
@@ -149,7 +141,7 @@ export const addVertices = async function (svg, data4Layout, parentLookupDb, gra
// const data = { // const data = {
// id: node.id, // id: node.id,
// ports: node.type === 'diamond' ? ports : [], // ports: node.shape === 'diamond' ? ports : [],
// // labelStyle: styles.labelStyle, // // labelStyle: styles.labelStyle,
// // shape: _shape, // // shape: _shape,
// layoutOptions, // layoutOptions,
@@ -168,7 +160,7 @@ export const addVertices = async function (svg, data4Layout, parentLookupDb, gra
// width: boundingBox?.width, // width: boundingBox?.width,
// height: boundingBox?.height, // height: boundingBox?.height,
// // dir: vertex.dir, // // dir: vertex.dir,
// type: node.type, // type: node.shape,
// // props: vertex.props, // // props: vertex.props,
// // padding: getConfig().flowchart.padding, // // padding: getConfig().flowchart.padding,
// // boundingBox, // // boundingBox,
@@ -198,6 +190,24 @@ export const addVertices = async function (svg, data4Layout, parentLookupDb, gra
// // padding: getConfig().flowchart.padding, // // padding: getConfig().flowchart.padding,
// // parent: parentLookupDb.parentById[vertex.id], // // parent: parentLookupDb.parentById[vertex.id],
// // }); // // });
};
// /**
// * Function that adds the vertices found during parsing to the graph to be rendered.
// *
// * @param vert Object containing the vertices.
// * @param g The graph that is to be drawn.
// * @param svgId
// * @param root
// * @param doc
// * @param diagObj
// */
export const addVertices = async function (nodeEl, nodeArr, graph, parentId) {
const siblings = nodeArr.filter((node) => node.parentId === parentId);
log.info('addVertices abc88', siblings, parentId);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
await Promise.all(
siblings.map(async (node) => {
await addVertex(nodeEl, graph, nodeArr, node);
}) })
); );
return graph; return graph;
@@ -235,9 +245,18 @@ const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, depth) => {
// ); // );
// label.node().appendChild(node.labelData.labelNode); // label.node().appendChild(node.labelData.labelNode);
// log.info('Id (UGH)= ', node.type, node.labels); // log.info('Id (UGH)= ', node.shape, node.labels);
// } else { // } else {
log.info('Id (UGH)= ', node.id); log.info(
'Id (UGH)= ',
node.id,
node.x,
node.y,
relX,
relY,
node.domId.node(),
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
);
node.domId.attr( node.domId.attr(
'transform', 'transform',
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})` `translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
@@ -246,12 +265,61 @@ const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, depth) => {
// } // }
// }); // });
// nodeArray.forEach(function (node) { // nodeArray.forEach(function (node) {
// if (node && node.type === 'group') { // if (node && node.shape === 'group') {
// drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj, depth + 1); // drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj, depth + 1);
// } // }
}); });
}; };
const getNextPort = (node, edgeDirection, graphDirection) => {
log.info('getNextPort abc88', { node, edgeDirection, graphDirection });
if (!portPos[node]) {
switch (graphDirection) {
case 'TB':
case 'TD':
portPos[node] = {
inPosition: 'north',
outPosition: 'south',
};
break;
case 'BT':
portPos[node] = {
inPosition: 'south',
outPosition: 'north',
};
break;
case 'RL':
portPos[node] = {
inPosition: 'east',
outPosition: 'west',
};
break;
case 'LR':
portPos[node] = {
inPosition: 'west',
outPosition: 'east',
};
break;
}
}
const result = edgeDirection === 'in' ? portPos[node].inPosition : portPos[node].outPosition;
if (edgeDirection === 'in') {
portPos[node].inPosition = getNextPosition(
portPos[node].inPosition,
edgeDirection,
graphDirection
);
} else {
portPos[node].outPosition = getNextPosition(
portPos[node].outPosition,
edgeDirection,
graphDirection
);
}
return result;
};
const getEdgeStartEndPoint = (edge, dir) => { const getEdgeStartEndPoint = (edge, dir) => {
let source = edge.start; let source = edge.start;
let target = edge.end; let target = edge.end;
@@ -267,11 +335,11 @@ const getEdgeStartEndPoint = (edge, dir) => {
return { source, target }; return { source, target };
} }
if (startNode.type === 'diamond') { if (startnode.shape === 'diamond') {
source = `${source}-${getNextPort(source, 'out', dir)}`; source = `${source}-${getNextPort(source, 'out', dir)}`;
} }
if (endNode.type === 'diamond') { if (endnode.shape === 'diamond') {
target = `${target}-${getNextPort(target, 'in', dir)}`; target = `${target}-${getNextPort(target, 'in', dir)}`;
} }
@@ -514,7 +582,9 @@ export const render = async (data4Layout, svg, element) => {
// that is not in the dom so we need to add it to the dom, get the size // that is not in the dom so we need to add it to the dom, get the size
// we will position the nodes when we get the layout from elkjs // we will position the nodes when we get the layout from elkjs
const parentLookupDb = {}; const parentLookupDb = {};
graph = await addVertices(svg, data4Layout, parentLookupDb, graph); const nodeEl = svg.insert('g').attr('class', 'nodes');
graph = await addVertices(nodeEl, data4Layout.nodes, graph);
console.log('after addVertices abc88', JSON.stringify(graph, null, 2));
console.log('graph', graph, data4Layout); console.log('graph', graph, data4Layout);
@@ -596,11 +666,13 @@ export const render = async (data4Layout, svg, element) => {
// }); // });
// insertChildren(graph.children, parentLookupDb); // insertChildren(graph.children, parentLookupDb);
// log.info('after layout', JSON.stringify(graph, null, 2));
// console.log('before layout abc88', JSON.stringify(graph, null, 2));
const g = await elk.layout(graph); const g = await elk.layout(graph);
log.info('after layout', JSON.stringify(graph, null, 2));
console.log('after layout abc88', g);
// drawNodes(0, 0, g.children, svg, subGraphsEl, 0); // drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
drawNodes(0, 0, g.children, svg, null, 0); drawNodes(0, 0, g.children, svg, null, 0);
console.log('after layout', g);
g.edges?.map((edge) => { g.edges?.map((edge) => {
// (elem, edge, clusterDb, diagramType, graph, id) // (elem, edge, clusterDb, diagramType, graph, id)
edge.start = nodeDb[edge.sources[0]]; edge.start = nodeDb[edge.sources[0]];

View File

@@ -419,7 +419,10 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, graph, i
// Currently only flowcharts get the curve from the settings, perhaps this should // Currently only flowcharts get the curve from the settings, perhaps this should
// be expanded to a common setting? Restricting it for now in order not to cause side-effects that // be expanded to a common setting? Restricting it for now in order not to cause side-effects that
// have not been thought through // have not been thought through
if (edge.curve && (diagramType === 'graph' || diagramType === 'flowchart')) { if (
edge.curve &&
(diagramType === 'graph' || diagramType === 'flowchart' || diagramType === 'stateDiagram')
) {
curve = edge.curve; curve = edge.curve;
} }