diff --git a/packages/react-diagrams-routing/src/dagre/DagreEngine.ts b/packages/react-diagrams-routing/src/dagre/DagreEngine.ts index 46440ac..fafdb71 100644 --- a/packages/react-diagrams-routing/src/dagre/DagreEngine.ts +++ b/packages/react-diagrams-routing/src/dagre/DagreEngine.ts @@ -1,14 +1,13 @@ import { DiagramModel, PointModel } from '@projectstorm/react-diagrams-core'; import * as dagre from 'dagre'; -import * as _ from 'lodash'; import { GraphLabel } from 'dagre'; +import * as _ from 'lodash'; import { Point } from '@projectstorm/geometry'; -import { link } from 'fs/promises'; export interface DagreEngineOptions { graph?: GraphLabel; /** - * Will also layout links + * Will also re-layout links */ includeLinks?: boolean; nodeMargin?: number; @@ -48,24 +47,9 @@ export class DagreEngine { } }); - - g.nodes().forEach(function (v) { - console.log("Node " + v + ": " + JSON.stringify(g.node(v))); - }); - g.edges().forEach(function (e) { - console.log("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(g.edge(e))); - }); - // layout the graph dagre.layout(g); - g.nodes().forEach(function (v) { - console.log("Node " + v + ": " + JSON.stringify(g.node(v))); - }); - g.edges().forEach(function (e) { - console.log("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(g.edge(e))); - }); - g.nodes().forEach((v) => { const node = g.node(v); model.getNode(v).setPosition(node.x - node.width / 2, node.y - node.height / 2); @@ -86,7 +70,10 @@ export class DagreEngine { } } - public refreshLinks(diagram: DiagramModel) { + /** + * TODO cleanup this method into smaller methods + */ + public refreshLinks(diagram: DiagramModel) { const { nodeMargin } = this.options; const nodes = diagram.getNodes(); const links = diagram.getLinks(); @@ -98,9 +85,11 @@ export class DagreEngine { _.forEach(nodes, (node) => { // find vertical lines. vertical lines go through maximum number of nodes located under each other. const nodeColumnCenter = node.getX() + node.width / 2; - if (_.every(verticalLines, (vLine) => { - return Math.abs(nodeColumnCenter - vLine) > nodeMargin - })) { + if ( + _.every(verticalLines, (vLine) => { + return Math.abs(nodeColumnCenter - vLine) > nodeMargin; + }) + ) { verticalLines.push(nodeColumnCenter); } }); @@ -115,13 +104,13 @@ export class DagreEngine { // set occupied chunks _.forEach(nodes, (node) => { const nodeColumnCenter = node.getX() + node.width / 2; - const startChunkIndex = Math.floor(node.getY() / (nodeMargin)); - const endChunkIndex = Math.floor((node.getY() + node.height) / (nodeMargin)); + const startChunkIndex = Math.floor(node.getY() / nodeMargin); + const endChunkIndex = Math.floor((node.getY() + node.height) / nodeMargin); // find max ChunkRowIndex if (endChunkIndex > maxChunkRowIndex) maxChunkRowIndex = endChunkIndex; const nodeColumnIndex = _.findIndex(verticalLines, (vLine) => { return Math.abs(nodeColumnCenter - vLine) <= nodeMargin; - }) + }); _.forEach(_.range(startChunkIndex, endChunkIndex + 1), (chunkIndex) => { chunks[nodeColumnIndex][chunkIndex] = true; }); @@ -136,35 +125,35 @@ export class DagreEngine { const sourceIndex = NodeXColumnIndexDictionary[source.getX()]; const targetIndex = NodeXColumnIndexDictionary[target.getX()]; - return sourceIndex > targetIndex ? { - link, - sourceIndex, - sourceY: source.getY() + source.height / 2, - source, - targetIndex, - targetY: target.getY() + source.height / 2, - target - } : { - link, - sourceIndex: targetIndex, - sourceY: target.getY() + target.height / 2, - source: target, - targetIndex: sourceIndex, - targetY: source.getY() + source.height / 2, - target: source - }; + return sourceIndex > targetIndex + ? { + link, + sourceIndex, + sourceY: source.getY() + source.height / 2, + source, + targetIndex, + targetY: target.getY() + source.height / 2, + target + } + : { + link, + sourceIndex: targetIndex, + sourceY: target.getY() + target.height / 2, + source: target, + targetIndex: sourceIndex, + targetY: source.getY() + source.height / 2, + target: source + }; } }); const sortedEdges = _.sortBy(edges, (link) => { return Math.abs(link.targetIndex - link.sourceIndex); - }) + }); + // set link points - if (this.options.includeLinks) { - _.forEach(sortedEdges, (edge) => { - - const link = diagram.getLink(edge.link.getID()) + const link = diagram.getLink(edge.link.getID()); // re-draw if (Math.abs(edge.sourceIndex - edge.targetIndex) > 1) { // get the length of link in column @@ -174,11 +163,18 @@ export class DagreEngine { const targetChunkIndex = Math.floor(edge.targetY / nodeMargin); // check upper paths - let northCost = 1; let aboveRowIndex = chunkIndex; + let northCost = 1; + let aboveRowIndex = chunkIndex; for (; aboveRowIndex >= 0; aboveRowIndex--, northCost++) { - if (_.every(columns, (columnIndex) => { - return !(chunks[columnIndex][aboveRowIndex] || chunks[columnIndex + 0.5][aboveRowIndex] || chunks[columnIndex - 0.5][aboveRowIndex]) ; - })) { + if ( + _.every(columns, (columnIndex) => { + return !( + chunks[columnIndex][aboveRowIndex] || + chunks[columnIndex + 0.5][aboveRowIndex] || + chunks[columnIndex - 0.5][aboveRowIndex] + ); + }) + ) { break; } } @@ -187,41 +183,69 @@ export class DagreEngine { let southCost = 0; let belowRowIndex = chunkIndex; for (; belowRowIndex <= maxChunkRowIndex; belowRowIndex++, southCost++) { - if (_.every(columns, (columnIndex) => { - return !(chunks[columnIndex][belowRowIndex] || chunks[columnIndex + 0.5][belowRowIndex] || chunks[columnIndex - 0.5][belowRowIndex]) ; - })) { + if ( + _.every(columns, (columnIndex) => { + return !( + chunks[columnIndex][belowRowIndex] || + chunks[columnIndex + 0.5][belowRowIndex] || + chunks[columnIndex - 0.5][belowRowIndex] + ); + }) + ) { break; } } // pick the cheapest path - const pathRowIndex = (southCost + (belowRowIndex - targetChunkIndex)) < (northCost + (targetChunkIndex - aboveRowIndex)) ? belowRowIndex + 1 : aboveRowIndex - 1; + const pathRowIndex = + southCost + (belowRowIndex - targetChunkIndex) < northCost + (targetChunkIndex - aboveRowIndex) + ? belowRowIndex + 1 + : aboveRowIndex - 1; // Finally update the link points - const points = [link.getFirstPoint()]; - points.push(new PointModel({ link: link, position: new Point((verticalLines[columns[0]] + verticalLines[columns[0] + 1]) / 2, (pathRowIndex + 0.5) * nodeMargin) })); + points.push( + new PointModel({ + link: link, + position: new Point( + (verticalLines[columns[0]] + verticalLines[columns[0] + 1]) / 2, + (pathRowIndex + 0.5) * nodeMargin + ) + }) + ); _.forEach(columns, (column) => { - points.push(new PointModel({ link: link, position: new Point(verticalLines[column], (pathRowIndex + 0.5) * nodeMargin) })); - points.push(new PointModel({ link: link, position: new Point((verticalLines[column] + verticalLines[column - 1]) / 2, (pathRowIndex + 0.5) * nodeMargin) })); + points.push( + new PointModel({ + link: link, + position: new Point(verticalLines[column], (pathRowIndex + 0.5) * nodeMargin) + }) + ); + points.push( + new PointModel({ + link: link, + position: new Point( + (verticalLines[column] + verticalLines[column - 1]) / 2, + (pathRowIndex + 0.5) * nodeMargin + ) + }) + ); chunks[column][pathRowIndex] = true; chunks[column][pathRowIndex + 1] = true; chunks[column + 0.5][pathRowIndex] = true; chunks[column + 0.5][pathRowIndex + 1] = true; - }) + }); link.setPoints(points.concat(link.getLastPoint())); - - } else { // refresh + } else { + // refresh link.setPoints([link.getFirstPoint(), link.getLastPoint()]); - const columnIndex = (edge.sourceIndex + edge.targetIndex)/2; + const columnIndex = (edge.sourceIndex + edge.targetIndex) / 2; if (!chunks[columnIndex]) { chunks[columnIndex] = {}; } - const rowIndex = Math.floor(((edge.sourceY + edge.targetY)/2)/ nodeMargin); - chunks[columnIndex][rowIndex] = true - chunks[columnIndex][rowIndex + 1] = true + const rowIndex = Math.floor((edge.sourceY + edge.targetY) / 2 / nodeMargin); + chunks[columnIndex][rowIndex] = true; + chunks[columnIndex][rowIndex + 1] = true; } - }); } }