diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js index d16843a22..f503beecb 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js @@ -1305,6 +1305,39 @@ RED.view.tools = (function() { } } + /** + * Determine if a point is within a node + * @param {*} node - A Node or Junction node + * @param {[Number,Number]} mouse_position The x,y position of the mouse + * @param {Number} [marginX=0] - A margin to add or deduct from the x position (to increase the hit area) + * @param {Number} [marginY=0] - A margin to add or deduct from the y position (to increase the hit area) + * @returns + */ + function isPointInNode (node, [x, y], marginX, marginY) { + marginX = marginX || 0 + marginY = marginY || 0 + + let w = node.w || 10 // junctions dont have any w or h value + let h = node.h || 10 + let x1, x2, y1, y2 + + if (node.type === "junction" || node.type === "group") { + // x/y is the top left of the node + x1 = node.x + y1 = node.y + x2 = node.x + w + y2 = node.y + h + } else { + // x/y is the center of the node + const [xMid, yMid] = [w/2, h/2] + x1 = node.x - xMid + y1 = node.y - yMid + x2 = node.x + xMid + y2 = node.y + yMid + } + return (x >= (x1 - marginX) && x <= (x2 + marginX) && y >= (y1 - marginY) && y <= (y2 + marginY)) + } + return { init: function() { RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); }) @@ -1387,7 +1420,8 @@ RED.view.tools = (function() { * @param {Number} dy */ moveSelection: moveSelection, - calculateGridSnapOffsets: calculateGridSnapOffsets + calculateGridSnapOffsets: calculateGridSnapOffsets, + isPointInNode: isPointInNode } })(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index a49133af7..fd9bd3c96 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -101,7 +101,7 @@ RED.view = (function() { // Note: these are the permitted status colour aliases. The actual RGB values // are set in the CSS - flow.scss/colors.scss - var status_colours = { + const status_colours = { "red": "#c00", "green": "#5a8", "yellow": "#F9DF31", @@ -110,19 +110,32 @@ RED.view = (function() { "gray": "#d3d3d3" } - var PORT_TYPE_INPUT = 1; - var PORT_TYPE_OUTPUT = 0; + const PORT_TYPE_INPUT = 1; + const PORT_TYPE_OUTPUT = 0; - var chart; - var outer; + /** + * The jQuery object for the workspace chart `#red-ui-workspace-chart` div element + * @type {JQuery} #red-ui-workspace-chart HTML Element + */ + let chart; + /** + * The d3 object `#red-ui-workspace-chart` svg element + * @type {d3.Selection} + */ + let outer; + /** + * The d3 object `#red-ui-workspace-chart` svg element (specifically for events) + * @type {d3.Selection} + */ var eventLayer; - var gridLayer; - var linkLayer; - var junctionLayer; - var dragGroupLayer; - var groupSelectLayer; - var nodeLayer; - var groupLayer; + + /** @type {SVGGElement} */ let gridLayer; + /** @type {SVGGElement} */ let linkLayer; + /** @type {SVGGElement} */ let junctionLayer; + /** @type {SVGGElement} */ let dragGroupLayer; + /** @type {SVGGElement} */ let groupSelectLayer; + /** @type {SVGGElement} */ let nodeLayer; + /** @type {SVGGElement} */ let groupLayer; var drag_lines; const movingSet = (function() { @@ -391,16 +404,6 @@ RED.view = (function() { touchStartTime = setTimeout(function() { touchStartTime = null; showTouchMenu(obj,pos); - //lasso = eventLayer.append("rect") - // .attr("ox",point[0]) - // .attr("oy",point[1]) - // .attr("rx",2) - // .attr("ry",2) - // .attr("x",point[0]) - // .attr("y",point[1]) - // .attr("width",0) - // .attr("height",0) - // .attr("class","nr-ui-view-lasso"); },touchLongPressTimeout); } d3.event.preventDefault(); @@ -3094,22 +3097,38 @@ RED.view = (function() { } } document.body.style.cursor = ""; + if (mouse_mode == RED.state.JOINING || mouse_mode == RED.state.QUICK_JOINING) { if (typeof TouchEvent != "undefined" && evt instanceof TouchEvent) { - var found = false; - RED.nodes.eachNode(function(n) { - if (n.z == RED.workspaces.active()) { - var hw = n.w/2; - var hh = n.h/2; - if (n.x-hw mouse_position[0] && - n.y-hhmouse_position[1]) { - found = true; - mouseup_node = n; - portType = mouseup_node.inputs>0?PORT_TYPE_INPUT:PORT_TYPE_OUTPUT; - portIndex = 0; + if (RED.view.DEBUG) { console.warn("portMouseUp: TouchEvent", mouse_mode,d,portType,portIndex); } + const direction = drag_lines[0].portType === PORT_TYPE_INPUT ? PORT_TYPE_OUTPUT : PORT_TYPE_INPUT + let found = false; + for (let nodeIdx = 0; nodeIdx < activeNodes.length; nodeIdx++) { + const n = activeNodes[nodeIdx]; + if (RED.view.tools.isPointInNode(n, mouse_position)) { + found = true; + mouseup_node = n; + // portType = mouseup_node.inputs > 0 ? PORT_TYPE_INPUT : PORT_TYPE_OUTPUT; + portType = direction; + portIndex = 0; + break + } + } + + if (!found && drag_lines.length > 0 && !drag_lines[0].virtualLink) { + for (let juncIdx = 0; juncIdx < activeJunctions.length; juncIdx++) { + // NOTE: a junction is 10px x 10px but the target area is expanded to 30wx20h by adding padding to the bounding box + const jNode = activeJunctions[juncIdx]; + if (RED.view.tools.isPointInNode(jNode, mouse_position, 20, 10)) { + found = true; + mouseup_node = jNode; + portType = direction; + portIndex = 0; + break } } - }); + } + if (!found && activeSubflow) { var subflowPorts = []; if (activeSubflow.status) { @@ -3121,16 +3140,13 @@ RED.view = (function() { if (activeSubflow.out) { subflowPorts = subflowPorts.concat(activeSubflow.out) } - for (var i=0;i mouse_position[0] && - n.y-hhmouse_position[1]) { - found = true; - mouseup_node = n; - portType = mouseup_node.direction === "in"?PORT_TYPE_OUTPUT:PORT_TYPE_INPUT; - portIndex = 0; + for (var i = 0; i < subflowPorts.length; i++) { + const sf = subflowPorts[i]; + if (RED.view.tools.isPointInNode(sf, mouse_position)) { + found = true; + mouseup_node = sf; + portType = mouseup_node.direction === "in" ? PORT_TYPE_OUTPUT : PORT_TYPE_INPUT; + portIndex = 0; break; } } @@ -5015,16 +5031,25 @@ RED.view = (function() { contents.appendChild(junctionOutput); junctionOutput.addEventListener("mouseup", portMouseUpProxy); junctionOutput.addEventListener("mousedown", portMouseDownProxy); - junctionOutput.addEventListener("mouseover", junctionMouseOverProxy); junctionOutput.addEventListener("mouseout", junctionMouseOutProxy); + junctionOutput.addEventListener("touchmove", junctionMouseOverProxy); + junctionOutput.addEventListener("touchend", portMouseUpProxy); + junctionOutput.addEventListener("touchstart", portMouseDownProxy); + junctionInput.addEventListener("mouseover", junctionMouseOverProxy); junctionInput.addEventListener("mouseout", junctionMouseOutProxy); + junctionInput.addEventListener("touchmove", junctionMouseOverProxy); + junctionInput.addEventListener("touchend", portMouseUpProxy); + junctionInput.addEventListener("touchstart", portMouseDownProxy); + junctionBack.addEventListener("mouseover", junctionMouseOverProxy); junctionBack.addEventListener("mouseout", junctionMouseOutProxy); + junctionBack.addEventListener("touchmove", junctionMouseOverProxy); // These handlers expect to be registered as d3 events d3.select(junctionBack).on("mousedown", nodeMouseDown).on("mouseup", nodeMouseUp); + d3.select(junctionBack).on("touchstart", nodeMouseDown).on("touchend", nodeMouseUp); junction[0][0].appendChild(contents); })