From a66d822e2a995f961ce5de65ffdb69640ce396cf Mon Sep 17 00:00:00 2001 From: atlasan Date: Sat, 2 Oct 2021 14:26:15 +0200 Subject: [PATCH] PointerEvents: from mouse events to pointer events v1 added LiteGraph.pointerevents_method with default "pointer" replaced EventListeners with pointerevents_method+"down", "up", etc.. replaced e.localX (and Y) for e.clientX (Y) fixed e.clientX is not writable TODO: finish checks and clean version with console.log("pointerevents..) enabled alpha working for mobile, touch enabled --- src/litegraph.js | 208 +++++++++++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 77 deletions(-) diff --git a/src/litegraph.js b/src/litegraph.js index 1f3f9c99d..f3fe0adee 100755 --- a/src/litegraph.js +++ b/src/litegraph.js @@ -98,7 +98,10 @@ searchbox_extras: {}, //used to add extra features to the search box auto_sort_node_types: false, // If set to true, will automatically sort node types / categories in the context menus - + + pointerevents_method: "pointer", // "mouse"|"pointer" use mouse for retrocompatibility issues + // TODO implement pointercancel, gotpointercapture, lostpointercapture, (pointerover, pointerout if necessary) + /** * Register a node class so it can be listed when the user wants to create a new one * @method registerNodeType @@ -4441,8 +4444,9 @@ LGraphNode.prototype.executeAction = function(action) this._binded_mouse_callback = this.onMouse.bind(this); - element.addEventListener("mousedown", this._binded_mouse_callback); - element.addEventListener("mousemove", this._binded_mouse_callback); + element.addEventListener(LiteGraph.pointerevents_method+"down", this._binded_mouse_callback); + element.addEventListener(LiteGraph.pointerevents_method+"move", this._binded_mouse_callback); + element.addEventListener(LiteGraph.pointerevents_method+"up", this._binded_mouse_callback); element.addEventListener( "mousewheel", @@ -4488,20 +4492,22 @@ LGraphNode.prototype.executeAction = function(action) e.canvasx = x; e.canvasy = y; e.dragging = this.dragging; - + var is_inside = !this.viewport || ( this.viewport && x >= this.viewport[0] && x < (this.viewport[0] + this.viewport[2]) && y >= this.viewport[1] && y < (this.viewport[1] + this.viewport[3]) ); + console.log("pointerevents:: DragAndScale onMouse "+e.type+" "+is_inside); + var ignore = false; if (this.onmouse) { ignore = this.onmouse(e); } - if (e.type == "mousedown" && is_inside) { + if (e.type == LiteGraph.pointerevents_method+"down" && is_inside) { this.dragging = true; - canvas.removeEventListener( "mousemove", this._binded_mouse_callback ); - document.body.addEventListener( "mousemove", this._binded_mouse_callback ); - document.body.addEventListener( "mouseup", this._binded_mouse_callback ); - } else if (e.type == "mousemove") { + canvas.removeEventListener( LiteGraph.pointerevents_method+"move", this._binded_mouse_callback ); + document.body.addEventListener( LiteGraph.pointerevents_method+"move", this._binded_mouse_callback ); + document.body.addEventListener( LiteGraph.pointerevents_method+"up", this._binded_mouse_callback ); + } else if (e.type == LiteGraph.pointerevents_method+"move") { if (!ignore) { var deltax = x - this.last_mouse[0]; var deltay = y - this.last_mouse[1]; @@ -4509,11 +4515,11 @@ LGraphNode.prototype.executeAction = function(action) this.mouseDrag(deltax, deltay); } } - } else if (e.type == "mouseup") { + } else if (e.type == LiteGraph.pointerevents_method+"up") { this.dragging = false; - document.body.removeEventListener( "mousemove", this._binded_mouse_callback ); - document.body.removeEventListener( "mouseup", this._binded_mouse_callback ); - canvas.addEventListener("mousemove", this._binded_mouse_callback ); + document.body.removeEventListener( LiteGraph.pointerevents_method+"move", this._binded_mouse_callback ); + document.body.removeEventListener( LiteGraph.pointerevents_method+"up", this._binded_mouse_callback ); + canvas.addEventListener(LiteGraph.pointerevents_method+"move", this._binded_mouse_callback ); } else if ( is_inside && (e.type == "mousewheel" || e.type == "wheel" || @@ -4982,8 +4988,8 @@ LGraphNode.prototype.executeAction = function(action) } //input: (move and up could be unbinded) - this._mousemove_callback = this.processMouseMove.bind(this); - this._mouseup_callback = this.processMouseUp.bind(this); + // why here? this._mousemove_callback = this.processMouseMove.bind(this); + // why here? this._mouseup_callback = this.processMouseUp.bind(this); if (!skip_events) { this.bindEvents(); @@ -4992,6 +4998,7 @@ LGraphNode.prototype.executeAction = function(action) //used in some events to capture them LGraphCanvas.prototype._doNothing = function doNothing(e) { + console.log("pointerevents:: _doNothing "+e.type); e.preventDefault(); return false; }; @@ -5010,6 +5017,8 @@ LGraphNode.prototype.executeAction = function(action) return; } + console.log("pointerevents:: binEvents"); + var canvas = this.canvas; var ref_window = this.getCanvasWindow(); @@ -5017,12 +5026,19 @@ LGraphNode.prototype.executeAction = function(action) this._mousedown_callback = this.processMouseDown.bind(this); this._mousewheel_callback = this.processMouseWheel.bind(this); - this._touch_callback = this.touchHandler.bind(this); + // why not binded here? this._mousemove_callback = this.processMouseMove.bind(this); + this._mousemove_callback = this.processMouseMove.bind(this); + this._mouseup_callback = this.processMouseUp.bind(this); + + //touch events -- THIS WAY DOES NOT WORK, finish implementing pointerevents, than clean the touchevents + //this._touch_callback = this.touchHandler.bind(this); - canvas.addEventListener("pointerdown", this._mousedown_callback, true); //down do not need to store the binded - canvas.addEventListener("mousemove", this._mousemove_callback); + canvas.addEventListener(LiteGraph.pointerevents_method+"down", this._mousedown_callback, true); //down do not need to store the binded canvas.addEventListener("mousewheel", this._mousewheel_callback, false); + canvas.addEventListener(LiteGraph.pointerevents_method+"up", this._mouseup_callback, true); + canvas.addEventListener(LiteGraph.pointerevents_method+"move", this._mousemove_callback); + canvas.addEventListener("contextmenu", this._doNothing); canvas.addEventListener( "DOMMouseScroll", @@ -5030,14 +5046,14 @@ LGraphNode.prototype.executeAction = function(action) false ); - //touch events - //if( 'touchstart' in document.documentElement ) + //touch events -- THIS WAY DOES NOT WORK, finish implementing pointerevents, than clean the touchevents + /*if( 'touchstart' in document.documentElement ) { canvas.addEventListener("touchstart", this._touch_callback, true); canvas.addEventListener("touchmove", this._touch_callback, true); canvas.addEventListener("touchend", this._touch_callback, true); canvas.addEventListener("touchcancel", this._touch_callback, true); - } + }*/ //Keyboard ****************** this._key_callback = this.processKey.bind(this); @@ -5066,10 +5082,14 @@ LGraphNode.prototype.executeAction = function(action) return; } + console.log("pointerevents:: unbindEvents"); + var ref_window = this.getCanvasWindow(); var document = ref_window.document; - this.canvas.removeEventListener("mousedown", this._mousedown_callback); + this.canvas.removeEventListener(LiteGraph.pointerevents_method+"move", this._mousedown_callback); + this.canvas.removeEventListener(LiteGraph.pointerevents_method+"up", this._mousedown_callback); + this.canvas.removeEventListener(LiteGraph.pointerevents_method+"down", this._mousedown_callback); this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback @@ -5084,10 +5104,11 @@ LGraphNode.prototype.executeAction = function(action) this.canvas.removeEventListener("drop", this._ondrop_callback); this.canvas.removeEventListener("dragenter", this._doReturnTrue); - this.canvas.removeEventListener("touchstart", this._touch_callback ); + //touch events -- THIS WAY DOES NOT WORK, finish implementing pointerevents, than clean the touchevents + /*this.canvas.removeEventListener("touchstart", this._touch_callback ); this.canvas.removeEventListener("touchmove", this._touch_callback ); this.canvas.removeEventListener("touchend", this._touch_callback ); - this.canvas.removeEventListener("touchcancel", this._touch_callback ); + this.canvas.removeEventListener("touchcancel", this._touch_callback );*/ this._mousedown_callback = null; this._mousewheel_callback = null; @@ -5217,7 +5238,7 @@ LGraphNode.prototype.executeAction = function(action) } LGraphCanvas.prototype.processMouseDown = function(e) { - + if( this.set_canvas_dirty_on_mouse_event ) this.dirty_canvas = true; @@ -5232,9 +5253,10 @@ LGraphNode.prototype.executeAction = function(action) LGraphCanvas.active_canvas = this; var that = this; - var x = e.localX; - var y = e.localY; + var x = e.clientX; + var y = e.clientY; //console.log(y,this.viewport); + console.log("pointerevents:: processMouseDown "+e.pointerId+" "+e.isPrimary+" :: "+x+" "+y); this.ds.viewport = this.viewport; var is_inside = !this.viewport || ( this.viewport && x >= this.viewport[0] && x < (this.viewport[0] + this.viewport[2]) && y >= this.viewport[1] && y < (this.viewport[1] + this.viewport[3]) ); @@ -5242,9 +5264,9 @@ LGraphNode.prototype.executeAction = function(action) //move mouse move event to the window in case it drags outside of the canvas if(!this.options.skip_events) { - 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 ); + this.canvas.removeEventListener(LiteGraph.pointerevents_method+"move", this._mousemove_callback); + ref_window.document.addEventListener( LiteGraph.pointerevents_method+"move", this._mousemove_callback, true ); //catch for the entire window + ref_window.document.addEventListener( LiteGraph.pointerevents_method+"up", this._mouseup_callback, true ); } if(!is_inside) @@ -5254,9 +5276,9 @@ LGraphNode.prototype.executeAction = function(action) var skip_dragging = false; var skip_action = false; var now = LiteGraph.getTime(); - var is_double_click = (now - this.last_mouseclick < 300) && (e.isPrimary); - this.mouse[0] = e.localX; - this.mouse[1] = e.localY; + var is_double_click = (now - this.last_mouseclick < 300) && (e.isPrimary!==undefined && e.isPrimary); + this.mouse[0] = e.clientX; + this.mouse[1] = e.clientY; this.graph_mouse[0] = e.canvasX; this.graph_mouse[1] = e.canvasY; this.last_click_position = [this.mouse[0],this.mouse[1]]; @@ -5508,8 +5530,10 @@ LGraphNode.prototype.executeAction = function(action) } if (!skip_action && clicking_canvas_bg && this.allow_dragcanvas) { - this.dragging_canvas = true; + console.log("pointerevents:: dragging_canvas start"); + this.dragging_canvas = true; } + } else if (e.which == 2) { //middle button } else if (e.which == 3) { @@ -5522,8 +5546,8 @@ LGraphNode.prototype.executeAction = function(action) //if(this.node_selected != prev_selected) // this.onNodeSelectionChange(this.node_selected); - this.last_mouse[0] = e.localX; - this.last_mouse[1] = e.localY; + this.last_mouse[0] = e.clientX; + this.last_mouse[1] = e.clientY; this.last_mouseclick = LiteGraph.getTime(); this.last_mouse_dragging = true; @@ -5571,7 +5595,7 @@ LGraphNode.prototype.executeAction = function(action) LGraphCanvas.active_canvas = this; this.adjustMouseEvent(e); - var mouse = [e.localX, e.localY]; + var mouse = [e.clientX, e.clientY]; this.mouse[0] = mouse[0]; this.mouse[1] = mouse[1]; var delta = [ @@ -5582,8 +5606,15 @@ LGraphNode.prototype.executeAction = function(action) this.graph_mouse[0] = e.canvasX; this.graph_mouse[1] = e.canvasY; + console.log("pointerevents:: processMouseMove "+e.pointerId+" "+e.isPrimary); + //convertEventToCanvasOffset + console.log(mouse); + console.log(this.graph_mouse); + //console.log(delta); + if(this.block_click) { + console.log("pointerevents:: processMouseMove block_click"); e.preventDefault(); return false; } @@ -5624,6 +5655,7 @@ LGraphNode.prototype.executeAction = function(action) } this.dirty_bgcanvas = true; } else if (this.dragging_canvas) { + //console.log("pointerevents:: processMouseMove is dragging_canvas"); this.ds.offset[0] += delta[0] / this.ds.scale; this.ds.offset[1] += delta[1] / this.ds.scale; this.dirty_canvas = true; @@ -5784,6 +5816,16 @@ LGraphNode.prototype.executeAction = function(action) **/ LGraphCanvas.prototype.processMouseUp = function(e) { + //early exit for extra pointer + if(e.isPrimary!==undefined && !e.isPrimary){ + /*e.stopPropagation(); + e.preventDefault();*/ + console.log("pointerevents:: processMouseUp pointerN_stop "+e.pointerId+" "+e.isPrimary); + return false; + } + + console.log("pointerevents:: processMouseUp "+e.pointerId+" "+e.isPrimary+" :: "+e.clientX+" "+e.clientY); + if( this.set_canvas_dirty_on_mouse_event ) this.dirty_canvas = true; @@ -5797,9 +5839,11 @@ LGraphNode.prototype.executeAction = function(action) //restore the mousemove event back to the canvas if(!this.options.skip_events) { - document.removeEventListener("mousemove",this._mousemove_callback,true); - this.canvas.addEventListener("mousemove",this._mousemove_callback,true); - document.removeEventListener("mouseup", this._mouseup_callback, true); + console.log("pointerevents:: processMouseUp removeEventListener"); + // why move listener from document to canvas? + document.removeEventListener(LiteGraph.pointerevents_method+"move",this._mousemove_callback,true); + this.canvas.addEventListener(LiteGraph.pointerevents_method+"move",this._mousemove_callback,true); + document.removeEventListener(LiteGraph.pointerevents_method+"up", this._mouseup_callback, true); } this.adjustMouseEvent(e); @@ -5810,10 +5854,12 @@ LGraphNode.prototype.executeAction = function(action) if(this.block_click) { - console.log("foo"); + console.log("pointerevents:: processMouseUp block_clicks"); this.block_click = false; //used to avoid sending twice a click in a immediate button } + console.log("pointerevents:: processMouseUp which: "+e.which); + if (e.which == 1) { if( this.node_widget ) @@ -6030,6 +6076,7 @@ LGraphNode.prototype.executeAction = function(action) this.graph.change(); + console.log("pointerevents:: processMouseUp stopPropagation"); e.stopPropagation(); e.preventDefault(); return false; @@ -6048,8 +6095,8 @@ LGraphNode.prototype.executeAction = function(action) this.adjustMouseEvent(e); - var x = e.localX; - var y = e.localY; + var x = e.clientX; + var y = e.clientY; var is_inside = !this.viewport || ( this.viewport && x >= this.viewport[0] && x < (this.viewport[0] + this.viewport[2]) && y >= this.viewport[1] && y < (this.viewport[1] + this.viewport[3]) ); if(!is_inside) return; @@ -6062,8 +6109,8 @@ LGraphNode.prototype.executeAction = function(action) scale *= 1 / 1.1; } - //this.setZoom( scale, [ e.localX, e.localY ] ); - this.ds.changeScale(scale, [e.localX, e.localY]); + //this.setZoom( scale, [ e.clientX, e.clientY ] ); + this.ds.changeScale(scale, [e.clientX, e.clientY]); this.graph.change(); @@ -6326,8 +6373,8 @@ LGraphNode.prototype.executeAction = function(action) LGraphCanvas.prototype.processDrop = function(e) { e.preventDefault(); this.adjustMouseEvent(e); - var x = e.localX; - var y = e.localY; + var x = e.clientX; + var y = e.clientY; var is_inside = !this.viewport || ( this.viewport && x >= this.viewport[0] && x < (this.viewport[0] + this.viewport[2]) && y >= this.viewport[1] && y < (this.viewport[1] + this.viewport[3]) ); if(!is_inside) return; @@ -6622,23 +6669,26 @@ LGraphNode.prototype.executeAction = function(action) * @method adjustMouseEvent **/ LGraphCanvas.prototype.adjustMouseEvent = function(e) { - if (this.canvas) { + + if (this.canvas) { var b = this.canvas.getBoundingClientRect(); - e.localX = e.clientX - b.left; - e.localY = e.clientY - b.top; + clientX_rel = e.clientX - b.left; + clientY_rel = e.clientY - b.top; } else { - e.localX = e.clientX; - e.localY = e.clientY; + clientX_rel = e.clientX; + clientY_rel = e.clientY; } + + e.deltaX = clientX_rel - this.last_mouse_position[0]; + e.deltaY = clientY_rel- this.last_mouse_position[1]; - e.deltaX = e.localX - this.last_mouse_position[0]; - e.deltaY = e.localY - this.last_mouse_position[1]; + this.last_mouse_position[0] = clientX_rel; + this.last_mouse_position[1] = clientY_rel; - this.last_mouse_position[0] = e.localX; - this.last_mouse_position[1] = e.localY; - - e.canvasX = e.localX / this.ds.scale - this.ds.offset[0]; - e.canvasY = e.localY / this.ds.scale - this.ds.offset[1]; + e.canvasX = clientX_rel / this.ds.scale - this.ds.offset[0]; + e.canvasY = clientY_rel / this.ds.scale - this.ds.offset[1]; + + console.log("pointerevents:: adjustMouseEvent "+e.clientX+":"+e.clientY+" "+clientX_rel+":"+clientY_rel+" "+e.canvasX+":"+e.canvasY); }; /** @@ -8951,7 +9001,7 @@ LGraphNode.prototype.executeAction = function(action) //inside widget switch (w.type) { case "button": - if (event.type === "mousedown") { + if (event.type === LiteGraph.pointerevents_method+"down") { if (w.callback) { setTimeout(function() { w.callback(w, that, node, pos, event); @@ -8975,7 +9025,7 @@ LGraphNode.prototype.executeAction = function(action) case "number": case "combo": var old_value = w.value; - if (event.type == "mousemove" && w.type == "number") { + if (event.type == LiteGraph.pointerevents_method+"move" && w.type == "number") { w.value += event.deltaX * 0.1 * (w.options.step || 1); if ( w.options.min != null && w.value < w.options.min ) { w.value = w.options.min; @@ -8983,7 +9033,7 @@ LGraphNode.prototype.executeAction = function(action) if ( w.options.max != null && w.value > w.options.max ) { w.value = w.options.max; } - } else if (event.type == "mousedown") { + } else if (event.type == LiteGraph.pointerevents_method+"down") { var values = w.options.values; if (values && values.constructor === Function) { values = w.options.values(w, node); @@ -9038,7 +9088,7 @@ LGraphNode.prototype.executeAction = function(action) } } } //end mousedown - else if(event.type == "mouseup" && w.type == "number") + else if(event.type == LiteGraph.pointerevents_method+"up" && w.type == "number") { var delta = x < 40 ? -1 : x > widget_width - 40 ? 1 : 0; if (event.click_time < 200 && delta == 0) { @@ -9060,7 +9110,7 @@ LGraphNode.prototype.executeAction = function(action) this.dirty_canvas = true; break; case "toggle": - if (event.type == "mousedown") { + if (event.type == LiteGraph.pointerevents_method+"down") { w.value = !w.value; setTimeout(function() { inner_value_change(w, w.value); @@ -9069,7 +9119,7 @@ LGraphNode.prototype.executeAction = function(action) break; case "string": case "text": - if (event.type == "mousedown") { + if (event.type == LiteGraph.pointerevents_method+"down") { this.prompt("Value",w.value,function(v) { this.value = v; inner_value_change(this, v); @@ -9228,7 +9278,11 @@ LGraphNode.prototype.executeAction = function(action) return; //disabled }; - LGraphCanvas.prototype.touchHandler = function(event) { + /* this is an implementation for touch not in production and not ready + * the idea is maybe good: simulate a similar event + * so let's try with pointerevents (working with both mouse and touch), and simulate the old mouseevents IF NECESSARY for retrocompatibility: existing old good nodes + */ + /*LGraphCanvas.prototype.touchHandler = function(event) { //alert("foo"); var touches = event.changedTouches, first = touches[0], @@ -9270,12 +9324,12 @@ LGraphNode.prototype.executeAction = function(action) false, false, false, - 0 /*left*/, + 0, //left null ); first.target.dispatchEvent(simulatedEvent); event.preventDefault(); - }; + };*/ /* CONTEXT MENU ********************/ @@ -9771,7 +9825,7 @@ LGraphNode.prototype.executeAction = function(action) dialog.style.transform = "scale(" + this.ds.scale + ")"; } - dialog.addEventListener("mouseleave", function(e) { + dialog.addEventListener(LiteGraph.pointerevents_method+"leave", function(e) { if (!modified) { dialog.close(); } @@ -9876,14 +9930,14 @@ LGraphNode.prototype.executeAction = function(action) dialog.style.transform = "scale(" + this.ds.scale + ")"; } - dialog.addEventListener("mouseenter", function(e) { + dialog.addEventListener(LiteGraph.pointerevents_method+"enter", function(e) { if (timeout_close) { clearTimeout(timeout_close); timeout_close = null; } }); - dialog.addEventListener("mouseleave", function(e) { + dialog.addEventListener(LiteGraph.pointerevents_method+"leave", function(e) { //dialog.close(); timeout_close = setTimeout(function() { dialog.close(); @@ -11499,7 +11553,7 @@ LGraphNode.prototype.executeAction = function(action) //this prevents the default context browser menu to open in case this menu was created when pressing right button root.addEventListener( - "mouseup", + LiteGraph.pointerevents_method+"up", function(e) { e.preventDefault(); return true; @@ -11520,7 +11574,7 @@ LGraphNode.prototype.executeAction = function(action) ); root.addEventListener( - "mousedown", + LiteGraph.pointerevents_method+"down", function(e) { if (e.button == 2) { that.close(); @@ -11569,7 +11623,7 @@ LGraphNode.prototype.executeAction = function(action) } //close on leave - root.addEventListener("mouseleave", function(e) { + root.addEventListener(LiteGraph.pointerevents_method+"leave", function(e) { if (that.lock) { return; } @@ -11580,7 +11634,7 @@ LGraphNode.prototype.executeAction = function(action) //that.close(e); }); - root.addEventListener("mouseenter", function(e) { + root.addEventListener(LiteGraph.pointerevents_method+"enter", function(e) { if (root.closing_timer) { clearTimeout(root.closing_timer); } @@ -11681,7 +11735,7 @@ LGraphNode.prototype.executeAction = function(action) element.addEventListener("click", inner_onclick); } if (options.autoopen) { - element.addEventListener("mouseenter", inner_over); + element.addEventListener(LiteGraph.pointerevents_method+"enter", inner_over); } function inner_over(e) { @@ -11776,7 +11830,7 @@ LGraphNode.prototype.executeAction = function(action) e && !ContextMenu.isCursorOverElement(e, this.parentMenu.root) ) { - ContextMenu.trigger(this.parentMenu.root, "mouseleave", e); + ContextMenu.trigger(this.parentMenu.root, LiteGraph.pointerevents_method+"leave", e); } } if (this.current_submenu) {