From 0129ea747088c1a43f5eb20d2ebcfd1879489f82 Mon Sep 17 00:00:00 2001 From: tamat Date: Fri, 2 Oct 2015 19:39:17 +0200 Subject: [PATCH] improved support for webgl --- build/litegraph.js | 535 ++++++++++++++++++++--------- build/litegraph.min.js | 71 ++-- demo/index.html | 1 + doc/classes/LGraph.html | 14 +- doc/classes/LGraphCanvas.html | 18 +- doc/classes/LGraphNode.html | 60 ++-- doc/data.json | 90 ++--- doc/files/.._src_litegraph.js.html | 401 ++++++++++++--------- src/litegraph.js | 401 ++++++++++++--------- src/nodes/base.js | 2 +- src/nodes/input.js | 132 +++++++ utils/deploy_files.txt | 1 + 12 files changed, 1132 insertions(+), 594 deletions(-) create mode 100644 src/nodes/input.js diff --git a/build/litegraph.js b/build/litegraph.js index 883837df2..7d49fd8ab 100644 --- a/build/litegraph.js +++ b/build/litegraph.js @@ -746,9 +746,10 @@ LGraph.prototype.findNodesByClass = function(classObject) LGraph.prototype.findNodesByType = function(type) { + var type = type.toLowerCase(); var r = []; for(var i in this._nodes) - if(this._nodes[i].type == type) + if(this._nodes[i].type.toLowerCase() == type ) r.push(this._nodes[i]); return r; } @@ -852,7 +853,7 @@ LGraph.prototype.changeGlobalInputType = function(name, type) if(!this.global_inputs[name]) return false; - if(this.global_inputs[name].type == type) + if(this.global_inputs[name].type.toLowerCase() == type.toLowerCase() ) return; this.global_inputs[name].type = type; @@ -933,7 +934,7 @@ LGraph.prototype.changeGlobalOutputType = function(name, type) if(!this.global_outputs[name]) return false; - if(this.global_outputs[name].type == type) + if(this.global_outputs[name].type.toLowerCase() == type.toLowerCase() ) return; this.global_outputs[name].type = type; @@ -1725,7 +1726,7 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) } else if( !output.type || //generic output !node.inputs[target_slot].type || //generic input - output.type == node.inputs[target_slot].type) //same type + output.type.toLowerCase() == node.inputs[target_slot].type.toLowerCase() ) //same type { //info: link structure => [ 0:link_id, 1:start_node_id, 2:start_slot, 3:end_node_id, 4:end_slot ] //var link = [ this.graph.last_link_id++, this.id, slot, node.id, target_slot ]; @@ -2045,16 +2046,13 @@ LGraphNode.prototype.localToScreen = function(x,y, graphcanvas) * @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format or the canvas itself) * @param {LGraph} graph [optional] */ -function LGraphCanvas(canvas, graph, skip_render) +function LGraphCanvas( canvas, graph, skip_render ) { //if(graph === undefined) // throw ("No graph assigned"); - if(typeof(canvas) == "string") - canvas = document.querySelector(canvas); - - if(!canvas) - throw("no canvas found"); + if(canvas && canvas.constructor === String ) + canvas = document.querySelector( canvas ); this.max_zoom = 10; this.min_zoom = 0.1; @@ -2063,7 +2061,7 @@ function LGraphCanvas(canvas, graph, skip_render) if(graph) graph.attachCanvas(this); - this.setCanvas(canvas); + this.setCanvas( canvas ); this.clear(); if(!skip_render) @@ -2098,9 +2096,7 @@ LGraphCanvas.prototype.clear = function() this.editor_alpha = 1; //used for transition this.pause_rendering = false; this.render_shadows = true; - this.dirty_canvas = true; - this.dirty_bgcanvas = true; - this.dirty_area = null; + this.clear_background = true; this.render_only_selected = true; this.live_mode = false; @@ -2108,6 +2104,10 @@ LGraphCanvas.prototype.clear = function() this.allow_dragcanvas = true; this.allow_dragnodes = true; + this.dirty_canvas = true; + this.dirty_bgcanvas = true; + this.dirty_area = null; + this.node_in_panel = null; this.last_mouse = [0,0]; @@ -2133,10 +2133,13 @@ LGraphCanvas.prototype.clear = function() * @method setGraph * @param {LGraph} graph */ -LGraphCanvas.prototype.setGraph = function(graph) +LGraphCanvas.prototype.setGraph = function( graph, skip_clear ) { - if(this.graph == graph) return; - this.clear(); + if(this.graph == graph) + return; + + if(!skip_clear) + this.clear(); if(!graph && this.graph) { @@ -2203,19 +2206,35 @@ LGraphCanvas.prototype.closeSubgraph = function() * @method setCanvas * @param {Canvas} assigns a canvas */ -LGraphCanvas.prototype.setCanvas = function(canvas) +LGraphCanvas.prototype.setCanvas = function( canvas, skip_events ) { var that = this; - //Canvas association - if(typeof(canvas) == "string") - canvas = document.getElementById(canvas); + if(canvas) + { + if( canvas.constructor === String ) + { + canvas = document.getElementById(canvas); + if(!canvas) + throw("Error creating LiteGraph canvas: Canvas not found"); + } + } - if(canvas == null) - throw("Error creating LiteGraph canvas: Canvas not found"); - if(canvas == this.canvas) return; + if(canvas === this.canvas) + return; + + if(!canvas && this.canvas) + { + //maybe detach events from old_canvas + if(!skip_events) + this.unbindEvents(); + } this.canvas = canvas; + + if(!canvas) + return; + //this.canvas.tabindex = "1000"; canvas.className += " lgraphcanvas"; canvas.data = this; @@ -2245,72 +2264,85 @@ LGraphCanvas.prototype.setCanvas = function(canvas) this._mousemove_callback = this.processMouseMove.bind(this); this._mouseup_callback = this.processMouseUp.bind(this); - canvas.addEventListener("mousedown", this.processMouseDown.bind(this), true ); //down do not need to store the binded - canvas.addEventListener("mousemove", this._mousemove_callback); + if(!skip_events) + this.bindEvents(); +} - canvas.addEventListener("contextmenu", function(e) { e.preventDefault(); return false; }); - - canvas.addEventListener("mousewheel", this.processMouseWheel.bind(this), false); - canvas.addEventListener("DOMMouseScroll", this.processMouseWheel.bind(this), false); +//used in some events to capture them +LGraphCanvas.prototype._doNothing = function doNothing() { return false; }; + +LGraphCanvas.prototype.bindEvents = function() +{ + if( this._events_binded ) + { + console.warn("LGraphCanvas: events already binded"); + return; + } + + var canvas = this.canvas; + + this._mousedown_callback = this.processMouseDown.bind(this); + this._mousewheel_callback = this.processMouseWheel.bind(this); + + canvas.addEventListener("mousedown", this._mousedown_callback, true ); //down do not need to store the binded + canvas.addEventListener("mousemove", this._mousemove_callback ); + canvas.addEventListener("mousewheel", this._mousewheel_callback, false); + + canvas.addEventListener("contextmenu", this._doNothing ); + canvas.addEventListener("DOMMouseScroll", this._mousewheel_callback, false); //touch events //if( 'touchstart' in document.documentElement ) { - //alert("doo"); canvas.addEventListener("touchstart", this.touchHandler, true); canvas.addEventListener("touchmove", this.touchHandler, true); canvas.addEventListener("touchend", this.touchHandler, true); canvas.addEventListener("touchcancel", this.touchHandler, true); } - //this.canvas.onselectstart = function () { return false; }; - canvas.addEventListener("keydown", function(e) { - that.processKeyDown(e); - }); + //Keyboard ****************** + this._key_callback = this.processKey.bind(this); - canvas.addEventListener("keyup", function(e) { - that.processKeyUp(e); - }); + canvas.addEventListener("keydown", this._key_callback ); + canvas.addEventListener("keyup", this._key_callback ); - //droping files - canvas.ondragover = function () { console.log('hover'); return false; }; - canvas.ondragend = function () { console.log('out'); return false; }; - canvas.ondrop = function (e) { - e.preventDefault(); - that.adjustMouseEvent(e); + //Droping Stuff over nodes ************************************ + this._ondrop_callback = this.processDrop.bind(this); - var pos = [e.canvasX,e.canvasY]; - var node = that.graph.getNodeOnPos(pos[0],pos[1]); - if(!node) - return; + canvas.addEventListener("dragover", this._doNothing, false ); + canvas.addEventListener("dragend", this._doNothing, false ); + canvas.addEventListener("drop", this._ondrop_callback, false ); - if(!node.onDropFile) - return; + this._events_binded = true; +} - var file = e.dataTransfer.files[0]; - var filename = file.name; - var ext = LGraphCanvas.getFileExtension( filename ); - //console.log(file); +LGraphCanvas.prototype.unbindEvents = function() +{ + if( !this._events_binded ) + { + console.warn("LGraphCanvas: no events binded"); + return; + } - //prepare reader - var reader = new FileReader(); - reader.onload = function (event) { - //console.log(event.target); - var data = event.target.result; - node.onDropFile( data, filename, file ); - }; + this.canvas.removeEventListener( "mousedown", this._mousedown_callback ); + this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback ); + this.canvas.removeEventListener( "DOMMouseScroll", this._mousewheel_callback ); + this.canvas.removeEventListener( "keydown", this._key_callback ); + this.canvas.removeEventListener( "keyup", this._key_callback ); + this.canvas.removeEventListener( "contextmenu", this._doNothing ); + this.canvas.removeEventListener( "drop", this._ondrop_callback ); - //read data - var type = file.type.split("/")[0]; - if(type == "text" || type == "") - reader.readAsText(file); - else if (type == "image") - reader.readAsDataURL(file); - else - reader.readAsArrayBuffer(file); + this.canvas.removeEventListener("touchstart", this.touchHandler ); + this.canvas.removeEventListener("touchmove", this.touchHandler ); + this.canvas.removeEventListener("touchend", this.touchHandler ); + this.canvas.removeEventListener("touchcancel", this.touchHandler ); - return false; - }; + this._mousedown_callback = null; + this._mousewheel_callback = null; + this._key_callback = null; + this._ondrop_callback = null; + + this._events_binded = false; } LGraphCanvas.getFileExtension = function (url) @@ -2467,13 +2499,15 @@ LGraphCanvas.prototype.stopRendering = function() LGraphCanvas.prototype.processMouseDown = function(e) { - if(!this.graph) return; + if(!this.graph) + return; this.adjustMouseEvent(e); var ref_window = this.getCanvasWindow(); var document = ref_window.document; + //move mouse move event to the window in case it drags outside of the canvas this.canvas.removeEventListener("mousemove", this._mousemove_callback ); ref_window.document.addEventListener("mousemove", this._mousemove_callback, true ); //catch for the entire window ref_window.document.addEventListener("mouseup", this._mouseup_callback, true ); @@ -2699,7 +2733,7 @@ LGraphCanvas.prototype.processMouseMove = function(e) if(slot != -1 && n.inputs[slot]) { var slot_type = n.inputs[slot].type; - if(slot_type == this.connecting_output.type || !slot_type || !this.connecting_output.type ) + if( !this.connecting_output.type || !slot_type || slot_type.toLowerCase() == this.connecting_output.type.toLowerCase() ) this._highlight_input = pos; } else @@ -2774,11 +2808,13 @@ LGraphCanvas.prototype.processMouseMove = function(e) LGraphCanvas.prototype.processMouseUp = function(e) { - if(!this.graph) return; + if(!this.graph) + return; var window = this.getCanvasWindow(); var document = window.document; + //restore the mousemove event back to the canvas document.removeEventListener("mousemove", this._mousemove_callback, true ); this.canvas.addEventListener("mousemove", this._mousemove_callback, true); document.removeEventListener("mouseup", this._mouseup_callback, true ); @@ -2815,7 +2851,7 @@ LGraphCanvas.prototype.processMouseUp = function(e) { //not on top of an input var input = node.getInputInfo(0); //simple connect - if(input && !input.link && input.type == this.connecting_output.type) + if(input && !input.link && input.type == this.connecting_output.type) //toLowerCase missing this.connecting_node.connect(this.connecting_slot, node, 0); } } @@ -2879,75 +2915,11 @@ LGraphCanvas.prototype.processMouseUp = function(e) return false; } -LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_pos) -{ - if(node.inputs) - for(var i = 0, l = node.inputs.length; i < l; ++i) - { - var input = node.inputs[i]; - var link_pos = node.getConnectionPos(true,i); - if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) - { - if(slot_pos) { slot_pos[0] = link_pos[0]; slot_pos[1] = link_pos[1] }; - return i; - } - } - return -1; -} - -LGraphCanvas.prototype.processKeyDown = function(e) -{ - if(!this.graph) return; - var block_default = false; - - //select all Control A - if(e.keyCode == 65 && e.ctrlKey) - { - this.selectAllNodes(); - block_default = true; - } - - //delete or backspace - if(e.keyCode == 46 || e.keyCode == 8) - { - this.deleteSelectedNodes(); - block_default = true; - } - - //collapse - //... - - //TODO - if(this.selected_nodes) - for (var i in this.selected_nodes) - if(this.selected_nodes[i].onKeyDown) - this.selected_nodes[i].onKeyDown(e); - - this.graph.change(); - - if(block_default) - { - e.preventDefault(); - return false; - } -} - -LGraphCanvas.prototype.processKeyUp = function(e) -{ - if(!this.graph) return; - //TODO - if(this.selected_nodes) - for (var i in this.selected_nodes) - if(this.selected_nodes[i].onKeyUp) - this.selected_nodes[i].onKeyUp(e); - - this.graph.change(); -} LGraphCanvas.prototype.processMouseWheel = function(e) { - if(!this.graph) return; - if(!this.allow_dragcanvas) return; + if(!this.graph || !this.allow_dragcanvas) + return; var delta = (e.wheelDeltaY != null ? e.wheelDeltaY : e.detail * -60); @@ -2973,6 +2945,109 @@ LGraphCanvas.prototype.processMouseWheel = function(e) return false; // prevent default } +LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_pos) +{ + if(node.inputs) + for(var i = 0, l = node.inputs.length; i < l; ++i) + { + var input = node.inputs[i]; + var link_pos = node.getConnectionPos(true,i); + if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) + { + if(slot_pos) { slot_pos[0] = link_pos[0]; slot_pos[1] = link_pos[1] }; + return i; + } + } + return -1; +} + +LGraphCanvas.prototype.processKey = function(e) +{ + if(!this.graph) + return; + + var block_default = false; + + if(e.type == "keydown") + { + //select all Control A + if(e.keyCode == 65 && e.ctrlKey) + { + this.selectAllNodes(); + block_default = true; + } + + //delete or backspace + if(e.keyCode == 46 || e.keyCode == 8) + { + this.deleteSelectedNodes(); + block_default = true; + } + + //collapse + //... + + //TODO + if(this.selected_nodes) + for (var i in this.selected_nodes) + if(this.selected_nodes[i].onKeyDown) + this.selected_nodes[i].onKeyDown(e); + } + else if( e.type == "keyup" ) + { + if(this.selected_nodes) + for (var i in this.selected_nodes) + if(this.selected_nodes[i].onKeyUp) + this.selected_nodes[i].onKeyUp(e); + } + + this.graph.change(); + + if(block_default) + { + e.preventDefault(); + return false; + } +} + +LGraphCanvas.prototype.processDrop = function(e) +{ + e.preventDefault(); + this.adjustMouseEvent(e); + + var pos = [e.canvasX,e.canvasY]; + var node = this.graph.getNodeOnPos(pos[0],pos[1]); + if(!node) + return; + + if(!node.onDropFile) + return; + + var file = e.dataTransfer.files[0]; + var filename = file.name; + var ext = LGraphCanvas.getFileExtension( filename ); + //console.log(file); + + //prepare reader + var reader = new FileReader(); + reader.onload = function (event) { + //console.log(event.target); + var data = event.target.result; + node.onDropFile( data, filename, file ); + }; + + //read data + var type = file.type.split("/")[0]; + if(type == "text" || type == "") + reader.readAsText(file); + else if (type == "image") + reader.readAsDataURL(file); + else + reader.readAsArrayBuffer(file); + + return false; +} + LGraphCanvas.prototype.processNodeSelected = function(n,e) { n.selected = true; @@ -3228,7 +3303,8 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //clear //canvas.width = canvas.width; - ctx.clearRect(0,0,canvas.width, canvas.height); + if(this.clear_background) + ctx.clearRect(0,0,canvas.width, canvas.height); //draw bg canvas if(this.bgcanvas == this.canvas) @@ -3242,19 +3318,7 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //info widget if(this.show_info) - { - ctx.font = "10px Arial"; - ctx.fillStyle = "#888"; - if(this.graph) - { - ctx.fillText( "T: " + this.graph.globaltime.toFixed(2)+"s",5,13*1 ); - ctx.fillText( "I: " + this.graph.iteration,5,13*2 ); - ctx.fillText( "F: " + this.frame,5,13*3 ); - ctx.fillText( "FPS:" + this.fps.toFixed(2),5,13*4 ); - } - else - ctx.fillText( "No graph selected",5,13*1 ); - } + this.renderInfo(ctx); if(this.graph) { @@ -3329,6 +3393,28 @@ LGraphCanvas.prototype.drawFrontCanvas = function() this.dirty_canvas = false; } +LGraphCanvas.prototype.renderInfo = function( ctx, x, y ) +{ + x = x || 0; + y = y || 0; + + ctx.save(); + ctx.translate( x, y ); + + ctx.font = "10px Arial"; + ctx.fillStyle = "#888"; + if(this.graph) + { + ctx.fillText( "T: " + this.graph.globaltime.toFixed(2)+"s",5,13*1 ); + ctx.fillText( "I: " + this.graph.iteration,5,13*2 ); + ctx.fillText( "F: " + this.frame,5,13*3 ); + ctx.fillText( "FPS:" + this.fps.toFixed(2),5,13*4 ); + } + else + ctx.fillText( "No graph selected",5,13*1 ); + ctx.restore(); +} + LGraphCanvas.prototype.drawBackCanvas = function() { var canvas = this.bgcanvas; @@ -3339,7 +3425,8 @@ LGraphCanvas.prototype.drawBackCanvas = function() ctx.start(); //clear - ctx.clearRect(0,0,canvas.width, canvas.height); + if(this.clear_background) + ctx.clearRect(0,0,canvas.width, canvas.height); //reset in case of error ctx.restore(); @@ -3540,7 +3627,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx ) var slot = node.inputs[i]; ctx.globalAlpha = editor_alpha; - if (this.connecting_node != null && this.connecting_output.type != 0 && node.inputs[i].type != 0 && this.connecting_output.type != node.inputs[i].type) + if (this.connecting_node != null && this.connecting_output.type && node.inputs[i].type && this.connecting_output.type.toLowerCase() != node.inputs[i].type.toLowerCase() ) ctx.globalAlpha = 0.4 * editor_alpha; ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA"; @@ -4788,7 +4875,7 @@ Subgraph.prototype.clone = function() } -LiteGraph.registerNodeType("graph/subgraph", Subgraph); +LiteGraph.registerNodeType("graph/subgraph", Subgraph ); //Input for a subgraph @@ -5738,6 +5825,138 @@ LiteGraph.registerNodeType("basic/console", Console ); })(); (function(){ +function GamepadInput() +{ + this.addOutput("left_x_axis","number"); + this.addOutput("left_y_axis","number"); + this.properties = {}; +} + +GamepadInput.title = "Gamepad"; +GamepadInput.desc = "gets the input of the gamepad"; + +GamepadInput.prototype.onExecute = function() +{ + //get gamepad + var gamepad = this.getGamepad(); + if(!gamepad) + return; + + if(this.outputs) + { + for(var i = 0; i < this.outputs.length; i++) + { + var output = this.outputs[i]; + var v = null; + switch( output.name ) + { + case "left_x_axis": v = gamepad.xbox.axes["lx"]; break; + case "left_y_axis": v = gamepad.xbox.axes["ly"]; break; + case "right_x_axis": v = gamepad.xbox.axes["rx"]; break; + case "right_y_axis": v = gamepad.xbox.axes["ry"]; break; + case "a_button": v = gamepad.xbox.buttons["a"] ? 1 : 0; break; + case "b_button": v = gamepad.xbox.buttons["b"] ? 1 : 0; break; + case "x_button": v = gamepad.xbox.buttons["x"] ? 1 : 0; break; + case "y_button": v = gamepad.xbox.buttons["y"] ? 1 : 0; break; + case "lb_button": v = gamepad.xbox.buttons["lb"] ? 1 : 0; break; + case "rb_button": v = gamepad.xbox.buttons["rb"] ? 1 : 0; break; + case "ls_button": v = gamepad.xbox.buttons["ls"] ? 1 : 0; break; + case "rs_button": v = gamepad.xbox.buttons["rs"] ? 1 : 0; break; + case "start_button": v = gamepad.xbox.buttons["start"] ? 1 : 0; break; + case "back_button": v = gamepad.xbox.buttons["back"] ? 1 : 0; break; + default: break; + } + this.setOutputData(i,v); + } + } +} + +GamepadInput.prototype.getGamepad = function() +{ + var getGamepads = navigator.getGamepads || navigator.webkitGetGamepads || navigator.mozGetGamepads; + if(!getGamepads) + return null; + var gamepads = getGamepads.call(navigator); + var gamepad = null; + + for(var i = 0; i < 4; i++) + { + if (gamepads[i]) + { + gamepad = gamepads[i]; + + //xbox controller mapping + var xbox = this.xbox_mapping; + if(!xbox) + xbox = this.xbox_mapping = { axes:[], buttons:{}, hat: ""}; + + xbox.axes["lx"] = gamepad.axes[0]; + xbox.axes["ly"] = gamepad.axes[1]; + xbox.axes["rx"] = gamepad.axes[2]; + xbox.axes["ry"] = gamepad.axes[3]; + xbox.axes["triggers"] = gamepad.axes[4]; + + for(var i = 0; i < gamepad.buttons.length; i++) + { + //mapping of XBOX + switch(i) //I use a switch to ensure that a player with another gamepad could play + { + case 0: xbox.buttons["a"] = gamepad.buttons[i].pressed; break; + case 1: xbox.buttons["b"] = gamepad.buttons[i].pressed; break; + case 2: xbox.buttons["x"] = gamepad.buttons[i].pressed; break; + case 3: xbox.buttons["y"] = gamepad.buttons[i].pressed; break; + case 4: xbox.buttons["lb"] = gamepad.buttons[i].pressed; break; + case 5: xbox.buttons["rb"] = gamepad.buttons[i].pressed; break; + case 6: xbox.buttons["lt"] = gamepad.buttons[i].pressed; break; + case 7: xbox.buttons["rt"] = gamepad.buttons[i].pressed; break; + case 8: xbox.buttons["back"] = gamepad.buttons[i].pressed; break; + case 9: xbox.buttons["start"] = gamepad.buttons[i].pressed; break; + case 10: xbox.buttons["ls"] = gamepad.buttons[i].pressed; break; + case 11: xbox.buttons["rs"] = gamepad.buttons[i].pressed; break; + case 12: if( gamepad.buttons[i].pressed) xbox.hat += "up"; break; + case 13: if( gamepad.buttons[i].pressed) xbox.hat += "down"; break; + case 14: if( gamepad.buttons[i].pressed) xbox.hat += "left"; break; + case 15: if( gamepad.buttons[i].pressed) xbox.hat += "right"; break; + case 16: xbox.buttons["home"] = gamepad.buttons[i].pressed; break; + default: + } + } + gamepad.xbox = xbox; + return gamepad; + } + } +} + +GamepadInput.prototype.onDrawBackground = function(ctx) +{ + //render +} + +GamepadInput.prototype.onGetOutputs = function() { + return [ + ["left_x_axis","number"], + ["left_y_axis","number"], + ["right_x_axis","number"], + ["right_y_axis","number"], + ["trigger","number"], + ["a_button","number"], + ["b_button","number"], + ["x_button","number"], + ["y_button","number"], + ["lb_button","number"], + ["rb_button","number"], + ["ls_button","number"], + ["rs_button","number"], + ["start","number"], + ["back","number"] + ]; +} + +LiteGraph.registerNodeType("input/gamepad", GamepadInput ); + +})(); +(function(){ + function MathRand() { diff --git a/build/litegraph.min.js b/build/litegraph.min.js index 7c5949528..890311d83 100644 --- a/build/litegraph.min.js +++ b/build/litegraph.min.js @@ -16,13 +16,13 @@ LGraph.prototype.sendEventToAllNodes=function(a,b){var c=this._nodes_in_order?th LGraph.prototype.add=function(a,b){if(a&&(-1==a.id||null==this._nodes_by_id[a.id])){if(this._nodes.length>=LiteGraph.MAX_NUMBER_OF_NODES)throw"LiteGraph: max number of nodes in a graph reached";if(null==a.id||-1==a.id)a.id=this.last_node_id++;a.graph=this;this._nodes.push(a);this._nodes_by_id[a.id]=a;if(a.onAdded)a.onAdded();this.config.align_to_grid&&a.alignToGrid();b||this.updateExecutionOrder();if(this.onNodeAdded)this.onNodeAdded(a);this.setDirtyCanvas(!0);this.change();return a}}; LGraph.prototype.remove=function(a){if(null!=this._nodes_by_id[a.id]&&!a.ignore_remove){if(a.inputs)for(var b=0;ba&&this.pos[1]-cb)return!0;return!1}; LGraphNode.prototype.findInputSlot=function(a){if(!this.inputs)return-1;for(var b=0,c=this.inputs.length;b=this.outputs.length)return LiteGraph.debug&&console.log("Connect: Error, slot number not found"),!1;if(b==this)return!1;if(c.constructor===String){if(c=b.findInputSlot(c),-1==c)return LiteGraph.debug&&console.log("Connect: Error, no slot of name "+c),!1}else if(!b.inputs||c>=b.inputs.length)return LiteGraph.debug&& -console.log("Connect: Error, slot number not found"),!1;-1!=c&&null!=b.inputs[c].link&&b.disconnectInput(c);var d=this.outputs[a];-1==c?(null==d.links&&(d.links=[]),d.links.push({id:b.id,slot:-1})):d.type&&b.inputs[c].type&&d.type!=b.inputs[c].type||(a={id:this.graph.last_link_id++,origin_id:this.id,origin_slot:a,target_id:b.id,target_slot:c},this.graph.links[a.id]=a,null==d.links&&(d.links=[]),d.links.push(a.id),b.inputs[c].link=a.id,this.setDirtyCanvas(!1,!0),this.graph.onConnectionChange());return!0}; +console.log("Connect: Error, slot number not found"),!1;-1!=c&&null!=b.inputs[c].link&&b.disconnectInput(c);var d=this.outputs[a];-1==c?(null==d.links&&(d.links=[]),d.links.push({id:b.id,slot:-1})):d.type&&b.inputs[c].type&&d.type.toLowerCase()!=b.inputs[c].type.toLowerCase()||(a={id:this.graph.last_link_id++,origin_id:this.id,origin_slot:a,target_id:b.id,target_slot:c},this.graph.links[a.id]=a,null==d.links&&(d.links=[]),d.links.push(a.id),b.inputs[c].link=a.id,this.setDirtyCanvas(!1,!0),this.graph.onConnectionChange()); +return!0}; LGraphNode.prototype.disconnectOutput=function(a,b){if(a.constructor===String){if(a=this.findOutputSlot(a),-1==a)return LiteGraph.debug&&console.log("Connect: Error, no slot of name "+a),!1}else if(!this.outputs||a>=this.outputs.length)return LiteGraph.debug&&console.log("Connect: Error, slot number not found"),!1;var c=this.outputs[a];if(!c.links||0==c.links.length)return!1;if(b)for(var d=0,e=c.links.length;d=this.inputs.length)return LiteGraph.debug&&console.log("Connect: Error, slot number not found"),!1;if(!this.inputs[a])return!1;var b=this.inputs[a].link;this.inputs[a].link=null;b=this.graph.links[b];a=this.graph.getNodeById(b.origin_id);if(!a)return!1;a=a.outputs[b.origin_slot];if(!a||!a.links|| @@ -53,14 +54,17 @@ a?[this.pos[0],this.pos[1]+10+b*LiteGraph.NODE_SLOT_HEIGHT]:[this.pos[0]+this.si LGraphNode.prototype.trace=function(a){this.console||(this.console=[]);this.console.push(a);this.console.length>LGraphNode.MAX_CONSOLE&&this.console.shift();this.graph.onNodeTrace(this,a)};LGraphNode.prototype.setDirtyCanvas=function(a,b){this.graph&&this.graph.sendActionToCanvas("setDirty",[a,b])};LGraphNode.prototype.loadImage=function(a){var b=new Image;b.src=LiteGraph.node_images_path+a;b.ready=!1;var c=this;b.onload=function(){this.ready=!0;c.setDirtyCanvas(!0)};return b}; LGraphNode.prototype.executeAction=function(a){if(""==a)return!1;if(-1!=a.indexOf(";")||-1!=a.indexOf("}"))return this.trace("Error: Action contains unsafe characters"),!1;var b=a.split("(")[0];if("function"!=typeof this[b])return this.trace("Error: Action not found on node: "+b),!1;try{b=eval,eval=null,(new Function("with(this) { "+a+"}")).call(this),eval=b}catch(c){return this.trace("Error executing action {"+a+"} :"+c),!1}return!0}; LGraphNode.prototype.captureInput=function(a){if(this.graph&&this.graph.list_of_graphcanvas){var b=this.graph.list_of_graphcanvas,c;for(c in b){var d=b[c];if(a||d.node_capturing_input==this)d.node_capturing_input=a?this:null}}};LGraphNode.prototype.collapse=function(){this.flags.collapsed=this.flags.collapsed?!1:!0;this.setDirtyCanvas(!0,!0)};LGraphNode.prototype.pin=function(a){this.flags.pinned=void 0===a?!this.flags.pinned:a}; -LGraphNode.prototype.localToScreen=function(a,b,c){return[(a+this.pos[0])*c.scale+c.offset[0],(b+this.pos[1])*c.scale+c.offset[1]]};function LGraphCanvas(a,b,c){"string"==typeof a&&(a=document.querySelector(a));if(!a)throw"no canvas found";this.max_zoom=10;this.min_zoom=0.1;b&&b.attachCanvas(this);this.setCanvas(a);this.clear();c||this.startRendering()}LGraphCanvas.link_type_colors={number:"#AAC",node:"#DCA"}; -LGraphCanvas.prototype.clear=function(){this.fps=this.render_time=this.last_draw_time=this.frame=0;this.scale=1;this.offset=[0,0];this.selected_nodes={};this.connecting_node=this.node_capturing_input=this.node_over=this.node_dragged=null;this.highquality_render=!0;this.editor_alpha=1;this.pause_rendering=!1;this.dirty_bgcanvas=this.dirty_canvas=this.render_shadows=!0;this.dirty_area=null;this.render_only_selected=!0;this.live_mode=!1;this.allow_dragnodes=this.allow_dragcanvas=this.show_info=!0;this.node_in_panel= -null;this.last_mouse=[0,0];this.last_mouseclick=0;this.title_text_font="bold 14px Arial";this.inner_text_font="normal 12px Arial";this.render_connections_shadows=!1;this.render_connection_arrows=this.render_curved_connections=this.render_connections_border=!0;this.connections_width=4;if(this.onClear)this.onClear()};LGraphCanvas.prototype.setGraph=function(a){this.graph!=a&&(this.clear(),!a&&this.graph?this.graph.detachCanvas(this):(a.attachCanvas(this),this.setDirty(!0,!0)))}; +LGraphNode.prototype.localToScreen=function(a,b,c){return[(a+this.pos[0])*c.scale+c.offset[0],(b+this.pos[1])*c.scale+c.offset[1]]};function LGraphCanvas(a,b,c){a&&a.constructor===String&&(a=document.querySelector(a));this.max_zoom=10;this.min_zoom=0.1;b&&b.attachCanvas(this);this.setCanvas(a);this.clear();c||this.startRendering()}LGraphCanvas.link_type_colors={number:"#AAC",node:"#DCA"}; +LGraphCanvas.prototype.clear=function(){this.fps=this.render_time=this.last_draw_time=this.frame=0;this.scale=1;this.offset=[0,0];this.selected_nodes={};this.connecting_node=this.node_capturing_input=this.node_over=this.node_dragged=null;this.highquality_render=!0;this.editor_alpha=1;this.pause_rendering=!1;this.render_only_selected=this.clear_background=this.render_shadows=!0;this.live_mode=!1;this.dirty_bgcanvas=this.dirty_canvas=this.allow_dragnodes=this.allow_dragcanvas=this.show_info=!0;this.node_in_panel= +this.dirty_area=null;this.last_mouse=[0,0];this.last_mouseclick=0;this.title_text_font="bold 14px Arial";this.inner_text_font="normal 12px Arial";this.render_connections_shadows=!1;this.render_connection_arrows=this.render_curved_connections=this.render_connections_border=!0;this.connections_width=4;if(this.onClear)this.onClear()};LGraphCanvas.prototype.setGraph=function(a,b){this.graph!=a&&(b||this.clear(),!a&&this.graph?this.graph.detachCanvas(this):(a.attachCanvas(this),this.setDirty(!0,!0)))}; LGraphCanvas.prototype.openSubgraph=function(a){if(!a)throw"graph cannot be null";if(this.graph==a)throw"graph cannot be the same";this.clear();this.graph&&(this._graph_stack||(this._graph_stack=[]),this._graph_stack.push(this.graph));a.attachCanvas(this);this.setDirty(!0,!0)};LGraphCanvas.prototype.closeSubgraph=function(){this._graph_stack&&0!=this._graph_stack.length&&(this._graph_stack.pop().attachCanvas(this),this.setDirty(!0,!0))}; -LGraphCanvas.prototype.setCanvas=function(a){var b=this;"string"==typeof a&&(a=document.getElementById(a));if(null==a)throw"Error creating LiteGraph canvas: Canvas not found";if(a!=this.canvas){this.canvas=a;a.className+=" lgraphcanvas";a.data=this;this.bgcanvas=null;this.bgcanvas||(this.bgcanvas=document.createElement("canvas"),this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height);if(null==a.getContext)throw"This browser doesnt support Canvas";null==(this.ctx=a.getContext("2d"))&& -(console.warn("This canvas seems to be WebGL, enabling WebGL renderer"),this.enableWebGL());this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);a.addEventListener("mousedown",this.processMouseDown.bind(this),!0);a.addEventListener("mousemove",this._mousemove_callback);a.addEventListener("contextmenu",function(a){a.preventDefault();return!1});a.addEventListener("mousewheel",this.processMouseWheel.bind(this),!1);a.addEventListener("DOMMouseScroll", -this.processMouseWheel.bind(this),!1);a.addEventListener("touchstart",this.touchHandler,!0);a.addEventListener("touchmove",this.touchHandler,!0);a.addEventListener("touchend",this.touchHandler,!0);a.addEventListener("touchcancel",this.touchHandler,!0);a.addEventListener("keydown",function(a){b.processKeyDown(a)});a.addEventListener("keyup",function(a){b.processKeyUp(a)});a.ondragover=function(){console.log("hover");return!1};a.ondragend=function(){console.log("out");return!1};a.ondrop=function(a){a.preventDefault(); -b.adjustMouseEvent(a);var d=[a.canvasX,a.canvasY],e=b.graph.getNodeOnPos(d[0],d[1]);if(e&&e.onDropFile){var f=a.dataTransfer.files[0],g=f.name;LGraphCanvas.getFileExtension(g);a=new FileReader;a.onload=function(a){e.onDropFile(a.target.result,g,f)};d=f.type.split("/")[0];"text"==d||""==d?a.readAsText(f):"image"==d?a.readAsDataURL(f):a.readAsArrayBuffer(f);return!1}}}}; +LGraphCanvas.prototype.setCanvas=function(a,b){if(a&&a.constructor===String&&(a=document.getElementById(a),!a))throw"Error creating LiteGraph canvas: Canvas not found";if(a!==this.canvas&&(!a&&this.canvas&&(b||this.unbindEvents()),this.canvas=a)){a.className+=" lgraphcanvas";a.data=this;this.bgcanvas=null;this.bgcanvas||(this.bgcanvas=document.createElement("canvas"),this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height);if(null==a.getContext)throw"This browser doesnt support Canvas"; +null==(this.ctx=a.getContext("2d"))&&(console.warn("This canvas seems to be WebGL, enabling WebGL renderer"),this.enableWebGL());this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);b||this.bindEvents()}};LGraphCanvas.prototype._doNothing=function(){return!1}; +LGraphCanvas.prototype.bindEvents=function(){if(this._events_binded)console.warn("LGraphCanvas: events already binded");else{var a=this.canvas;this._mousedown_callback=this.processMouseDown.bind(this);this._mousewheel_callback=this.processMouseWheel.bind(this);a.addEventListener("mousedown",this._mousedown_callback,!0);a.addEventListener("mousemove",this._mousemove_callback);a.addEventListener("mousewheel",this._mousewheel_callback,!1);a.addEventListener("contextmenu",this._doNothing);a.addEventListener("DOMMouseScroll", +this._mousewheel_callback,!1);a.addEventListener("touchstart",this.touchHandler,!0);a.addEventListener("touchmove",this.touchHandler,!0);a.addEventListener("touchend",this.touchHandler,!0);a.addEventListener("touchcancel",this.touchHandler,!0);this._key_callback=this.processKey.bind(this);a.addEventListener("keydown",this._key_callback);a.addEventListener("keyup",this._key_callback);this._ondrop_callback=this.processDrop.bind(this);a.addEventListener("dragover",this._doNothing,!1);a.addEventListener("dragend", +this._doNothing,!1);a.addEventListener("drop",this._ondrop_callback,!1);this._events_binded=!0}}; +LGraphCanvas.prototype.unbindEvents=function(){this._events_binded?(this.canvas.removeEventListener("mousedown",this._mousedown_callback),this.canvas.removeEventListener("mousewheel",this._mousewheel_callback),this.canvas.removeEventListener("DOMMouseScroll",this._mousewheel_callback),this.canvas.removeEventListener("keydown",this._key_callback),this.canvas.removeEventListener("keyup",this._key_callback),this.canvas.removeEventListener("contextmenu",this._doNothing),this.canvas.removeEventListener("drop", +this._ondrop_callback),this.canvas.removeEventListener("touchstart",this.touchHandler),this.canvas.removeEventListener("touchmove",this.touchHandler),this.canvas.removeEventListener("touchend",this.touchHandler),this.canvas.removeEventListener("touchcancel",this.touchHandler),this._ondrop_callback=this._key_callback=this._mousewheel_callback=this._mousedown_callback=null,this._events_binded=!1):console.warn("LGraphCanvas: no events binded")}; LGraphCanvas.getFileExtension=function(a){var b=a.indexOf("?");-1!=b&&(a=a.substr(0,b));b=a.lastIndexOf(".");return-1==b?"":a.substr(b+1).toLowerCase()};LGraphCanvas.prototype.enableWebGL=function(){if(void 0===typeof GL)throw"litegl.js must be included to use a WebGL canvas";if(void 0===typeof enableWebGLCanvas)throw"webglCanvas.js must be included to use this feature";this.gl=this.ctx=enableWebGLCanvas(this.canvas);this.ctx.webgl=!0;this.bgcanvas=this.canvas;this.bgctx=this.gl}; LGraphCanvas.prototype.setDirty=function(a,b){a&&(this.dirty_canvas=!0);b&&(this.dirty_bgcanvas=!0)};LGraphCanvas.prototype.getCanvasWindow=function(){var a=this.canvas.ownerDocument;return a.defaultView||a.parentWindow};LGraphCanvas.prototype.startRendering=function(){function a(){this.pause_rendering||this.draw();var b=this.getCanvasWindow();this.is_rendering&&b.requestAnimationFrame(a.bind(this))}this.is_rendering||(this.is_rendering=!0,a.call(this))}; LGraphCanvas.prototype.stopRendering=function(){this.is_rendering=!1}; @@ -70,16 +74,17 @@ g;++e)h=c.inputs[e],k=c.getConnectionPos(!0,e),isInsideRectangle(a.canvasX,a.can !1;if(300>LiteGraph.getTime()-this.last_mouseclick&&this.selected_nodes[c.id]){if(c.onDblClick)c.onDblClick(a);this.processNodeDblClicked(c);e=!0}c.onMouseDown&&c.onMouseDown(a)?e=!0:this.live_mode&&(e=d=!0);e||(this.allow_dragnodes&&(this.node_dragged=c),this.selected_nodes[c.id]||this.processNodeSelected(c,a));this.dirty_canvas=!0}}else d=!0;d&&this.allow_dragcanvas&&(this.dragging_canvas=!0)}else 2!=a.which&&3==a.which&&this.processContextualMenu(c,a);this.last_mouse[0]=a.localX;this.last_mouse[1]= a.localY;this.last_mouseclick=LiteGraph.getTime();this.canvas_mouse=[a.canvasX,a.canvasY];this.graph.change();(!b.document.activeElement||"input"!=b.document.activeElement.nodeName.toLowerCase()&&"textarea"!=b.document.activeElement.nodeName.toLowerCase())&&a.preventDefault();a.stopPropagation();return!1}}; LGraphCanvas.prototype.processMouseMove=function(a){if(this.graph){this.adjustMouseEvent(a);var b=[a.localX,a.localY],c=[b[0]-this.last_mouse[0],b[1]-this.last_mouse[1]];this.last_mouse=b;this.canvas_mouse=[a.canvasX,a.canvasY];if(this.dragging_canvas)this.offset[0]+=c[0]/this.scale,this.offset[1]+=c[1]/this.scale,this.dirty_bgcanvas=this.dirty_canvas=!0;else{this.connecting_node&&(this.dirty_canvas=!0);var b=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes),d;for(d in this.graph._nodes)if(this.graph._nodes[d].mouseOver&& -b!=this.graph._nodes[d]){this.graph._nodes[d].mouseOver=!1;if(this.node_over&&this.node_over.onMouseLeave)this.node_over.onMouseLeave(a);this.node_over=null;this.dirty_canvas=!0}if(b){if(!b.mouseOver&&(b.mouseOver=!0,this.node_over=b,this.dirty_canvas=!0,b.onMouseEnter))b.onMouseEnter(a);if(b.onMouseMove)b.onMouseMove(a);if(this.connecting_node){var e=this._highlight_input||[0,0],f=this.isOverNodeInput(b,a.canvasX,a.canvasY,e);-1!=f&&b.inputs[f]?(f=b.inputs[f].type,f!=this.connecting_output.type&& -f&&this.connecting_output.type||(this._highlight_input=e)):this._highlight_input=null}isInsideRectangle(a.canvasX,a.canvasY,b.pos[0]+b.size[0]-5,b.pos[1]+b.size[1]-5,5,5)?this.canvas.style.cursor="se-resize":this.canvas.style.cursor=null}else this.canvas.style.cursor=null;if(this.node_capturing_input&&this.node_capturing_input!=b&&this.node_capturing_input.onMouseMove)this.node_capturing_input.onMouseMove(a);if(this.node_dragged&&!this.live_mode){for(d in this.selected_nodes)b=this.selected_nodes[d], -b.pos[0]+=c[0]/this.scale,b.pos[1]+=c[1]/this.scale;this.dirty_bgcanvas=this.dirty_canvas=!0}this.resizing_node&&!this.live_mode&&(this.resizing_node.size[0]+=c[0]/this.scale,this.resizing_node.size[1]+=c[1]/this.scale,c=Math.max(this.resizing_node.inputs?this.resizing_node.inputs.length:0,this.resizing_node.outputs?this.resizing_node.outputs.length:0),this.resizing_node.size[1]b&&(c*=1/1.1);this.setZoom(c,[a.localX,a.localY]);this.graph.change();a.preventDefault();return!1}}; +!0,this.dragging_canvas=!1);this.graph.change();a.stopPropagation();a.preventDefault();return!1}};LGraphCanvas.prototype.processMouseWheel=function(a){if(this.graph&&this.allow_dragcanvas){var b=null!=a.wheelDeltaY?a.wheelDeltaY:-60*a.detail;this.adjustMouseEvent(a);var c=this.scale;0b&&(c*=1/1.1);this.setZoom(c,[a.localX,a.localY]);this.graph.change();a.preventDefault();return!1}}; +LGraphCanvas.prototype.isOverNodeInput=function(a,b,c,d){if(a.inputs)for(var e=0,f=a.inputs.length;ea&&db?!0:!1}function growBounding(a,b,c){ba[2]&&(a[2]=b);ca[3]&&(a[3]=c)} function isInsideBounding(a,b){return a[0]b[1][0]||a[1]>b[1][1]?!1:!0}function overlapBounding(a,b){return a[0]>b[2]||a[1]>b[3]||a[2]f;f+=2)d="0123456789ABCDEF".indexOf(a.charAt(f)),e="0123456789ABCDEF".indexOf(a.charAt(f+1)),b[c]=16*d+e,c++;return b} @@ -137,8 +142,8 @@ h=h.left+h.width),h>f.width-a.width-10&&(h=f.width-a.width-10),g>f.height-a.heig LiteGraph.extendClass=function(a,b){for(var c in b)a.hasOwnProperty(c)||(a[c]=b[c]);if(b.prototype)for(c in b.prototype)b.prototype.hasOwnProperty(c)&&!a.prototype.hasOwnProperty(c)&&(b.prototype.__lookupGetter__(c)?a.prototype.__defineGetter__(c,b.prototype.__lookupGetter__(c)):a.prototype[c]=b.prototype[c],b.prototype.__lookupSetter__(c)&&a.prototype.__defineSetter__(c,b.prototype.__lookupSetter__(c)))}; window.requestAnimationFrame||(window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)}); (function(){function a(){this.size=[120,60];this.subgraph=new LGraph;this.subgraph._subgraph_node=this;this.subgraph._is_subgraph=!0;this.subgraph.onGlobalInputAdded=this.onSubgraphNewGlobalInput.bind(this);this.subgraph.onGlobalInputRenamed=this.onSubgraphRenamedGlobalInput.bind(this);this.subgraph.onGlobalInputTypeChanged=this.onSubgraphTypeChangeGlobalInput.bind(this);this.subgraph.onGlobalOutputAdded=this.onSubgraphNewGlobalOutput.bind(this);this.subgraph.onGlobalOutputRenamed=this.onSubgraphRenamedGlobalOutput.bind(this); -this.subgraph.onGlobalOutputTypeChanged=this.onSubgraphTypeChangeGlobalOutput.bind(this);this.bgcolor="#940"}function b(){var a="input_"+(1E3*Math.random()).toFixed();this.addOutput(a,null);this.properties={name:a,type:null};var b=this;Object.defineProperty(this.properties,"name",{get:function(){return a},set:function(c){if(""!=c){var f=b.getOutputInfo(0);f.name!=c&&(f.name=c,b.graph&&b.graph.renameGlobalInput(a,c),a=c)}},enumerable:!0});Object.defineProperty(this.properties,"type",{get:function(){return b.outputs[0].type}, -set:function(c){b.outputs[0].type=c;b.graph&&b.graph.changeGlobalInputType(a,b.outputs[0].type)},enumerable:!0})}function c(){var a="output_"+(1E3*Math.random()).toFixed();this.addInput(a,null);this.properties={name:a,type:null};var b=this;Object.defineProperty(this.properties,"name",{get:function(){return a},set:function(c){if(""!=c){var f=b.getInputInfo(0);f.name!=c&&(f.name=c,b.graph&&b.graph.renameGlobalOutput(a,c),a=c)}},enumerable:!0});Object.defineProperty(this.properties,"type",{get:function(){return b.inputs[0].type}, +this.subgraph.onGlobalOutputTypeChanged=this.onSubgraphTypeChangeGlobalOutput.bind(this);this.bgcolor="#940"}function b(){var a="input_"+(1E3*Math.random()).toFixed();this.addOutput(a,null);this.properties={name:a,type:null};var b=this;Object.defineProperty(this.properties,"name",{get:function(){return a},set:function(c){if(""!=c){var d=b.getOutputInfo(0);d.name!=c&&(d.name=c,b.graph&&b.graph.renameGlobalInput(a,c),a=c)}},enumerable:!0});Object.defineProperty(this.properties,"type",{get:function(){return b.outputs[0].type}, +set:function(c){b.outputs[0].type=c;b.graph&&b.graph.changeGlobalInputType(a,b.outputs[0].type)},enumerable:!0})}function c(){var a="output_"+(1E3*Math.random()).toFixed();this.addInput(a,null);this.properties={name:a,type:null};var b=this;Object.defineProperty(this.properties,"name",{get:function(){return a},set:function(c){if(""!=c){var d=b.getInputInfo(0);d.name!=c&&(d.name=c,b.graph&&b.graph.renameGlobalOutput(a,c),a=c)}},enumerable:!0});Object.defineProperty(this.properties,"type",{get:function(){return b.inputs[0].type}, set:function(c){b.inputs[0].type=c;b.graph&&b.graph.changeGlobalInputType(a,b.inputs[0].type)},enumerable:!0})}function d(){this.addOutput("value","number");this.properties={value:1};this.editable={property:"value",type:"number"}}function e(){this.size=[60,20];this.addInput("value",0,{label:""});this.addOutput("value",0,{label:""});this.properties={value:""}}function f(){this.size=[60,20];this.addInput("data",0)}a.title="Subgraph";a.desc="Graph inside a node";a.prototype.onSubgraphNewGlobalInput= function(a,b){this.addInput(a,b)};a.prototype.onSubgraphRenamedGlobalInput=function(a,b){var c=this.findInputSlot(a);-1!=c&&(this.getInputInfo(c).name=b)};a.prototype.onSubgraphTypeChangeGlobalInput=function(a,b){var c=this.findInputSlot(a);-1!=c&&(this.getInputInfo(c).type=b)};a.prototype.onSubgraphNewGlobalOutput=function(a,b){this.addOutput(a,b)};a.prototype.onSubgraphRenamedGlobalOutput=function(a,b){var c=this.findOutputSlot(a);-1!=c&&(this.getOutputInfo(c).name=b)};a.prototype.onSubgraphTypeChangeGlobalOutput= function(a,b){var c=this.findOutputSlot(a);-1!=c&&(this.getOutputInfo(c).type=b)};a.prototype.getExtraMenuOptions=function(a){var b=this;return[{content:"Open",callback:function(){a.openSubgraph(b.subgraph)}}]};a.prototype.onExecute=function(){if(this.inputs)for(var a=0;ad;d++)if(c[d]){a=c[d];c=this.xbox_mapping;c||(c=this.xbox_mapping={axes:[],buttons:{},hat:""});c.axes.lx=a.axes[0];c.axes.ly=a.axes[1];c.axes.rx=a.axes[2];c.axes.ry=a.axes[3];c.axes.triggers=a.axes[4];for(d=0;d"};this.size=[60,40]}function n(){this.addInput("inc","number");this.addOutput("total","number");this.properties={increment:0,value:0}}function p(){this.addInput("v","number");this.addOutput("sin","number");this.properties={amplitude:1,offset:0};this.bgImageUrl="nodes/imgs/icon-sin.png"}a.title="Rand";a.desc="Random number";a.prototype.onExecute=function(){if(this.inputs)for(var a=0;a + diff --git a/doc/classes/LGraph.html b/doc/classes/LGraph.html index 2fecb1ec5..2471a5fe1 100644 --- a/doc/classes/LGraph.html +++ b/doc/classes/LGraph.html @@ -644,7 +644,7 @@ - ../src/litegraph.js:1076 + ../src/litegraph.js:1077

@@ -932,7 +932,7 @@ - ../src/litegraph.js:755 + ../src/litegraph.js:756

@@ -1393,7 +1393,7 @@ if the nodes are using graphical actions

- ../src/litegraph.js:771 + ../src/litegraph.js:772

@@ -1591,7 +1591,7 @@ if the nodes are using graphical actions

- ../src/litegraph.js:1010 + ../src/litegraph.js:1011

@@ -1939,7 +1939,7 @@ if the nodes are using graphical actions

- ../src/litegraph.js:1043 + ../src/litegraph.js:1044

@@ -2024,7 +2024,7 @@ if the nodes are using graphical actions

- ../src/litegraph.js:958 + ../src/litegraph.js:959

@@ -2134,7 +2134,7 @@ can be easily accesed from the outside of the graph

- ../src/litegraph.js:973 + ../src/litegraph.js:974

diff --git a/doc/classes/LGraphCanvas.html b/doc/classes/LGraphCanvas.html index 5cfdb1acf..1beee8603 100644 --- a/doc/classes/LGraphCanvas.html +++ b/doc/classes/LGraphCanvas.html @@ -96,7 +96,7 @@ @@ -163,7 +163,7 @@ - ../src/litegraph.js:2397 + ../src/litegraph.js:2429

@@ -353,7 +353,7 @@ - ../src/litegraph.js:2075 + ../src/litegraph.js:2073

@@ -418,7 +418,7 @@ - ../src/litegraph.js:2184 + ../src/litegraph.js:2187

@@ -501,7 +501,7 @@ - ../src/litegraph.js:2413 + ../src/litegraph.js:2445

@@ -580,7 +580,7 @@ - ../src/litegraph.js:2157 + ../src/litegraph.js:2160

@@ -668,7 +668,7 @@ - ../src/litegraph.js:2199 + ../src/litegraph.js:2202

@@ -835,7 +835,7 @@ - ../src/litegraph.js:2425 + ../src/litegraph.js:2457

@@ -890,7 +890,7 @@ - ../src/litegraph.js:2448 + ../src/litegraph.js:2480

diff --git a/doc/classes/LGraphNode.html b/doc/classes/LGraphNode.html index 03e383242..340df53ec 100644 --- a/doc/classes/LGraphNode.html +++ b/doc/classes/LGraphNode.html @@ -96,7 +96,7 @@ @@ -415,7 +415,7 @@ - ../src/litegraph.js:1569 + ../src/litegraph.js:1570

@@ -563,7 +563,7 @@ - ../src/litegraph.js:1508 + ../src/litegraph.js:1509

@@ -683,7 +683,7 @@ - ../src/litegraph.js:1530 + ../src/litegraph.js:1531

@@ -784,7 +784,7 @@ - ../src/litegraph.js:1448 + ../src/litegraph.js:1449

@@ -904,7 +904,7 @@ - ../src/litegraph.js:1469 + ../src/litegraph.js:1470

@@ -983,7 +983,7 @@ - ../src/litegraph.js:2001 + ../src/litegraph.js:2002

@@ -1052,7 +1052,7 @@ - ../src/litegraph.js:1582 + ../src/litegraph.js:1583

@@ -1144,7 +1144,7 @@ - ../src/litegraph.js:1190 + ../src/litegraph.js:1191

@@ -1225,7 +1225,7 @@ - ../src/litegraph.js:1662 + ../src/litegraph.js:1663

@@ -1364,7 +1364,7 @@ - ../src/litegraph.js:1812 + ../src/litegraph.js:1813

@@ -1477,7 +1477,7 @@ - ../src/litegraph.js:1745 + ../src/litegraph.js:1746

@@ -1600,7 +1600,7 @@ - ../src/litegraph.js:1632 + ../src/litegraph.js:1633

@@ -1707,7 +1707,7 @@ - ../src/litegraph.js:1647 + ../src/litegraph.js:1648

@@ -1804,7 +1804,7 @@ - ../src/litegraph.js:1600 + ../src/litegraph.js:1601

@@ -1893,7 +1893,7 @@ - ../src/litegraph.js:1869 + ../src/litegraph.js:1870

@@ -2016,7 +2016,7 @@ - ../src/litegraph.js:1349 + ../src/litegraph.js:1350

@@ -2122,7 +2122,7 @@ - ../src/litegraph.js:1377 + ../src/litegraph.js:1378

@@ -2226,7 +2226,7 @@ - ../src/litegraph.js:1392 + ../src/litegraph.js:1393

@@ -2330,7 +2330,7 @@ - ../src/litegraph.js:1419 + ../src/litegraph.js:1420

@@ -2420,7 +2420,7 @@ - ../src/litegraph.js:1315 + ../src/litegraph.js:1316

@@ -2489,7 +2489,7 @@ - ../src/litegraph.js:1364 + ../src/litegraph.js:1365

@@ -2593,7 +2593,7 @@ - ../src/litegraph.js:1407 + ../src/litegraph.js:1408

@@ -2703,7 +2703,7 @@ - ../src/litegraph.js:1610 + ../src/litegraph.js:1611

@@ -2808,7 +2808,7 @@ - ../src/litegraph.js:2014 + ../src/litegraph.js:2015

@@ -2873,7 +2873,7 @@ - ../src/litegraph.js:1555 + ../src/litegraph.js:1556

@@ -2961,7 +2961,7 @@ - ../src/litegraph.js:1494 + ../src/litegraph.js:1495

@@ -3039,7 +3039,7 @@ - ../src/litegraph.js:1249 + ../src/litegraph.js:1250

@@ -3110,7 +3110,7 @@ - ../src/litegraph.js:1328 + ../src/litegraph.js:1329

@@ -3203,7 +3203,7 @@ - ../src/litegraph.js:1303 + ../src/litegraph.js:1304

diff --git a/doc/data.json b/doc/data.json index ff262682c..3affa1f0c 100644 --- a/doc/data.json +++ b/doc/data.json @@ -51,7 +51,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 1155, + "line": 1156, "description": "Base Class for all the node type classes", "params": [ { @@ -70,7 +70,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 2397, + "line": 2429, "description": "marks as dirty the canvas, this way it will be rendered again", "is_constructor": 1, "params": [ @@ -409,7 +409,7 @@ }, { "file": "../src/litegraph.js", - "line": 755, + "line": 756, "description": "Returns a list of nodes that matches a name", "itemtype": "method", "name": "findNodesByName", @@ -428,7 +428,7 @@ }, { "file": "../src/litegraph.js", - "line": 771, + "line": 772, "description": "Returns the top-most node in this position of the canvas", "itemtype": "method", "name": "getNodeOnPos", @@ -457,7 +457,7 @@ }, { "file": "../src/litegraph.js", - "line": 958, + "line": 959, "description": "Assigns a value to all the nodes that matches this name. This is used to create global variables of the node that\ncan be easily accesed from the outside of the graph", "itemtype": "method", "name": "setInputData", @@ -477,7 +477,7 @@ }, { "file": "../src/litegraph.js", - "line": 973, + "line": 974, "description": "Returns the value of the first node with this name. This is used to access global variables of the graph from the outside", "itemtype": "method", "name": "setInputData", @@ -496,7 +496,7 @@ }, { "file": "../src/litegraph.js", - "line": 1010, + "line": 1011, "description": "returns if the graph is in live mode", "itemtype": "method", "name": "isLive", @@ -504,7 +504,7 @@ }, { "file": "../src/litegraph.js", - "line": 1043, + "line": 1044, "description": "Creates a Object containing all the info about this graph, it can be serialized", "itemtype": "method", "name": "serialize", @@ -516,7 +516,7 @@ }, { "file": "../src/litegraph.js", - "line": 1076, + "line": 1077, "description": "Configure a graph from a JSON string", "itemtype": "method", "name": "configure", @@ -531,7 +531,7 @@ }, { "file": "../src/litegraph.js", - "line": 1190, + "line": 1191, "description": "configure a node from an object containing the serialized info", "itemtype": "method", "name": "configure", @@ -539,7 +539,7 @@ }, { "file": "../src/litegraph.js", - "line": 1249, + "line": 1250, "description": "serialize the content", "itemtype": "method", "name": "serialize", @@ -547,7 +547,7 @@ }, { "file": "../src/litegraph.js", - "line": 1303, + "line": 1304, "description": "serialize and stringify", "itemtype": "method", "name": "toString", @@ -555,7 +555,7 @@ }, { "file": "../src/litegraph.js", - "line": 1315, + "line": 1316, "description": "get the title string", "itemtype": "method", "name": "getTitle", @@ -563,7 +563,7 @@ }, { "file": "../src/litegraph.js", - "line": 1328, + "line": 1329, "description": "sets the output data", "itemtype": "method", "name": "setOutputData", @@ -583,7 +583,7 @@ }, { "file": "../src/litegraph.js", - "line": 1349, + "line": 1350, "description": "retrieves the input data (data traveling through the connection) from one slot", "itemtype": "method", "name": "getInputData", @@ -602,7 +602,7 @@ }, { "file": "../src/litegraph.js", - "line": 1364, + "line": 1365, "description": "tells you if there is a connection in one input slot", "itemtype": "method", "name": "isInputConnected", @@ -621,7 +621,7 @@ }, { "file": "../src/litegraph.js", - "line": 1377, + "line": 1378, "description": "tells you info about an input connection (which node, type, etc)", "itemtype": "method", "name": "getInputInfo", @@ -640,7 +640,7 @@ }, { "file": "../src/litegraph.js", - "line": 1392, + "line": 1393, "description": "tells you info about an output connection (which node, type, etc)", "itemtype": "method", "name": "getOutputInfo", @@ -659,7 +659,7 @@ }, { "file": "../src/litegraph.js", - "line": 1407, + "line": 1408, "description": "tells you if there is a connection in one output slot", "itemtype": "method", "name": "isOutputConnected", @@ -678,7 +678,7 @@ }, { "file": "../src/litegraph.js", - "line": 1419, + "line": 1420, "description": "retrieves all the nodes connected to this output slot", "itemtype": "method", "name": "getOutputNodes", @@ -697,7 +697,7 @@ }, { "file": "../src/litegraph.js", - "line": 1448, + "line": 1449, "description": "add a new output slot to use in this node", "itemtype": "method", "name": "addOutput", @@ -722,7 +722,7 @@ }, { "file": "../src/litegraph.js", - "line": 1469, + "line": 1470, "description": "add a new output slot to use in this node", "itemtype": "method", "name": "addOutputs", @@ -737,7 +737,7 @@ }, { "file": "../src/litegraph.js", - "line": 1494, + "line": 1495, "description": "remove an existing output slot", "itemtype": "method", "name": "removeOutput", @@ -752,7 +752,7 @@ }, { "file": "../src/litegraph.js", - "line": 1508, + "line": 1509, "description": "add a new input slot to use in this node", "itemtype": "method", "name": "addInput", @@ -777,7 +777,7 @@ }, { "file": "../src/litegraph.js", - "line": 1530, + "line": 1531, "description": "add several new input slots in this node", "itemtype": "method", "name": "addInputs", @@ -792,7 +792,7 @@ }, { "file": "../src/litegraph.js", - "line": 1555, + "line": 1556, "description": "remove an existing input slot", "itemtype": "method", "name": "removeInput", @@ -807,7 +807,7 @@ }, { "file": "../src/litegraph.js", - "line": 1569, + "line": 1570, "description": "add an special connection to this node (used for special kinds of graphs)", "itemtype": "method", "name": "addConnection", @@ -837,7 +837,7 @@ }, { "file": "../src/litegraph.js", - "line": 1582, + "line": 1583, "description": "computes the size of a node according to its inputs and output slots", "itemtype": "method", "name": "computeSize", @@ -856,7 +856,7 @@ }, { "file": "../src/litegraph.js", - "line": 1600, + "line": 1601, "description": "returns the bounding of the object, used for rendering purposes", "itemtype": "method", "name": "getBounding", @@ -868,7 +868,7 @@ }, { "file": "../src/litegraph.js", - "line": 1610, + "line": 1611, "description": "checks if a point is inside the shape of a node", "itemtype": "method", "name": "isPointInsideNode", @@ -892,7 +892,7 @@ }, { "file": "../src/litegraph.js", - "line": 1632, + "line": 1633, "description": "returns the input slot with a given name (used for dynamic slots), -1 if not found", "itemtype": "method", "name": "findInputSlot", @@ -911,7 +911,7 @@ }, { "file": "../src/litegraph.js", - "line": 1647, + "line": 1648, "description": "returns the output slot with a given name (used for dynamic slots), -1 if not found", "itemtype": "method", "name": "findOutputSlot", @@ -930,7 +930,7 @@ }, { "file": "../src/litegraph.js", - "line": 1662, + "line": 1663, "description": "connect this node output to the input of another node", "itemtype": "method", "name": "connect", @@ -959,7 +959,7 @@ }, { "file": "../src/litegraph.js", - "line": 1745, + "line": 1746, "description": "disconnect one output to an specific node", "itemtype": "method", "name": "disconnectOutput", @@ -983,7 +983,7 @@ }, { "file": "../src/litegraph.js", - "line": 1812, + "line": 1813, "description": "disconnect one input", "itemtype": "method", "name": "disconnectInput", @@ -1002,7 +1002,7 @@ }, { "file": "../src/litegraph.js", - "line": 1869, + "line": 1870, "description": "returns the center of a connection point in canvas coords", "itemtype": "method", "name": "getConnectionPos", @@ -1026,7 +1026,7 @@ }, { "file": "../src/litegraph.js", - "line": 2001, + "line": 2002, "description": "Collapse the node to make it smaller on the canvas", "itemtype": "method", "name": "collapse", @@ -1034,7 +1034,7 @@ }, { "file": "../src/litegraph.js", - "line": 2014, + "line": 2015, "description": "Forces the node to do not move or realign on Z", "itemtype": "method", "name": "pin", @@ -1042,7 +1042,7 @@ }, { "file": "../src/litegraph.js", - "line": 2075, + "line": 2073, "description": "clears all the data inside", "itemtype": "method", "name": "clear", @@ -1065,7 +1065,7 @@ }, { "file": "../src/litegraph.js", - "line": 2157, + "line": 2160, "description": "opens a graph contained inside a node in the current graph", "itemtype": "method", "name": "openSubgraph", @@ -1080,7 +1080,7 @@ }, { "file": "../src/litegraph.js", - "line": 2184, + "line": 2187, "description": "closes a subgraph contained inside a node", "itemtype": "method", "name": "closeSubgraph", @@ -1095,7 +1095,7 @@ }, { "file": "../src/litegraph.js", - "line": 2199, + "line": 2202, "description": "assigns a canvas", "itemtype": "method", "name": "setCanvas", @@ -1110,7 +1110,7 @@ }, { "file": "../src/litegraph.js", - "line": 2413, + "line": 2445, "description": "Used to attach the canvas in a popup", "itemtype": "method", "name": "getCanvasWindow", @@ -1122,7 +1122,7 @@ }, { "file": "../src/litegraph.js", - "line": 2425, + "line": 2457, "description": "starts rendering the content of the canvas when needed", "itemtype": "method", "name": "startRendering", @@ -1130,7 +1130,7 @@ }, { "file": "../src/litegraph.js", - "line": 2448, + "line": 2480, "description": "stops rendering the content of the canvas (to save resources)", "itemtype": "method", "name": "stopRendering", diff --git a/doc/files/.._src_litegraph.js.html b/doc/files/.._src_litegraph.js.html index 8e88f542b..246040aa1 100644 --- a/doc/files/.._src_litegraph.js.html +++ b/doc/files/.._src_litegraph.js.html @@ -839,9 +839,10 @@ LGraph.prototype.findNodesByClass = function(classObject) LGraph.prototype.findNodesByType = function(type) { + var type = type.toLowerCase(); var r = []; for(var i in this._nodes) - if(this._nodes[i].type == type) + if(this._nodes[i].type.toLowerCase() == type ) r.push(this._nodes[i]); return r; } @@ -945,7 +946,7 @@ LGraph.prototype.changeGlobalInputType = function(name, type) if(!this.global_inputs[name]) return false; - if(this.global_inputs[name].type == type) + if(this.global_inputs[name].type.toLowerCase() == type.toLowerCase() ) return; this.global_inputs[name].type = type; @@ -1026,7 +1027,7 @@ LGraph.prototype.changeGlobalOutputType = function(name, type) if(!this.global_outputs[name]) return false; - if(this.global_outputs[name].type == type) + if(this.global_outputs[name].type.toLowerCase() == type.toLowerCase() ) return; this.global_outputs[name].type = type; @@ -1818,7 +1819,7 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) } else if( !output.type || //generic output !node.inputs[target_slot].type || //generic input - output.type == node.inputs[target_slot].type) //same type + output.type.toLowerCase() == node.inputs[target_slot].type.toLowerCase() ) //same type { //info: link structure => [ 0:link_id, 1:start_node_id, 2:start_slot, 3:end_node_id, 4:end_slot ] //var link = [ this.graph.last_link_id++, this.id, slot, node.id, target_slot ]; @@ -2138,16 +2139,13 @@ LGraphNode.prototype.localToScreen = function(x,y, graphcanvas) * @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format or the canvas itself) * @param {LGraph} graph [optional] */ -function LGraphCanvas(canvas, graph, skip_render) +function LGraphCanvas( canvas, graph, skip_render ) { //if(graph === undefined) // throw ("No graph assigned"); - if(typeof(canvas) == "string") - canvas = document.querySelector(canvas); - - if(!canvas) - throw("no canvas found"); + if(canvas && canvas.constructor === String ) + canvas = document.querySelector( canvas ); this.max_zoom = 10; this.min_zoom = 0.1; @@ -2156,7 +2154,7 @@ function LGraphCanvas(canvas, graph, skip_render) if(graph) graph.attachCanvas(this); - this.setCanvas(canvas); + this.setCanvas( canvas ); this.clear(); if(!skip_render) @@ -2191,9 +2189,7 @@ LGraphCanvas.prototype.clear = function() this.editor_alpha = 1; //used for transition this.pause_rendering = false; this.render_shadows = true; - this.dirty_canvas = true; - this.dirty_bgcanvas = true; - this.dirty_area = null; + this.clear_background = true; this.render_only_selected = true; this.live_mode = false; @@ -2201,6 +2197,10 @@ LGraphCanvas.prototype.clear = function() this.allow_dragcanvas = true; this.allow_dragnodes = true; + this.dirty_canvas = true; + this.dirty_bgcanvas = true; + this.dirty_area = null; + this.node_in_panel = null; this.last_mouse = [0,0]; @@ -2226,10 +2226,13 @@ LGraphCanvas.prototype.clear = function() * @method setGraph * @param {LGraph} graph */ -LGraphCanvas.prototype.setGraph = function(graph) +LGraphCanvas.prototype.setGraph = function( graph, skip_clear ) { - if(this.graph == graph) return; - this.clear(); + if(this.graph == graph) + return; + + if(!skip_clear) + this.clear(); if(!graph && this.graph) { @@ -2296,19 +2299,35 @@ LGraphCanvas.prototype.closeSubgraph = function() * @method setCanvas * @param {Canvas} assigns a canvas */ -LGraphCanvas.prototype.setCanvas = function(canvas) +LGraphCanvas.prototype.setCanvas = function( canvas, skip_events ) { var that = this; - //Canvas association - if(typeof(canvas) == "string") - canvas = document.getElementById(canvas); + if(canvas) + { + if( canvas.constructor === String ) + { + canvas = document.getElementById(canvas); + if(!canvas) + throw("Error creating LiteGraph canvas: Canvas not found"); + } + } - if(canvas == null) - throw("Error creating LiteGraph canvas: Canvas not found"); - if(canvas == this.canvas) return; + if(canvas === this.canvas) + return; + + if(!canvas && this.canvas) + { + //maybe detach events from old_canvas + if(!skip_events) + this.unbindEvents(); + } this.canvas = canvas; + + if(!canvas) + return; + //this.canvas.tabindex = "1000"; canvas.className += " lgraphcanvas"; canvas.data = this; @@ -2338,72 +2357,85 @@ LGraphCanvas.prototype.setCanvas = function(canvas) this._mousemove_callback = this.processMouseMove.bind(this); this._mouseup_callback = this.processMouseUp.bind(this); - canvas.addEventListener("mousedown", this.processMouseDown.bind(this), true ); //down do not need to store the binded - canvas.addEventListener("mousemove", this._mousemove_callback); + if(!skip_events) + this.bindEvents(); +} - canvas.addEventListener("contextmenu", function(e) { e.preventDefault(); return false; }); - - canvas.addEventListener("mousewheel", this.processMouseWheel.bind(this), false); - canvas.addEventListener("DOMMouseScroll", this.processMouseWheel.bind(this), false); +//used in some events to capture them +LGraphCanvas.prototype._doNothing = function doNothing() { return false; }; + +LGraphCanvas.prototype.bindEvents = function() +{ + if( this._events_binded ) + { + console.warn("LGraphCanvas: events already binded"); + return; + } + + var canvas = this.canvas; + + this._mousedown_callback = this.processMouseDown.bind(this); + this._mousewheel_callback = this.processMouseWheel.bind(this); + + canvas.addEventListener("mousedown", this._mousedown_callback, true ); //down do not need to store the binded + canvas.addEventListener("mousemove", this._mousemove_callback ); + canvas.addEventListener("mousewheel", this._mousewheel_callback, false); + + canvas.addEventListener("contextmenu", this._doNothing ); + canvas.addEventListener("DOMMouseScroll", this._mousewheel_callback, false); //touch events //if( 'touchstart' in document.documentElement ) { - //alert("doo"); canvas.addEventListener("touchstart", this.touchHandler, true); canvas.addEventListener("touchmove", this.touchHandler, true); canvas.addEventListener("touchend", this.touchHandler, true); canvas.addEventListener("touchcancel", this.touchHandler, true); } - //this.canvas.onselectstart = function () { return false; }; - canvas.addEventListener("keydown", function(e) { - that.processKeyDown(e); - }); + //Keyboard ****************** + this._key_callback = this.processKey.bind(this); - canvas.addEventListener("keyup", function(e) { - that.processKeyUp(e); - }); + canvas.addEventListener("keydown", this._key_callback ); + canvas.addEventListener("keyup", this._key_callback ); - //droping files - canvas.ondragover = function () { console.log('hover'); return false; }; - canvas.ondragend = function () { console.log('out'); return false; }; - canvas.ondrop = function (e) { - e.preventDefault(); - that.adjustMouseEvent(e); + //Droping Stuff over nodes ************************************ + this._ondrop_callback = this.processDrop.bind(this); - var pos = [e.canvasX,e.canvasY]; - var node = that.graph.getNodeOnPos(pos[0],pos[1]); - if(!node) - return; + canvas.addEventListener("dragover", this._doNothing, false ); + canvas.addEventListener("dragend", this._doNothing, false ); + canvas.addEventListener("drop", this._ondrop_callback, false ); - if(!node.onDropFile) - return; + this._events_binded = true; +} - var file = e.dataTransfer.files[0]; - var filename = file.name; - var ext = LGraphCanvas.getFileExtension( filename ); - //console.log(file); +LGraphCanvas.prototype.unbindEvents = function() +{ + if( !this._events_binded ) + { + console.warn("LGraphCanvas: no events binded"); + return; + } - //prepare reader - var reader = new FileReader(); - reader.onload = function (event) { - //console.log(event.target); - var data = event.target.result; - node.onDropFile( data, filename, file ); - }; + this.canvas.removeEventListener( "mousedown", this._mousedown_callback ); + this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback ); + this.canvas.removeEventListener( "DOMMouseScroll", this._mousewheel_callback ); + this.canvas.removeEventListener( "keydown", this._key_callback ); + this.canvas.removeEventListener( "keyup", this._key_callback ); + this.canvas.removeEventListener( "contextmenu", this._doNothing ); + this.canvas.removeEventListener( "drop", this._ondrop_callback ); - //read data - var type = file.type.split("/")[0]; - if(type == "text" || type == "") - reader.readAsText(file); - else if (type == "image") - reader.readAsDataURL(file); - else - reader.readAsArrayBuffer(file); + this.canvas.removeEventListener("touchstart", this.touchHandler ); + this.canvas.removeEventListener("touchmove", this.touchHandler ); + this.canvas.removeEventListener("touchend", this.touchHandler ); + this.canvas.removeEventListener("touchcancel", this.touchHandler ); - return false; - }; + this._mousedown_callback = null; + this._mousewheel_callback = null; + this._key_callback = null; + this._ondrop_callback = null; + + this._events_binded = false; } LGraphCanvas.getFileExtension = function (url) @@ -2560,13 +2592,15 @@ LGraphCanvas.prototype.stopRendering = function() LGraphCanvas.prototype.processMouseDown = function(e) { - if(!this.graph) return; + if(!this.graph) + return; this.adjustMouseEvent(e); var ref_window = this.getCanvasWindow(); var document = ref_window.document; + //move mouse move event to the window in case it drags outside of the canvas this.canvas.removeEventListener("mousemove", this._mousemove_callback ); ref_window.document.addEventListener("mousemove", this._mousemove_callback, true ); //catch for the entire window ref_window.document.addEventListener("mouseup", this._mouseup_callback, true ); @@ -2792,7 +2826,7 @@ LGraphCanvas.prototype.processMouseMove = function(e) if(slot != -1 && n.inputs[slot]) { var slot_type = n.inputs[slot].type; - if(slot_type == this.connecting_output.type || !slot_type || !this.connecting_output.type ) + if( !this.connecting_output.type || !slot_type || slot_type.toLowerCase() == this.connecting_output.type.toLowerCase() ) this._highlight_input = pos; } else @@ -2867,11 +2901,13 @@ LGraphCanvas.prototype.processMouseMove = function(e) LGraphCanvas.prototype.processMouseUp = function(e) { - if(!this.graph) return; + if(!this.graph) + return; var window = this.getCanvasWindow(); var document = window.document; + //restore the mousemove event back to the canvas document.removeEventListener("mousemove", this._mousemove_callback, true ); this.canvas.addEventListener("mousemove", this._mousemove_callback, true); document.removeEventListener("mouseup", this._mouseup_callback, true ); @@ -2908,7 +2944,7 @@ LGraphCanvas.prototype.processMouseUp = function(e) { //not on top of an input var input = node.getInputInfo(0); //simple connect - if(input && !input.link && input.type == this.connecting_output.type) + if(input && !input.link && input.type == this.connecting_output.type) //toLowerCase missing this.connecting_node.connect(this.connecting_slot, node, 0); } } @@ -2972,75 +3008,11 @@ LGraphCanvas.prototype.processMouseUp = function(e) return false; } -LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_pos) -{ - if(node.inputs) - for(var i = 0, l = node.inputs.length; i < l; ++i) - { - var input = node.inputs[i]; - var link_pos = node.getConnectionPos(true,i); - if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) - { - if(slot_pos) { slot_pos[0] = link_pos[0]; slot_pos[1] = link_pos[1] }; - return i; - } - } - return -1; -} - -LGraphCanvas.prototype.processKeyDown = function(e) -{ - if(!this.graph) return; - var block_default = false; - - //select all Control A - if(e.keyCode == 65 && e.ctrlKey) - { - this.selectAllNodes(); - block_default = true; - } - - //delete or backspace - if(e.keyCode == 46 || e.keyCode == 8) - { - this.deleteSelectedNodes(); - block_default = true; - } - - //collapse - //... - - //TODO - if(this.selected_nodes) - for (var i in this.selected_nodes) - if(this.selected_nodes[i].onKeyDown) - this.selected_nodes[i].onKeyDown(e); - - this.graph.change(); - - if(block_default) - { - e.preventDefault(); - return false; - } -} - -LGraphCanvas.prototype.processKeyUp = function(e) -{ - if(!this.graph) return; - //TODO - if(this.selected_nodes) - for (var i in this.selected_nodes) - if(this.selected_nodes[i].onKeyUp) - this.selected_nodes[i].onKeyUp(e); - - this.graph.change(); -} LGraphCanvas.prototype.processMouseWheel = function(e) { - if(!this.graph) return; - if(!this.allow_dragcanvas) return; + if(!this.graph || !this.allow_dragcanvas) + return; var delta = (e.wheelDeltaY != null ? e.wheelDeltaY : e.detail * -60); @@ -3066,6 +3038,109 @@ LGraphCanvas.prototype.processMouseWheel = function(e) return false; // prevent default } +LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_pos) +{ + if(node.inputs) + for(var i = 0, l = node.inputs.length; i < l; ++i) + { + var input = node.inputs[i]; + var link_pos = node.getConnectionPos(true,i); + if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) + { + if(slot_pos) { slot_pos[0] = link_pos[0]; slot_pos[1] = link_pos[1] }; + return i; + } + } + return -1; +} + +LGraphCanvas.prototype.processKey = function(e) +{ + if(!this.graph) + return; + + var block_default = false; + + if(e.type == "keydown") + { + //select all Control A + if(e.keyCode == 65 && e.ctrlKey) + { + this.selectAllNodes(); + block_default = true; + } + + //delete or backspace + if(e.keyCode == 46 || e.keyCode == 8) + { + this.deleteSelectedNodes(); + block_default = true; + } + + //collapse + //... + + //TODO + if(this.selected_nodes) + for (var i in this.selected_nodes) + if(this.selected_nodes[i].onKeyDown) + this.selected_nodes[i].onKeyDown(e); + } + else if( e.type == "keyup" ) + { + if(this.selected_nodes) + for (var i in this.selected_nodes) + if(this.selected_nodes[i].onKeyUp) + this.selected_nodes[i].onKeyUp(e); + } + + this.graph.change(); + + if(block_default) + { + e.preventDefault(); + return false; + } +} + +LGraphCanvas.prototype.processDrop = function(e) +{ + e.preventDefault(); + this.adjustMouseEvent(e); + + var pos = [e.canvasX,e.canvasY]; + var node = this.graph.getNodeOnPos(pos[0],pos[1]); + if(!node) + return; + + if(!node.onDropFile) + return; + + var file = e.dataTransfer.files[0]; + var filename = file.name; + var ext = LGraphCanvas.getFileExtension( filename ); + //console.log(file); + + //prepare reader + var reader = new FileReader(); + reader.onload = function (event) { + //console.log(event.target); + var data = event.target.result; + node.onDropFile( data, filename, file ); + }; + + //read data + var type = file.type.split("/")[0]; + if(type == "text" || type == "") + reader.readAsText(file); + else if (type == "image") + reader.readAsDataURL(file); + else + reader.readAsArrayBuffer(file); + + return false; +} + LGraphCanvas.prototype.processNodeSelected = function(n,e) { n.selected = true; @@ -3321,7 +3396,8 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //clear //canvas.width = canvas.width; - ctx.clearRect(0,0,canvas.width, canvas.height); + if(this.clear_background) + ctx.clearRect(0,0,canvas.width, canvas.height); //draw bg canvas if(this.bgcanvas == this.canvas) @@ -3335,19 +3411,7 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //info widget if(this.show_info) - { - ctx.font = "10px Arial"; - ctx.fillStyle = "#888"; - if(this.graph) - { - ctx.fillText( "T: " + this.graph.globaltime.toFixed(2)+"s",5,13*1 ); - ctx.fillText( "I: " + this.graph.iteration,5,13*2 ); - ctx.fillText( "F: " + this.frame,5,13*3 ); - ctx.fillText( "FPS:" + this.fps.toFixed(2),5,13*4 ); - } - else - ctx.fillText( "No graph selected",5,13*1 ); - } + this.renderInfo(ctx); if(this.graph) { @@ -3422,6 +3486,28 @@ LGraphCanvas.prototype.drawFrontCanvas = function() this.dirty_canvas = false; } +LGraphCanvas.prototype.renderInfo = function( ctx, x, y ) +{ + x = x || 0; + y = y || 0; + + ctx.save(); + ctx.translate( x, y ); + + ctx.font = "10px Arial"; + ctx.fillStyle = "#888"; + if(this.graph) + { + ctx.fillText( "T: " + this.graph.globaltime.toFixed(2)+"s",5,13*1 ); + ctx.fillText( "I: " + this.graph.iteration,5,13*2 ); + ctx.fillText( "F: " + this.frame,5,13*3 ); + ctx.fillText( "FPS:" + this.fps.toFixed(2),5,13*4 ); + } + else + ctx.fillText( "No graph selected",5,13*1 ); + ctx.restore(); +} + LGraphCanvas.prototype.drawBackCanvas = function() { var canvas = this.bgcanvas; @@ -3432,7 +3518,8 @@ LGraphCanvas.prototype.drawBackCanvas = function() ctx.start(); //clear - ctx.clearRect(0,0,canvas.width, canvas.height); + if(this.clear_background) + ctx.clearRect(0,0,canvas.width, canvas.height); //reset in case of error ctx.restore(); @@ -3633,7 +3720,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx ) var slot = node.inputs[i]; ctx.globalAlpha = editor_alpha; - if (this.connecting_node != null && this.connecting_output.type != 0 && node.inputs[i].type != 0 && this.connecting_output.type != node.inputs[i].type) + if (this.connecting_node != null && this.connecting_output.type && node.inputs[i].type && this.connecting_output.type.toLowerCase() != node.inputs[i].type.toLowerCase() ) ctx.globalAlpha = 0.4 * editor_alpha; ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA"; diff --git a/src/litegraph.js b/src/litegraph.js index cc4fd136d..dae09ae78 100644 --- a/src/litegraph.js +++ b/src/litegraph.js @@ -745,9 +745,10 @@ LGraph.prototype.findNodesByClass = function(classObject) LGraph.prototype.findNodesByType = function(type) { + var type = type.toLowerCase(); var r = []; for(var i in this._nodes) - if(this._nodes[i].type == type) + if(this._nodes[i].type.toLowerCase() == type ) r.push(this._nodes[i]); return r; } @@ -851,7 +852,7 @@ LGraph.prototype.changeGlobalInputType = function(name, type) if(!this.global_inputs[name]) return false; - if(this.global_inputs[name].type == type) + if(this.global_inputs[name].type.toLowerCase() == type.toLowerCase() ) return; this.global_inputs[name].type = type; @@ -932,7 +933,7 @@ LGraph.prototype.changeGlobalOutputType = function(name, type) if(!this.global_outputs[name]) return false; - if(this.global_outputs[name].type == type) + if(this.global_outputs[name].type.toLowerCase() == type.toLowerCase() ) return; this.global_outputs[name].type = type; @@ -1724,7 +1725,7 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) } else if( !output.type || //generic output !node.inputs[target_slot].type || //generic input - output.type == node.inputs[target_slot].type) //same type + output.type.toLowerCase() == node.inputs[target_slot].type.toLowerCase() ) //same type { //info: link structure => [ 0:link_id, 1:start_node_id, 2:start_slot, 3:end_node_id, 4:end_slot ] //var link = [ this.graph.last_link_id++, this.id, slot, node.id, target_slot ]; @@ -2044,16 +2045,13 @@ LGraphNode.prototype.localToScreen = function(x,y, graphcanvas) * @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format or the canvas itself) * @param {LGraph} graph [optional] */ -function LGraphCanvas(canvas, graph, skip_render) +function LGraphCanvas( canvas, graph, skip_render ) { //if(graph === undefined) // throw ("No graph assigned"); - if(typeof(canvas) == "string") - canvas = document.querySelector(canvas); - - if(!canvas) - throw("no canvas found"); + if(canvas && canvas.constructor === String ) + canvas = document.querySelector( canvas ); this.max_zoom = 10; this.min_zoom = 0.1; @@ -2062,7 +2060,7 @@ function LGraphCanvas(canvas, graph, skip_render) if(graph) graph.attachCanvas(this); - this.setCanvas(canvas); + this.setCanvas( canvas ); this.clear(); if(!skip_render) @@ -2097,9 +2095,7 @@ LGraphCanvas.prototype.clear = function() this.editor_alpha = 1; //used for transition this.pause_rendering = false; this.render_shadows = true; - this.dirty_canvas = true; - this.dirty_bgcanvas = true; - this.dirty_area = null; + this.clear_background = true; this.render_only_selected = true; this.live_mode = false; @@ -2107,6 +2103,10 @@ LGraphCanvas.prototype.clear = function() this.allow_dragcanvas = true; this.allow_dragnodes = true; + this.dirty_canvas = true; + this.dirty_bgcanvas = true; + this.dirty_area = null; + this.node_in_panel = null; this.last_mouse = [0,0]; @@ -2132,10 +2132,13 @@ LGraphCanvas.prototype.clear = function() * @method setGraph * @param {LGraph} graph */ -LGraphCanvas.prototype.setGraph = function(graph) +LGraphCanvas.prototype.setGraph = function( graph, skip_clear ) { - if(this.graph == graph) return; - this.clear(); + if(this.graph == graph) + return; + + if(!skip_clear) + this.clear(); if(!graph && this.graph) { @@ -2202,19 +2205,35 @@ LGraphCanvas.prototype.closeSubgraph = function() * @method setCanvas * @param {Canvas} assigns a canvas */ -LGraphCanvas.prototype.setCanvas = function(canvas) +LGraphCanvas.prototype.setCanvas = function( canvas, skip_events ) { var that = this; - //Canvas association - if(typeof(canvas) == "string") - canvas = document.getElementById(canvas); + if(canvas) + { + if( canvas.constructor === String ) + { + canvas = document.getElementById(canvas); + if(!canvas) + throw("Error creating LiteGraph canvas: Canvas not found"); + } + } - if(canvas == null) - throw("Error creating LiteGraph canvas: Canvas not found"); - if(canvas == this.canvas) return; + if(canvas === this.canvas) + return; + + if(!canvas && this.canvas) + { + //maybe detach events from old_canvas + if(!skip_events) + this.unbindEvents(); + } this.canvas = canvas; + + if(!canvas) + return; + //this.canvas.tabindex = "1000"; canvas.className += " lgraphcanvas"; canvas.data = this; @@ -2244,72 +2263,85 @@ LGraphCanvas.prototype.setCanvas = function(canvas) this._mousemove_callback = this.processMouseMove.bind(this); this._mouseup_callback = this.processMouseUp.bind(this); - canvas.addEventListener("mousedown", this.processMouseDown.bind(this), true ); //down do not need to store the binded - canvas.addEventListener("mousemove", this._mousemove_callback); + if(!skip_events) + this.bindEvents(); +} - canvas.addEventListener("contextmenu", function(e) { e.preventDefault(); return false; }); - - canvas.addEventListener("mousewheel", this.processMouseWheel.bind(this), false); - canvas.addEventListener("DOMMouseScroll", this.processMouseWheel.bind(this), false); +//used in some events to capture them +LGraphCanvas.prototype._doNothing = function doNothing() { return false; }; + +LGraphCanvas.prototype.bindEvents = function() +{ + if( this._events_binded ) + { + console.warn("LGraphCanvas: events already binded"); + return; + } + + var canvas = this.canvas; + + this._mousedown_callback = this.processMouseDown.bind(this); + this._mousewheel_callback = this.processMouseWheel.bind(this); + + canvas.addEventListener("mousedown", this._mousedown_callback, true ); //down do not need to store the binded + canvas.addEventListener("mousemove", this._mousemove_callback ); + canvas.addEventListener("mousewheel", this._mousewheel_callback, false); + + canvas.addEventListener("contextmenu", this._doNothing ); + canvas.addEventListener("DOMMouseScroll", this._mousewheel_callback, false); //touch events //if( 'touchstart' in document.documentElement ) { - //alert("doo"); canvas.addEventListener("touchstart", this.touchHandler, true); canvas.addEventListener("touchmove", this.touchHandler, true); canvas.addEventListener("touchend", this.touchHandler, true); canvas.addEventListener("touchcancel", this.touchHandler, true); } - //this.canvas.onselectstart = function () { return false; }; - canvas.addEventListener("keydown", function(e) { - that.processKeyDown(e); - }); + //Keyboard ****************** + this._key_callback = this.processKey.bind(this); - canvas.addEventListener("keyup", function(e) { - that.processKeyUp(e); - }); + canvas.addEventListener("keydown", this._key_callback ); + canvas.addEventListener("keyup", this._key_callback ); - //droping files - canvas.ondragover = function () { console.log('hover'); return false; }; - canvas.ondragend = function () { console.log('out'); return false; }; - canvas.ondrop = function (e) { - e.preventDefault(); - that.adjustMouseEvent(e); + //Droping Stuff over nodes ************************************ + this._ondrop_callback = this.processDrop.bind(this); - var pos = [e.canvasX,e.canvasY]; - var node = that.graph.getNodeOnPos(pos[0],pos[1]); - if(!node) - return; + canvas.addEventListener("dragover", this._doNothing, false ); + canvas.addEventListener("dragend", this._doNothing, false ); + canvas.addEventListener("drop", this._ondrop_callback, false ); - if(!node.onDropFile) - return; + this._events_binded = true; +} - var file = e.dataTransfer.files[0]; - var filename = file.name; - var ext = LGraphCanvas.getFileExtension( filename ); - //console.log(file); +LGraphCanvas.prototype.unbindEvents = function() +{ + if( !this._events_binded ) + { + console.warn("LGraphCanvas: no events binded"); + return; + } - //prepare reader - var reader = new FileReader(); - reader.onload = function (event) { - //console.log(event.target); - var data = event.target.result; - node.onDropFile( data, filename, file ); - }; + this.canvas.removeEventListener( "mousedown", this._mousedown_callback ); + this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback ); + this.canvas.removeEventListener( "DOMMouseScroll", this._mousewheel_callback ); + this.canvas.removeEventListener( "keydown", this._key_callback ); + this.canvas.removeEventListener( "keyup", this._key_callback ); + this.canvas.removeEventListener( "contextmenu", this._doNothing ); + this.canvas.removeEventListener( "drop", this._ondrop_callback ); - //read data - var type = file.type.split("/")[0]; - if(type == "text" || type == "") - reader.readAsText(file); - else if (type == "image") - reader.readAsDataURL(file); - else - reader.readAsArrayBuffer(file); + this.canvas.removeEventListener("touchstart", this.touchHandler ); + this.canvas.removeEventListener("touchmove", this.touchHandler ); + this.canvas.removeEventListener("touchend", this.touchHandler ); + this.canvas.removeEventListener("touchcancel", this.touchHandler ); - return false; - }; + this._mousedown_callback = null; + this._mousewheel_callback = null; + this._key_callback = null; + this._ondrop_callback = null; + + this._events_binded = false; } LGraphCanvas.getFileExtension = function (url) @@ -2466,13 +2498,15 @@ LGraphCanvas.prototype.stopRendering = function() LGraphCanvas.prototype.processMouseDown = function(e) { - if(!this.graph) return; + if(!this.graph) + return; this.adjustMouseEvent(e); var ref_window = this.getCanvasWindow(); var document = ref_window.document; + //move mouse move event to the window in case it drags outside of the canvas this.canvas.removeEventListener("mousemove", this._mousemove_callback ); ref_window.document.addEventListener("mousemove", this._mousemove_callback, true ); //catch for the entire window ref_window.document.addEventListener("mouseup", this._mouseup_callback, true ); @@ -2698,7 +2732,7 @@ LGraphCanvas.prototype.processMouseMove = function(e) if(slot != -1 && n.inputs[slot]) { var slot_type = n.inputs[slot].type; - if(slot_type == this.connecting_output.type || !slot_type || !this.connecting_output.type ) + if( !this.connecting_output.type || !slot_type || slot_type.toLowerCase() == this.connecting_output.type.toLowerCase() ) this._highlight_input = pos; } else @@ -2773,11 +2807,13 @@ LGraphCanvas.prototype.processMouseMove = function(e) LGraphCanvas.prototype.processMouseUp = function(e) { - if(!this.graph) return; + if(!this.graph) + return; var window = this.getCanvasWindow(); var document = window.document; + //restore the mousemove event back to the canvas document.removeEventListener("mousemove", this._mousemove_callback, true ); this.canvas.addEventListener("mousemove", this._mousemove_callback, true); document.removeEventListener("mouseup", this._mouseup_callback, true ); @@ -2814,7 +2850,7 @@ LGraphCanvas.prototype.processMouseUp = function(e) { //not on top of an input var input = node.getInputInfo(0); //simple connect - if(input && !input.link && input.type == this.connecting_output.type) + if(input && !input.link && input.type == this.connecting_output.type) //toLowerCase missing this.connecting_node.connect(this.connecting_slot, node, 0); } } @@ -2878,75 +2914,11 @@ LGraphCanvas.prototype.processMouseUp = function(e) return false; } -LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_pos) -{ - if(node.inputs) - for(var i = 0, l = node.inputs.length; i < l; ++i) - { - var input = node.inputs[i]; - var link_pos = node.getConnectionPos(true,i); - if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) - { - if(slot_pos) { slot_pos[0] = link_pos[0]; slot_pos[1] = link_pos[1] }; - return i; - } - } - return -1; -} - -LGraphCanvas.prototype.processKeyDown = function(e) -{ - if(!this.graph) return; - var block_default = false; - - //select all Control A - if(e.keyCode == 65 && e.ctrlKey) - { - this.selectAllNodes(); - block_default = true; - } - - //delete or backspace - if(e.keyCode == 46 || e.keyCode == 8) - { - this.deleteSelectedNodes(); - block_default = true; - } - - //collapse - //... - - //TODO - if(this.selected_nodes) - for (var i in this.selected_nodes) - if(this.selected_nodes[i].onKeyDown) - this.selected_nodes[i].onKeyDown(e); - - this.graph.change(); - - if(block_default) - { - e.preventDefault(); - return false; - } -} - -LGraphCanvas.prototype.processKeyUp = function(e) -{ - if(!this.graph) return; - //TODO - if(this.selected_nodes) - for (var i in this.selected_nodes) - if(this.selected_nodes[i].onKeyUp) - this.selected_nodes[i].onKeyUp(e); - - this.graph.change(); -} LGraphCanvas.prototype.processMouseWheel = function(e) { - if(!this.graph) return; - if(!this.allow_dragcanvas) return; + if(!this.graph || !this.allow_dragcanvas) + return; var delta = (e.wheelDeltaY != null ? e.wheelDeltaY : e.detail * -60); @@ -2972,6 +2944,109 @@ LGraphCanvas.prototype.processMouseWheel = function(e) return false; // prevent default } +LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_pos) +{ + if(node.inputs) + for(var i = 0, l = node.inputs.length; i < l; ++i) + { + var input = node.inputs[i]; + var link_pos = node.getConnectionPos(true,i); + if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) + { + if(slot_pos) { slot_pos[0] = link_pos[0]; slot_pos[1] = link_pos[1] }; + return i; + } + } + return -1; +} + +LGraphCanvas.prototype.processKey = function(e) +{ + if(!this.graph) + return; + + var block_default = false; + + if(e.type == "keydown") + { + //select all Control A + if(e.keyCode == 65 && e.ctrlKey) + { + this.selectAllNodes(); + block_default = true; + } + + //delete or backspace + if(e.keyCode == 46 || e.keyCode == 8) + { + this.deleteSelectedNodes(); + block_default = true; + } + + //collapse + //... + + //TODO + if(this.selected_nodes) + for (var i in this.selected_nodes) + if(this.selected_nodes[i].onKeyDown) + this.selected_nodes[i].onKeyDown(e); + } + else if( e.type == "keyup" ) + { + if(this.selected_nodes) + for (var i in this.selected_nodes) + if(this.selected_nodes[i].onKeyUp) + this.selected_nodes[i].onKeyUp(e); + } + + this.graph.change(); + + if(block_default) + { + e.preventDefault(); + return false; + } +} + +LGraphCanvas.prototype.processDrop = function(e) +{ + e.preventDefault(); + this.adjustMouseEvent(e); + + var pos = [e.canvasX,e.canvasY]; + var node = this.graph.getNodeOnPos(pos[0],pos[1]); + if(!node) + return; + + if(!node.onDropFile) + return; + + var file = e.dataTransfer.files[0]; + var filename = file.name; + var ext = LGraphCanvas.getFileExtension( filename ); + //console.log(file); + + //prepare reader + var reader = new FileReader(); + reader.onload = function (event) { + //console.log(event.target); + var data = event.target.result; + node.onDropFile( data, filename, file ); + }; + + //read data + var type = file.type.split("/")[0]; + if(type == "text" || type == "") + reader.readAsText(file); + else if (type == "image") + reader.readAsDataURL(file); + else + reader.readAsArrayBuffer(file); + + return false; +} + LGraphCanvas.prototype.processNodeSelected = function(n,e) { n.selected = true; @@ -3227,7 +3302,8 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //clear //canvas.width = canvas.width; - ctx.clearRect(0,0,canvas.width, canvas.height); + if(this.clear_background) + ctx.clearRect(0,0,canvas.width, canvas.height); //draw bg canvas if(this.bgcanvas == this.canvas) @@ -3241,19 +3317,7 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //info widget if(this.show_info) - { - ctx.font = "10px Arial"; - ctx.fillStyle = "#888"; - if(this.graph) - { - ctx.fillText( "T: " + this.graph.globaltime.toFixed(2)+"s",5,13*1 ); - ctx.fillText( "I: " + this.graph.iteration,5,13*2 ); - ctx.fillText( "F: " + this.frame,5,13*3 ); - ctx.fillText( "FPS:" + this.fps.toFixed(2),5,13*4 ); - } - else - ctx.fillText( "No graph selected",5,13*1 ); - } + this.renderInfo(ctx); if(this.graph) { @@ -3328,6 +3392,28 @@ LGraphCanvas.prototype.drawFrontCanvas = function() this.dirty_canvas = false; } +LGraphCanvas.prototype.renderInfo = function( ctx, x, y ) +{ + x = x || 0; + y = y || 0; + + ctx.save(); + ctx.translate( x, y ); + + ctx.font = "10px Arial"; + ctx.fillStyle = "#888"; + if(this.graph) + { + ctx.fillText( "T: " + this.graph.globaltime.toFixed(2)+"s",5,13*1 ); + ctx.fillText( "I: " + this.graph.iteration,5,13*2 ); + ctx.fillText( "F: " + this.frame,5,13*3 ); + ctx.fillText( "FPS:" + this.fps.toFixed(2),5,13*4 ); + } + else + ctx.fillText( "No graph selected",5,13*1 ); + ctx.restore(); +} + LGraphCanvas.prototype.drawBackCanvas = function() { var canvas = this.bgcanvas; @@ -3338,7 +3424,8 @@ LGraphCanvas.prototype.drawBackCanvas = function() ctx.start(); //clear - ctx.clearRect(0,0,canvas.width, canvas.height); + if(this.clear_background) + ctx.clearRect(0,0,canvas.width, canvas.height); //reset in case of error ctx.restore(); @@ -3539,7 +3626,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx ) var slot = node.inputs[i]; ctx.globalAlpha = editor_alpha; - if (this.connecting_node != null && this.connecting_output.type != 0 && node.inputs[i].type != 0 && this.connecting_output.type != node.inputs[i].type) + if (this.connecting_node != null && this.connecting_output.type && node.inputs[i].type && this.connecting_output.type.toLowerCase() != node.inputs[i].type.toLowerCase() ) ctx.globalAlpha = 0.4 * editor_alpha; ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA"; diff --git a/src/nodes/base.js b/src/nodes/base.js index c87513167..0e186698d 100644 --- a/src/nodes/base.js +++ b/src/nodes/base.js @@ -138,7 +138,7 @@ Subgraph.prototype.clone = function() } -LiteGraph.registerNodeType("graph/subgraph", Subgraph); +LiteGraph.registerNodeType("graph/subgraph", Subgraph ); //Input for a subgraph diff --git a/src/nodes/input.js b/src/nodes/input.js new file mode 100644 index 000000000..92e55436d --- /dev/null +++ b/src/nodes/input.js @@ -0,0 +1,132 @@ +(function(){ + +function GamepadInput() +{ + this.addOutput("left_x_axis","number"); + this.addOutput("left_y_axis","number"); + this.properties = {}; +} + +GamepadInput.title = "Gamepad"; +GamepadInput.desc = "gets the input of the gamepad"; + +GamepadInput.prototype.onExecute = function() +{ + //get gamepad + var gamepad = this.getGamepad(); + if(!gamepad) + return; + + if(this.outputs) + { + for(var i = 0; i < this.outputs.length; i++) + { + var output = this.outputs[i]; + var v = null; + switch( output.name ) + { + case "left_x_axis": v = gamepad.xbox.axes["lx"]; break; + case "left_y_axis": v = gamepad.xbox.axes["ly"]; break; + case "right_x_axis": v = gamepad.xbox.axes["rx"]; break; + case "right_y_axis": v = gamepad.xbox.axes["ry"]; break; + case "a_button": v = gamepad.xbox.buttons["a"] ? 1 : 0; break; + case "b_button": v = gamepad.xbox.buttons["b"] ? 1 : 0; break; + case "x_button": v = gamepad.xbox.buttons["x"] ? 1 : 0; break; + case "y_button": v = gamepad.xbox.buttons["y"] ? 1 : 0; break; + case "lb_button": v = gamepad.xbox.buttons["lb"] ? 1 : 0; break; + case "rb_button": v = gamepad.xbox.buttons["rb"] ? 1 : 0; break; + case "ls_button": v = gamepad.xbox.buttons["ls"] ? 1 : 0; break; + case "rs_button": v = gamepad.xbox.buttons["rs"] ? 1 : 0; break; + case "start_button": v = gamepad.xbox.buttons["start"] ? 1 : 0; break; + case "back_button": v = gamepad.xbox.buttons["back"] ? 1 : 0; break; + default: break; + } + this.setOutputData(i,v); + } + } +} + +GamepadInput.prototype.getGamepad = function() +{ + var getGamepads = navigator.getGamepads || navigator.webkitGetGamepads || navigator.mozGetGamepads; + if(!getGamepads) + return null; + var gamepads = getGamepads.call(navigator); + var gamepad = null; + + for(var i = 0; i < 4; i++) + { + if (gamepads[i]) + { + gamepad = gamepads[i]; + + //xbox controller mapping + var xbox = this.xbox_mapping; + if(!xbox) + xbox = this.xbox_mapping = { axes:[], buttons:{}, hat: ""}; + + xbox.axes["lx"] = gamepad.axes[0]; + xbox.axes["ly"] = gamepad.axes[1]; + xbox.axes["rx"] = gamepad.axes[2]; + xbox.axes["ry"] = gamepad.axes[3]; + xbox.axes["triggers"] = gamepad.axes[4]; + + for(var i = 0; i < gamepad.buttons.length; i++) + { + //mapping of XBOX + switch(i) //I use a switch to ensure that a player with another gamepad could play + { + case 0: xbox.buttons["a"] = gamepad.buttons[i].pressed; break; + case 1: xbox.buttons["b"] = gamepad.buttons[i].pressed; break; + case 2: xbox.buttons["x"] = gamepad.buttons[i].pressed; break; + case 3: xbox.buttons["y"] = gamepad.buttons[i].pressed; break; + case 4: xbox.buttons["lb"] = gamepad.buttons[i].pressed; break; + case 5: xbox.buttons["rb"] = gamepad.buttons[i].pressed; break; + case 6: xbox.buttons["lt"] = gamepad.buttons[i].pressed; break; + case 7: xbox.buttons["rt"] = gamepad.buttons[i].pressed; break; + case 8: xbox.buttons["back"] = gamepad.buttons[i].pressed; break; + case 9: xbox.buttons["start"] = gamepad.buttons[i].pressed; break; + case 10: xbox.buttons["ls"] = gamepad.buttons[i].pressed; break; + case 11: xbox.buttons["rs"] = gamepad.buttons[i].pressed; break; + case 12: if( gamepad.buttons[i].pressed) xbox.hat += "up"; break; + case 13: if( gamepad.buttons[i].pressed) xbox.hat += "down"; break; + case 14: if( gamepad.buttons[i].pressed) xbox.hat += "left"; break; + case 15: if( gamepad.buttons[i].pressed) xbox.hat += "right"; break; + case 16: xbox.buttons["home"] = gamepad.buttons[i].pressed; break; + default: + } + } + gamepad.xbox = xbox; + return gamepad; + } + } +} + +GamepadInput.prototype.onDrawBackground = function(ctx) +{ + //render +} + +GamepadInput.prototype.onGetOutputs = function() { + return [ + ["left_x_axis","number"], + ["left_y_axis","number"], + ["right_x_axis","number"], + ["right_y_axis","number"], + ["trigger","number"], + ["a_button","number"], + ["b_button","number"], + ["x_button","number"], + ["y_button","number"], + ["lb_button","number"], + ["rb_button","number"], + ["ls_button","number"], + ["rs_button","number"], + ["start","number"], + ["back","number"] + ]; +} + +LiteGraph.registerNodeType("input/gamepad", GamepadInput ); + +})(); \ No newline at end of file diff --git a/utils/deploy_files.txt b/utils/deploy_files.txt index 65cb39dd1..54e252603 100644 --- a/utils/deploy_files.txt +++ b/utils/deploy_files.txt @@ -1,6 +1,7 @@ ../src/litegraph.js ../src/nodes/base.js ../src/nodes/interface.js +../src/nodes/input.js ../src/nodes/math.js ../src/nodes/logic.js ../src/nodes/image.js