const TOOLS = { select: new SelectTool("select"), collect: new CollectTool("collect"), delete: new DeleteTool("delete"), addnode: new AddNodeTool("addnode"), connect: new ConnectTool("connect"), }; const CONTEXT = { node: "node", link: "link", mixed: "mixed", }; class State extends Tool { 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) { return; } this.tool.onToolDeactivate(tool); this.previousTool = this.tool; this.tool = tool; this.display.setSelectedTool(tool); this.tool.onToolActivate(); } 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); } 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) { 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[NODE_IMAGE] !== undefined) { var path = IMAGE_SRC + node[NODE_IMAGE]; var img = new Image(); img.src = path; ctx.drawImage( img, node.x - IMAGE_SIZE / 2, node.y - IMAGE_SIZE / 2, IMAGE_SIZE, IMAGE_SIZE ); } // 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 - IMAGE_SIZE / 2, node.y - IMAGE_SIZE / 2, IMAGE_SIZE, IMAGE_SIZE ); // 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) ? LINK_PARTICLE_COUNT : 0; } onBackgroundClick(event, positions) { this.tool.onBackgroundClick(event, positions); } 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, state.selectedItem) ); } }