Skip to content
Snippets Groups Projects
graph.ts 3.38 KiB
Newer Older
import { Link } from "../common/graph/link";
import { NodeType, NodeTypeData } from "../common/graph/nodetype";
Matthias Konitzny's avatar
Matthias Konitzny committed
import { Node, NodeData, SimNodeData } from "../common/graph/node";
import * as Common from "../common/graph/graph";
import { History } from "../common/history";
import { GraphContent, GraphData, SimGraphData } from "../common/graph/graph";

export class DynamicGraph extends Common.Graph {
    public history: History<SimGraphData>;

    constructor(data?: GraphContent) {
        super(data);
        if (data != undefined) {
            this.history = new History<SimGraphData>(
                this,
                20,
                "Created new graph."
            );
        }
    }

    public fromSerializedObject(data: GraphData | SimGraphData): DynamicGraph {
        super.fromSerializedObject(data);
        this.history = new History<SimGraphData>(
            this,
            20,
            "Created new graph."
        );

        return this;
    public createObjectGroup(data?: NodeTypeData): NodeType {
        if (data == undefined) {
            data = {
                id: 0,
                name: "Unnamed",
                color: "#000000",
            };
        return super.createObjectGroup(data);
Matthias Konitzny's avatar
Matthias Konitzny committed
    public createNode(
        data?: NodeData | SimNodeData,
        x?: number,
        y?: number,
        vx?: number,
        vy?: number
    ): Node {
        if (data == undefined) {
            data = {
                id: 0,
                name: "Undefined",
                type: this.objectGroups[0].id,
Matthias Konitzny's avatar
Matthias Konitzny committed
                x: x,
                y: y,
                vx: vx,
                vy: vy,
            };
        }
        return super.createNode(data);
    }

    getLink(
        sourceId: number,
        targetId: number,
        directionSensitive = true
    ): Link {
        return this.links.find((l) => {
            if (l.sourceId === sourceId && l.targetId === targetId) {
                return true;
            }

            // Check other direction if allowed
            return (
                !directionSensitive &&
                l.sourceId === targetId &&
                l.targetId === sourceId
            );
        });
    }

    public createLink(source: number, target: number): Link {
        const link = this.getLink(source, target, false);
        if (link !== undefined) {
            return link; // Already exists in graph.
        }

        return super.createLink(source, target);
    }

    /**
Matthias Konitzny's avatar
Matthias Konitzny committed
     * Goes over all nodes and finds the closest node based on distance.
     * @returns Closest node and distance. Undefined, if no closest node can be found.
     */
Matthias Konitzny's avatar
Matthias Konitzny committed
    public getClosestNode(
        x: number,
        y: number,
        exclude?: Node
    ): {
        node: Node;
        distance: number;
    } {
        // Iterate over all nodes, keep the one with the shortest distance
        let closestDistance = Number.MAX_VALUE;
        let closestNode: Node = undefined;
        this.nodes.forEach((node) => {
Matthias Konitzny's avatar
Matthias Konitzny committed
            if (node.equals(exclude)) {
Matthias Konitzny's avatar
Matthias Konitzny committed
            const currentDistance = Math.hypot(x - node.x, y - node.y);

            if (closestDistance > currentDistance) {
                closestDistance = currentDistance;
                closestNode = node;
            }
        });

        return { node: closestNode, distance: closestDistance };
    }
}