Layering.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import LayeringError from "../../errors/graph/layering/LayeringError.js";
  2. import Edge from "../Edge.js";
  3. import Node from "../Node.js";
  4. import Layer from "./Layer.js";
  5. export default class Layering<TNode extends Node, TEdge extends Edge<TNode>> {
  6. private readonly _layers: Map<number, Layer<TNode>>;
  7. public constructor() {
  8. this._layers = new Map();
  9. }
  10. public assign(node: TNode, layerIndex: number) : this {
  11. if(!this._layers.has(layerIndex))
  12. this._layers.set(layerIndex, new Layer(layerIndex));
  13. this._layers.get(layerIndex)!.addNodes([node.id]);
  14. return this;
  15. }
  16. public getLayers(): Layer<TNode>[] {
  17. return Array.from(this._layers.values()).sort((a, b) => a.index - b.index);
  18. }
  19. public getLayerOf(nodeId: TNode["id"]) : number | null {
  20. for(const [layerIndex, layer] of this._layers)
  21. if(layer.nodes.some((id) => id == nodeId))
  22. return layerIndex;
  23. return null;
  24. }
  25. public setLayerOf(nodeId: TNode["id"], newLayerIndex: number) : this {
  26. const oldIndex = this.getLayerOf(nodeId);
  27. if(oldIndex !== null) {
  28. const oldLayer = this._layers.get(oldIndex);
  29. oldLayer?.removeNodes([nodeId])
  30. }
  31. if(!this._layers.has(newLayerIndex))
  32. this._layers.set(newLayerIndex, new Layer(newLayerIndex));
  33. this._layers.get(newLayerIndex)!.addNodes([nodeId]);
  34. return this;
  35. }
  36. public isEdgeTight(edge: TEdge) : boolean {
  37. const { from, to } = edge;
  38. const fromLayerIndex = this.getLayerOf(from), toLayerIndex = this.getLayerOf(to);
  39. if(fromLayerIndex == null || toLayerIndex == null)
  40. throw new LayeringError(`Node from edge ${edge.id} is not assigned to any layer`);
  41. return Math.abs(fromLayerIndex - toLayerIndex) === 1;
  42. }
  43. public getEdgeSpan(edge: TEdge) : number {
  44. const fromLayer = this.getLayerOf(edge.from);
  45. const toLayer = this.getLayerOf(edge.to);
  46. if(fromLayer === null || toLayer === null)
  47. throw new LayeringError(`Node from edge ${edge.id} is not assigned to any layer`);
  48. return Math.abs(fromLayer - toLayer);
  49. }
  50. public normalize() : this {
  51. const minLayerIndex = Math.min(...Array.from(this._layers.keys()));
  52. if(minLayerIndex === 0)
  53. return this;
  54. const newLayers = new Map<number, Layer<TNode>>();
  55. for(const [index, layer] of this._layers) {
  56. const newLayerIndex = index - minLayerIndex;
  57. const newLayer = new Layer<TNode>(newLayerIndex);
  58. newLayer.addNodes(layer.nodes);
  59. newLayers.set(newLayerIndex, newLayer);
  60. }
  61. this._layers.clear();
  62. newLayers.forEach((layer, index) => this._layers.set(index, layer));
  63. return this;
  64. }
  65. public get height() : number {
  66. return this._layers.size;
  67. }
  68. public get width() : number {
  69. return Math.max(...Array.from(this._layers.values()).map((layer) => layer.width));
  70. }
  71. }