| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- import Edge from "../../graph/edge/Edge.js";
- import Graph from "../../graph/Graph.js";
- import Layering from "../../graph/layering/Layering.js";
- import Node from "../../graph/node/Node.js";
- import AlgorithmStep from "../AlgorithmStep.js";
- import Grid from "../siguiyama/grid/Grid.js";
- import { FeedbackSet, SiguiyamaContext } from "../siguiyama/SiguiyamaContext.js";
- export default class CoordinateAssignmentStep extends AlgorithmStep<SiguiyamaContext> {
- private readonly _layerGap: number;
- private readonly _nodeGap: number;
- public constructor(layerGap: number, nodeGap: number) {
- super(CoordinateAssignmentStep.name);
- this._layerGap = layerGap;
- this._nodeGap = nodeGap;
- }
- public run(context: SiguiyamaContext): void {
- const { graph, layering, feedbackSet } = context;
- if(!graph)
- throw new Error("Source graph was not found!");
- if(!layering)
- throw new Error("Layering of graph was not found!");
- if(!feedbackSet)
- throw new Error("Feedback set was not found!");
- this.reverseEdgesInFeedback(graph, feedbackSet);
- const grid = this.buildGrid(layering);
-
- this.assignCoordinatesFromGrid(graph, grid);
- }
- private reverseEdgesInFeedback(graph: Graph<Node,Edge<Node>>, feedbackSet: FeedbackSet) : void {
- const edges = graph.getEdges();
- for(const edge of edges) {
- if(!feedbackSet.includes(edge))
- continue;
- const from = edge.getFrom(), to = edge.getTo();
- edge.setFrom(to).setTo(from);
- }
- }
- private buildGrid(layering: Layering<Node, Edge<Node>>): Grid<Node> {
- const grid = new Grid<Node>();
- const layers = layering.getLayers();
- for(let col = layers.length - 1; col >= 0; col--) {
- const layer = layers[col]!;
- for(let row = 0; row < layer.nodes.length; row++)
- grid.set(row, col, layer.nodes[row]!);
- }
- return grid;
- }
- private assignCoordinatesFromGrid(graph: Graph<Node, Edge<Node>>, grid: Grid<Node>): void {
- const PADDING = 60;
- const colWidths = this.computeColWidths(grid);
- const rowHeights = this.computeRowHeights(grid);
- const colX = this.computeOffsets(colWidths, this._nodeGap, PADDING);
- const rowY = this.computeOffsets(rowHeights, this._layerGap, PADDING);
- for(let col = 0; col < grid.cols; col++) {
- for(let row = 0; row < grid.rows; row++) {
- const node = grid.get(row, col);
- if(!node)
- continue;
- node.setX(colX[col]! + (colWidths[col]! - node.getWidth()) / 2);
- node.setY(rowY[row]! + (rowHeights[row]! - node.getHeight()) / 2);
- }
- }
- }
- private computeColWidths(grid: Grid<Node>): number[] {
- const widths: number[] = new Array(grid.cols).fill(0);
- for(let col = 0; col < grid.cols; col++)
- for(let row = 0; row < grid.rows; row++) {
- const node = grid.get(row, col);
- if(!node)
- continue;
- widths[col] = Math.max(widths[col]!, node.getWidth());
- }
- return widths;
- }
- private computeRowHeights(grid: Grid<Node>): number[] {
- const heights: number[] = new Array(grid.rows).fill(0);
- for(let row = 0; row < grid.rows; row++)
- for(let col = 0; col < grid.cols; col++) {
- const node = grid.get(row, col);
- if(!node) continue;
- heights[row] = Math.max(heights[row]!, node.getHeight());
- }
- return heights;
- }
- private computeOffsets(sizes: number[], gap: number, padding: number): number[] {
- const offsets: number[] = [padding];
- for(let i = 1; i < sizes.length; i++)
- offsets.push(offsets[i - 1]! + sizes[i - 1]! + gap);
- return offsets;
- }
- }
|