Skip to content
Snippets Groups Projects
graph.ts 4.09 KiB
Newer Older
import * as Config from "../config";

interface Link {
    source: string;
    target: string;
    type?: string;
}

export interface LinkData {
    source: NodeData;
    target: NodeData;
    type?: string;
}

export interface NodeData {
    id: string;
    name: string;
    description?: string;
    icon?: string;
    banner?: string;
    type?: string;
    video?: string;
    references?: string[];
    neighbors: NodeData[];
    links: LinkData[];
}

export interface Coordinate {
    x: number;
    y: number;
    z: number;
}

export default class Graph {
    public nodes: NodeData[];
    public links: LinkData[];
    private idToNode: Map<string, NodeData>;
    public edgeColors: Map<string, string>;
    public nodeColors: Map<string, string>;
    constructor(nodes: NodeData[], links: Link[]) {
        this.nodes = nodes;
        this.idToNode = new Map<string, NodeData>();
        nodes.forEach((node) => {
            this.idToNode.set(node.id, node);
        });

        this.links = links.map((link) => {
            return {
                source: this.idToNode.get(link.source),
                target: this.idToNode.get(link.target),
                type: link.type,
            };
        });

        this.edgeColors = new Map<string, string>();
        this.nodeColors = new Map<string, string>();

        this.resetNodeData();
        this.updateNodeData();
        this.mapNodeColors();
        this.mapLinkColors();
        for (const node of this.nodes) {
            node.neighbors = [];
            node.links = [];
        }
    }

    /**
     * Updates the graph data structure to contain additional values.
     * Creates a 'neighbors' and 'links' array for each node object.
     */
        this.resetNodeData();

        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: string): NodeData {
        return this.idToNode.get(id);
    }

    /**
     * Maps the colors of the color palette to the different edge types
     */
    private mapLinkColors() {
        // TODO: Legacy - is there a use-case for link types?
        const linkClasses = this.getLinkClasses();
        for (let i = 0; i < linkClasses.length; i++) {
            this.edgeColors.set(
                linkClasses[i],
                Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length]
            );
        }
    }

    /**
     * Maps the colors of the color palette to the different edge types
     */
    private mapNodeColors() {
        const nodeClasses = this.getNodeClasses();
        for (let i = 0; i < nodeClasses.length; i++) {
            this.nodeColors.set(
                nodeClasses[i],
                Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length]
            );
        }
    }

    /**
     * Returns an array containing the different edge types of the graph.
     * @returns {*[]}
     */
    public getLinkClasses(): string[] {
        const linkClasses: string[] = [];

        this.links.forEach((link) => linkClasses.push(link.type));
        return [...new Set(linkClasses)].map((c) => String(c));
    }

    public getNodeClasses(): string[] {
        const nodeClasses: string[] = [];
        this.nodes.forEach((node) => nodeClasses.push(node.type));
        return [...new Set(nodeClasses)].map((c) => String(c));
    }
        nodeTypes: Map<string, boolean>,
        linkTypes?: Map<string, boolean>
        let links;
        if (linkTypes === undefined) {
            links = this.links;
        } else {
            links = this.links.filter((l) => linkTypes.get(l.type));
        }
        return new Graph(
            this.nodes.filter((l) => nodeTypes.get(l.type)),
            links.map((link) => {
                return {
                    source: link.source.id,
                    target: link.target.id,
                    type: link.type,
                };
            })