| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- import AlgorithmStep from "../AlgorithmStep.js";
- import { SiguiyamaContext } from "../siguiyama/SiguiyamaContext.js";
- import EdgeRoutingStepError from "../../errors/optimizer/EdgeRoutingStepError.js";
- import Edge from "../../graph/edge/Edge.js";
- import Layering from "../../graph/layering/Layering.js";
- import Node from "../../graph/node/Node.js";
- /**
- * Шаг назначения координат вершинам
- * Размещает вершины в двумерной плоскости по колонкам (слоям) и строкам (позициям в слое),
- * учитывая размеры вершин, вертикальный отступ между строками и горизонтальный отступ между слоями.
- */
- export default class CoordinateAssignmentStep extends AlgorithmStep<SiguiyamaContext> {
- /**
- * Отступ между вершинами по вертикали внутри одной колонки.
- */
- private readonly _layerGap: number;
- /**
- * Отступ между колонками (слоями) по горизонтали.
- */
- private readonly _padding: number;
- /**
- * @param layerGap Вертикальный отступ между вершинами в колонке.
- * @param padding Горизонтальный отступ между слоями.
- * @throws {EdgeRoutingStepError} Если передан отрицательный `layerGap` или `padding`.
- */
- public constructor(layerGap: number = 100, padding: number = 60) {
- if(layerGap < 0)
- throw new EdgeRoutingStepError("Layer Gap must be greater than 0");
- if(padding < 0)
- throw new EdgeRoutingStepError("Padding must be greater than 0");
- super(CoordinateAssignmentStep.name);
- this._layerGap = layerGap;
- this._padding = padding;
- }
- public run(context: SiguiyamaContext): void {
- const { layering } = context;
- if(!layering)
- throw new Error("Layering of graph was not found!");
- this.assignCoordinates(layering);
- }
- /**
- * Назначение координат всем вершинам графа.
- *
- * Алгоритм:
- * - слои обходятся справа налево (`toReversed()`),
- * - для каждого слоя вычисляется ширина колонки как максимальная ширина вершины в слое,
- * - для каждой позиции `i` внутри слоя вычисляется высота строки как максимум по всем слоям в этой позиции `i`,
- * - вершина размещается по центру своей ячейки.
- * @param layering Слоистая укладка графа.
- */
- private assignCoordinates(layering: Layering<Node, Edge<Node>>) : void {
- const layers = layering.getLayers().toReversed();
- let xOffset = 0.0;
- for(const layer of layers) {
- const nodes = layer.getNodes();
- const width = Math.max(...nodes.map(node => node.getWidth()));
- let yOffset = 0.0;
- for(let i = 0; i < nodes.length; i++) {
- const node = nodes[i]!;
- const height = Math.max(...layers.map((l) => l.getNodes().at(i)?.getHeight() ?? 0));
- node.setX(xOffset + width / 2 - node.getWidth() / 2).setY(yOffset + height / 2 - node.getHeight() / 2);
- yOffset += height + this._layerGap;
- }
- xOffset += width + this._padding;
- }
- }
- }
|