UNPKG

devexpress-diagram

Version:

DevExpress Diagram Control

59 lines (56 loc) 2.85 kB
import { IKeyOwner } from "../Interfaces"; import { Graph } from "./Graph"; import { ConnectionMode } from "./Structures"; import { ItemKey } from "../Model/DiagramItem"; export class Tree<T extends IKeyOwner> { private parentToChildren: {[parentKey: string]: T[]}; private childToParent: {[childKey: string]: ItemKey} = {}; root: T; constructor(root: T, parentToChildren: {[parentKey: string]: T[]}) { this.root = root; this.parentToChildren = parentToChildren; for(const key in parentToChildren) { if(!Object.prototype.hasOwnProperty.call(parentToChildren, key)) continue; parentToChildren[key].forEach(c => this.childToParent[c.key] = key); } } getChildren(node: T): T[] { return node && this.parentToChildren[node.key] ? this.parentToChildren[node.key] : []; } hasChildren(node: T): boolean { return this.parentToChildren[node.key] && this.parentToChildren[node.key].length > 0; } iterate(callback: (node: T, level: number) => void) { this.iterateCore(this.root, 0, callback); } static createSpanningTree<T extends IKeyOwner>(component: Graph<T>): Tree<T> { const rootKey = Tree.findRoot(component); const iterator = component.createIterator(ConnectionMode.Outgoing); const parentToChildren: { [parentKey: string]: T[] } = {}; iterator.skipEdge = (e => e.to === undefined || iterator.isNodeVisited(e.to)); iterator.onNode = n => parentToChildren[n.key] = []; iterator.onEdge = e => { const node = component.getNode(e.to); node && parentToChildren[e.from].push(node); }; iterator.iterate(rootKey); return new Tree(component.getNode(rootKey), parentToChildren); } private iterateCore(node: T, level: number, callback: (node: T, level: number) => void) { callback(node, level); this.getChildren(node).forEach(n => this.iterateCore(n, level + 1, callback)); } private static findRoot<T extends IKeyOwner>(component: Graph<T>): ItemKey { return component.nodes.reduce<{inc: number, out: number, candidate: ItemKey}>((aggregator, cur) => { const edges = component.getAdjacentEdges(cur); const inc = edges.filter(l => l.to === cur).length; const out = edges.filter(l => l.from === cur).length; if(aggregator.candidate === undefined || (inc === 0 && aggregator.inc > 0) || (aggregator.inc !== 0 && aggregator.out - aggregator.inc < out - inc)) { aggregator.candidate = cur; aggregator.inc = inc; aggregator.out = out; } return aggregator; }, { inc: -1, out: -1, candidate: undefined }).candidate; } }