Skip to content
Snippets Groups Projects
graph.ts 4.92 KiB
Newer Older
  • Learn to ignore specific revisions
  • import * as Config from "../config";
    
    
        source: number;
        target: number;
    
    export interface Link {
        source: Node;
        target: Node;
        type?: GraphObjectType;
    
        name: string;
        description?: string;
    
        icon?: string;
        banner?: string;
    
        video?: string;
    
        references?: string[];
    
        id: number;
    
        type?: string;
    }
    
    export interface Node extends NodeContent {
    
        id: number;
    
        type: GraphObjectType;
    
        neighbors: Node[];
        links: Link[];
    }
    
    export interface GraphObjectType {
    
        id: number;
    
    }
    
    export interface Coordinate {
        x: number;
        y: number;
        z: number;
    }
    
    
    export interface GraphContent {
        nodes: Node[];
        links: Link[];
        objectGroups: GraphObjectType[];
    }
    
    
    /**
     * Basic graph data structure.
     */
    
    export default class Graph implements GraphContent {
    
        public nodes: Node[];
        public links: Link[];
        public objectGroups: GraphObjectType[];
        public nameToObjectGroup: Map<string, GraphObjectType>;
    
        private idToNode: Map<number, Node>;
    
    
        constructor(
            nodes: NodeData[],
            links: LinkData[],
            objectGroups?: GraphObjectType[]
        ) {
            this.objectGroups = objectGroups ?? this.createObjectGroups(nodes);
    
            this.nameToObjectGroup = new Map<string, GraphObjectType>();
            this.objectGroups.forEach((group) =>
                this.nameToObjectGroup.set(group.name, group)
            );
    
            this.createNodes(nodes);
    
    
            this.links = links.map((link) => {
                return {
                    source: this.idToNode.get(link.source),
                    target: this.idToNode.get(link.target),
                };
            });
    
    
            this.updateNodeData();
    
        private createNodes(nodes: NodeData[]) {
            this.nodes = [];
            for (const nodeData of nodes) {
                const { type, ...nodeVars } = nodeData;
                const node = { ...nodeVars } as Node;
                node.type = this.nameToObjectGroup.get(type);
    
                node.neighbors = [];
                node.links = [];
    
            this.idToNode = new Map<number, Node>();
    
            this.nodes.forEach((node) => {
                this.idToNode.set(node.id, node);
            });
    
        private removeFloatingNodes() {
            this.nodes = this.nodes.filter((node) => node.neighbors.length > 0);
        }
    
    
        /**
         * Updates the graph data structure to contain additional values.
         * Creates a 'neighbors' and 'links' array for each node object.
         */
    
            this.links.forEach((link) => {
                const a = link.source;
                const b = link.target;
                a.neighbors.push(b);
                b.neighbors.push(a);
                a.links.push(link);
                b.links.push(link);
            });
        }
    
    
        public node(id: number): Node {
    
            return this.idToNode.get(id);
        }
    
    
        private createObjectGroups(nodes: NodeData[]): GraphObjectType[] {
            const objectGroups: GraphObjectType[] = [];
            const nodeClasses: string[] = [];
            nodes.forEach((node) => nodeClasses.push(node.type));
            const nodeTypes = [...new Set(nodeClasses)].map((c) => String(c));
    
            for (let i = 0; i < nodeTypes.length; i++) {
                objectGroups.push({
    
                    id: undefined,  // Does not matter for display graph
    
                    name: nodeTypes[i],
                    color: Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length],
                });
    
            nodeTypes: Map<string, boolean>,
    
            linkTypes?: Map<string, boolean>
    
            const nodes = this.nodes.filter((l) => nodeTypes.get(l.type.name));
    
            let links;
            if (linkTypes === undefined) {
                links = this.links;
            } else {
    
                links = this.links.filter((l) => linkTypes.get(l.type.name));
    
            // Filter links which are connected to an invisible node
            links = links.filter(
    
                (l) =>
                    nodeTypes.get(l.source.type.name) &&
                    nodeTypes.get(l.target.type.name)
    
            // Convert to data objects and create new graph.
            // Using spread syntax to simplify object copying.
    
            return new Graph(
    
                nodes.map((node) => {
                    // eslint-disable-next-line no-unused-vars
                    const { type, neighbors, links, ...nodeVars } = node;
                    const nodeData = { ...nodeVars } as NodeData;
                    nodeData.type = type.name;
                    return nodeData;
                }),
    
                links.map((link) => {
                    return {
                        source: link.source.id,
                        target: link.target.id,
                    };