import LayeringError from "../../errors/graph/layering/LayeringError.js"; import Edge from "../Edge.js"; import Node from "../Node.js"; import Layer from "./Layer.js"; export default class Layering> { private readonly _layers: Map>; public constructor() { this._layers = new Map(); } public assign(node: TNode, layerIndex: number) : this { if(!this._layers.has(layerIndex)) this._layers.set(layerIndex, new Layer(layerIndex)); this._layers.get(layerIndex)!.addNodes([node.id]); return this; } public getLayers(): Layer[] { return Array.from(this._layers.values()).sort((a, b) => a.index - b.index); } public getLayerOf(nodeId: TNode["id"]) : number | null { for(const [layerIndex, layer] of this._layers) if(layer.nodes.some((id) => id == nodeId)) return layerIndex; return null; } public setLayerOf(nodeId: TNode["id"], newLayerIndex: number) : this { const oldIndex = this.getLayerOf(nodeId); if(oldIndex !== null) { const oldLayer = this._layers.get(oldIndex); oldLayer?.removeNodes([nodeId]) } if(!this._layers.has(newLayerIndex)) this._layers.set(newLayerIndex, new Layer(newLayerIndex)); this._layers.get(newLayerIndex)!.addNodes([nodeId]); return this; } public isEdgeTight(edge: TEdge) : boolean { const { from, to } = edge; const fromLayerIndex = this.getLayerOf(from), toLayerIndex = this.getLayerOf(to); if(fromLayerIndex == null || toLayerIndex == null) throw new LayeringError(`Node from edge ${edge.id} is not assigned to any layer`); return Math.abs(fromLayerIndex - toLayerIndex) === 1; } public getEdgeSpan(edge: TEdge) : number { const fromLayer = this.getLayerOf(edge.from); const toLayer = this.getLayerOf(edge.to); if(fromLayer === null || toLayer === null) throw new LayeringError(`Node from edge ${edge.id} is not assigned to any layer`); return Math.abs(fromLayer - toLayer); } public normalize() : this { const minLayerIndex = Math.min(...Array.from(this._layers.keys())); if(minLayerIndex === 0) return this; const newLayers = new Map>(); for(const [index, layer] of this._layers) { const newLayerIndex = index - minLayerIndex; const newLayer = new Layer(newLayerIndex); newLayer.addNodes(layer.nodes); newLayers.set(newLayerIndex, newLayer); } this._layers.clear(); newLayers.forEach((layer, index) => this._layers.set(index, layer)); return this; } public get height() : number { return this._layers.size; } public get width() : number { return Math.max(...Array.from(this._layers.values()).map((layer) => layer.width)); } }