Skip to content
Snippets Groups Projects
state.js 6.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • import Tool from "./tools/tool";
    import UndoTool from "./tools/undotool";
    import RedoTool from "./tools/redotool";
    import SelectTool from "./tools/selecttool";
    import CollectTool from "./tools/collecttool";
    import DeleteTool from "./tools/deletetool";
    import AddNodeTool from "./tools/addnodetool";
    import ConnectTool from "./tools/connecttool";
    import { graph } from "./editor";
    import Display from "./display";
    import * as Graph from "./graph";
    
    export const TOOLS = {
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        undo: new UndoTool("undo"),
        redo: new RedoTool("redo"),
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        select: new SelectTool("select"),
        collect: new CollectTool("collect"),
        delete: new DeleteTool("delete"),
    
        addnode: new AddNodeTool("addnode"),
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        connect: new ConnectTool("connect"),
    
    Maximilian Giller's avatar
    Maximilian Giller committed
    };
    
    
    export const CONTEXT = {
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        node: "node",
        link: "link",
        mixed: "mixed",
    };
    
    
    export class State extends Tool {
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        constructor() {
            super("State");
    
            this.display = new Display(TOOLS);
    
            this.tool = undefined;
            this.setTool(TOOLS.select);
    
            // Shared variables
            this.selectedItem = undefined;
            this.selectedItems = new Set();
            this.itemsContext = undefined;
    
            this.keyStates = {};
        }
    
        setTool(tool) {
    
            if (this.tool === tool) {
    
    Maximilian Giller's avatar
    Maximilian Giller committed
                return;
            }
    
    
    Maximilian Giller's avatar
    Maximilian Giller committed
            if (this.tool !== undefined) {
    
                this.tool.deactivateTool(tool);
    
    Maximilian Giller's avatar
    Maximilian Giller committed
            this.previousTool = this.tool;
            this.tool = tool;
            this.display.setSelectedTool(tool);
    
    Maximilian Giller's avatar
    Maximilian Giller committed
            if (this.tool !== undefined) {
    
                this.tool.activateTool();
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        }
    
        setSelectedItem(item) {
            this.selectedItem = item;
            this.display.setSelectedItem(item);
        }
    
        addSelectedItem(item) {
            this.selectedItems.add(item);
            this.display.setSelectedItems(this.selectedItems, this.itemsContext);
        }
    
        removeSelectedItem(item) {
            this.selectedItems.delete(item);
            this.display.setSelectedItems(this.selectedItems, this.itemsContext);
        }
    
        clearSelectedItems() {
            this.selectedItems.clear();
            this.itemsContext = undefined;
            this.display.setSelectedItems(this.selectedItems, this.itemsContext);
        }
    
        onNodeClick(node) {
            this.tool.onNodeClick(node);
        }
    
        onLinkClick(link) {
            this.tool.onLinkClick(link);
        }
    
    
        linkColor(link) {
            return graph.getLinkColor(link);
        }
    
        nodeColor(node) {
            return 'lightblue';
        }
    
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        onKeyDown(key) {
            var id = this.getKeyId(key);
            var previous = this.keyStates[id];
    
            this.keyStates[id] = true;
    
            if (previous !== true) {
                this.tool.onKeyDown(key);
            }
        }
    
        onKeyUp(key) {
            var id = this.getKeyId(key);
            var previous = this.keyStates[id];
    
            this.keyStates[id] = false;
    
            if (previous !== false) {
                this.tool.onKeyUp(key);
            }
        }
    
        getKeyId(key) {
            return key.keyCode;
        }
    
    
        nodeCanvasObject(node, ctx, globalScale) {
    
    Maximilian Giller's avatar
    Maximilian Giller committed
            var toolValue = this.tool.nodeCanvasObject(node, ctx);
    
            if (toolValue !== undefined) {
                return toolValue;
            }
    
            // TODO: Clean up function
    
            // add ring just for highlighted nodes
            if (this.selectedItem === node || this.selectedItems.has(node)) {
                ctx.beginPath();
                ctx.arc(node.x, node.y, 5 * 1.4, 0, 2 * Math.PI, false);
                ctx.fillStyle = this.selectedItem === node ? "red" : "green";
                ctx.fill();
            }
    
            // Draw image
    
            if (node[Graph.NODE_IMAGE] !== undefined) {
                var path = Graph.IMAGE_SRC + node[Graph.NODE_IMAGE];
    
    Maximilian Giller's avatar
    Maximilian Giller committed
                var img = new Image();
                img.src = path;
    
                ctx.drawImage(
                    img,
    
                    node.x - Graph.IMAGE_SIZE / 2,
                    node.y - Graph.IMAGE_SIZE / 2,
                    Graph.IMAGE_SIZE,
                    Graph.IMAGE_SIZE
    
            // Draw label
            const label = node[Graph.NODE_LABEL];
            const fontSize = 11/globalScale;
            ctx.font = `${fontSize}px Sans-Serif`;
            const textWidth = ctx.measureText(label).width;
            const bckgDimensions = [textWidth, fontSize].map(n => n + fontSize * 0.2); // some padding
    
            const nodeHeightOffset = Graph.IMAGE_SIZE / 3 + bckgDimensions[1];
            ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
            ctx.fillRect(node.x - bckgDimensions[0] / 2, node.y - bckgDimensions[1] / 2 + nodeHeightOffset, ...bckgDimensions);
    
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillStyle = 'white';
            ctx.fillText(label, node.x, node.y + nodeHeightOffset);
    
    
    Maximilian Giller's avatar
    Maximilian Giller committed
            // TODO: Render label as always visible
        }
    
        nodePointerAreaPaint(node, color, ctx) {
            var toolValue = this.tool.nodePointerAreaPaint(node, color, ctx);
    
            if (toolValue !== undefined) {
                return toolValue;
            }
    
            ctx.fillStyle = color;
            ctx.fillRect(
    
                node.x - Graph.IMAGE_SIZE / 2,
                node.y - Graph.IMAGE_SIZE / 2,
                Graph.IMAGE_SIZE,
                Graph.IMAGE_SIZE
    
    Maximilian Giller's avatar
    Maximilian Giller committed
            ); // draw square as pointer trap
        }
    
        nodeCanvasObjectMode(node) {
            var toolValue = this.tool.nodeCanvasObjectMode(node);
    
            if (toolValue !== undefined) {
                return toolValue;
            }
    
            return "after";
        }
    
        linkWidth(link) {
            var toolValue = this.tool.linkWidth(link);
    
            if (toolValue !== undefined) {
                return toolValue;
            }
    
            return this.isLinkHighlighted(link) ? 5 : 1;
        }
    
        linkDirectionalParticles() {
            var toolValue = this.tool.linkDirectionalParticles();
    
            if (toolValue !== undefined) {
                return toolValue;
            }
    
            return 4;
        }
    
        linkDirectionalParticleWidth(link) {
            var toolValue = this.tool.linkDirectionalParticleWidth(link);
    
            if (toolValue !== undefined) {
                return toolValue;
            }
    
    
            return this.isLinkHighlighted(link) ? Graph.LINK_PARTICLE_COUNT : 0;
    
        onBackgroundClick(event, positions) {
            this.tool.onBackgroundClick(event, positions);
        }
    
    
    Maximilian Giller's avatar
    Maximilian Giller committed
        redraw() {
            this.display.setSelectedTool(this.tool);
            this.display.setSelectedItem(this.selectedItem);
            this.display.setSelectedItems(this.selectedItems, this.itemsContext);
        }
    
        isLinkHighlighted(link) {
            return (
                this.selectedItem === link ||
    
                graph.isLinkOnNode(link, this.selectedItem)