Skip to content
Snippets Groups Projects
graph.js 6.32 KiB
Newer Older
  • Learn to ignore specific revisions
  • Maximilian Giller's avatar
    Maximilian Giller committed
    const NODE_LABEL = "name";
    const NODE_ID = "id";
    const NODE_GROUP = "group";
    const NODE_DESCRIPTION = "description";
    const NODE_IMAGE = "image";
    
    const LINK_SOURCE = "source";
    const LINK_TARGET = "target";
    const LINK_TYPE = "type";
    const LINK_PARTICLE_COUNT = 4;
    
    const GRAPH_NODES = "nodes";
    const GRAPH_LINKS = "links";
    
    const IMAGE_SIZE = 12;
    
    const IMAGE_SRC = PLUGIN_PATH + "datasets/images/";
    
    Maximilian Giller's avatar
    Maximilian Giller committed
    
    const LINK_PARAMS = [LINK_TYPE];
    const NODE_PARAMS = [NODE_ID, NODE_LABEL, NODE_IMAGE, NODE_DESCRIPTION];
    
    const JSON_CONFIG = PLUGIN_PATH + "datasets/aud1.json";
    
    const STOP_PHYSICS_DELAY = 5000; // ms
    
    const graph = {
        data: undefined,
    
        externUpdate: [],   // Register callbacks in this list
    
    
        update() {
            graph.externUpdate.forEach((fn) => fn());
        },
    
    Maximilian Giller's avatar
    Maximilian Giller committed
    
        deleteNode(nodeId) {
            // Delete node from nodes
            graph.data[GRAPH_NODES] = graph.data[GRAPH_NODES].filter(
                (n) => n[NODE_ID] !== nodeId
            );
    
            // Delete links with node
            graph.data[GRAPH_LINKS] = graph.data[GRAPH_LINKS].filter(
                (l) =>
                    l[LINK_SOURCE][NODE_ID] !== nodeId &&
                    l[LINK_TARGET][NODE_ID] !== nodeId
            );
        },
    
        stopPhysics() {
            graph.data[GRAPH_NODES].forEach((n) => {
                n.fx = n.x;
                n.fy = n.y;
            });
        },
    
        addIdentifiers() {
            graph.data[GRAPH_NODES].forEach((n) => {
                n.node = true;
                n.link = false;
            });
            graph.data[GRAPH_LINKS].forEach((l) => {
                l.node = false;
                l.link = true;
            });
        },
    
        deleteLink(sourceId, targetId) {
            // Only keep links, of one of the nodes is different
            graph.data[GRAPH_LINKS] = graph.data[GRAPH_LINKS].filter(
                (l) =>
                    l[LINK_SOURCE][NODE_ID] !== sourceId ||
                    l[LINK_TARGET][NODE_ID] !== targetId
            );
        },
    
        isLinkOnNode(link, node) {
            if (link === undefined || node === undefined) {
                return false;
            }
    
            if (link.link !== true || node.node !== true) {
                return false;
            }
    
            return (
                link[LINK_SOURCE][NODE_ID] === node[NODE_ID] ||
                link[LINK_TARGET][NODE_ID] === node[NODE_ID]
            );
        },
    
        existsLink(sourceId, targetId) {
            const links = graph.data[GRAPH_LINKS];
    
            for (var i = 0; i < links.length; i++) {
                var link = links[i];
                if (
                    link[LINK_SOURCE][NODE_ID] === sourceId &&
                    link[LINK_TARGET][NODE_ID] === targetId
                ) {
                    return true;
                }
            }
    
            return false;
        },
    
        connectNodes(sourceId, targetIds) {
            targetIds.forEach((targetId) => {
                if (
                    graph.existsLink(sourceId, targetId) ||
                    graph.existsLink(targetId, sourceId)
                ) {
                    return;
                }
    
                var link = {};
    
                link[LINK_SOURCE] = sourceId;
                link[LINK_TARGET] = targetId;
    
                graph.data[GRAPH_LINKS].push(link);
            });
        },
    
        getCleanData() {
            var cleanData = {};
            cleanData[GRAPH_LINKS] = [];
            cleanData[GRAPH_NODES] = [];
    
            graph.data[GRAPH_LINKS].forEach((link) =>
                cleanData[GRAPH_LINKS].push(graph.getCleanLink(link))
            );
    
            graph.data[GRAPH_NODES].forEach((node) =>
                cleanData[GRAPH_NODES].push(graph.getCleanNode(node))
            );
    
            console.log(cleanData);
            return cleanData;
        },
    
        getCleanNode(node) {
            var cleanNode = {};
    
            NODE_PARAMS.forEach((param) => {
                cleanNode[param] = node[param];
            });
    
            return cleanNode;
        },
    
        getCleanLink(link) {
            var cleanLink = {};
    
            // Source and target nodes
            // Node ids will be converted to complete node objects on running graphs, gotta convert back
            cleanLink[LINK_SOURCE] = link[LINK_SOURCE][NODE_ID];
            cleanLink[LINK_TARGET] = link[LINK_TARGET][NODE_ID];
    
            // Other parameters
            LINK_PARAMS.forEach((param) => {
                cleanLink[param] = link[param];
            });
    
            return cleanLink;
        },
    
    
        existsNodeId(nodeId) {
            var nodes = graph.data[GRAPH_NODES];
            for (var i = 0; i < nodes.length; i++) {
                if (nodes[i][NODE_ID] === nodeId) {
                    return true;
                }
            }
            return false;
        },
    
        getUnusedNodeId() {
            var id;
            do {
                id = graph.getRandomString();
            } while (graph.existsNodeId(id));
            return id;
        },
    
        getRandomString(length = 8) {
            // Based on: https://stackoverflow.com/a/1349426/7376120
            var characters =
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            var charactersLength = characters.length;
    
            var result = "";
            for (var i = 0; i < length; i++) {
                result += characters.charAt(
                    Math.floor(Math.random() * charactersLength)
                );
            }
            return result;
        },
    
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        addLink(sourceId, targetId, linkDetails = {}) {
            // Copy params
            var newLink = linkDetails;
    
            // Make sure the IDs exist
            if (
                sourceId === undefined ||
                targetId === undefined ||
                graph.existsNodeId(sourceId) === false ||
                graph.existsNodeId(targetId) === false
            ) {
                return;
            }
    
    
            // Make sure the link is unique
            if (graph.existsLink(sourceId, targetId)) {
                return;
            }
    
            newLink[LINK_SOURCE] = sourceId;
            newLink[LINK_TARGET] = targetId;
    
            // Basic node properties
            newLink.link = true;
            newLink.node = false;
    
            // Add node
            graph.data[GRAPH_LINKS].push(newLink);
            graph.update();
    
            return newLink;
        },
    
    
        addNode(nodeDetails) {
            // Copy params
            var newNode = nodeDetails;
    
            // Make sure the ID is set and unique
            if (newNode[NODE_ID] === undefined) {
                newNode[NODE_ID] = graph.getUnusedNodeId();
            } else if (graph.existsNodeId(newNode[NODE_ID])) {
                return;
            }
    
            // Basic node properties
            newNode.node = true;
            newNode.link = false;
    
            // Add node
            graph.data[GRAPH_NODES].push(newNode);
            graph.update();
    
            return newNode;
        },
    
    Maximilian Giller's avatar
    Maximilian Giller committed
    };