From 26fc942c795cab26063847288462f9ef36df1b42 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 23 Jun 2023 12:24:48 +0100 Subject: [PATCH 1/3] Improve wiring for horizontally aligned nodes --- .../@node-red/editor-client/src/js/ui/view.js | 158 ++++++++++++------ 1 file changed, 103 insertions(+), 55 deletions(-) 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 9fdbc3dde..b7dd48b66 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 @@ -1033,7 +1033,7 @@ RED.view = (function() { }) } - function generateLinkPath(origX,origY, destX, destY, sc) { + function generateLinkPath(origX,origY, destX, destY, sc, hasStatus = false) { var dy = destY-origY; var dx = destX-origX; var delta = Math.sqrt(dy*dy+dx*dx); @@ -1050,62 +1050,110 @@ RED.view = (function() { } else { scale = 0.4-0.2*(Math.max(0,(node_width-Math.min(Math.abs(dx),Math.abs(dy)))/node_width)); } + function genCP(cp) { + return ` M ${cp[0]-5} ${cp[1]} h 10 M ${cp[0]} ${cp[1]-5} v 10 ` + } if (dx*sc > 0) { - return "M "+origX+" "+origY+ - " C "+(origX+sc*(node_width*scale))+" "+(origY+scaleY*node_height)+" "+ - (destX-sc*(scale)*node_width)+" "+(destY-scaleY*node_height)+" "+ - destX+" "+destY + let cp = [ + [(origX+sc*(node_width*scale)), (origY+scaleY*node_height)], + [(destX-sc*(scale)*node_width), (destY-scaleY*node_height)] + ] + return `M ${origX} ${origY} C ${cp[0][0]} ${cp[0][1]} ${cp[1][0]} ${cp[1][1]} ${destX} ${destY}` + + ` ${genCP(cp[0])} ${genCP(cp[1])}` } else { + let topX, topY, bottomX, bottomY + let cp + let midX = Math.floor(destX-dx/2); + let midY = Math.floor(destY-dy/2); + if (Math.abs(dy) < 10) { + bottomY = Math.max(origY, destY) + (hasStatus?35:25) + let startCurveHeight = bottomY - origY + let endCurveHeight = bottomY - destY + cp = [ + [ origX + sc*15 , origY ], + [ origX + sc*25 , origY + 5 ], + [ origX + sc*25 , origY + startCurveHeight/2 ], - var midX = Math.floor(destX-dx/2); - var midY = Math.floor(destY-dy/2); - // - if (dy === 0) { - midY = destY + node_height; - } - var cp_height = node_height/2; - var y1 = (destY + midY)/2 - var topX =origX + sc*node_width*scale; - var topY = dy>0?Math.min(y1 - dy/2 , origY+cp_height):Math.max(y1 - dy/2 , origY-cp_height); - var bottomX = destX - sc*node_width*scale; - var bottomY = dy>0?Math.max(y1, destY-cp_height):Math.min(y1, destY+cp_height); - var x1 = (origX+topX)/2; - var scy = dy>0?1:-1; - var cp = [ - // Orig -> Top - [x1,origY], - [topX,dy>0?Math.max(origY, topY-cp_height):Math.min(origY, topY+cp_height)], - // Top -> Mid - // [Mirror previous cp] - [x1,dy>0?Math.min(midY, topY+cp_height):Math.max(midY, topY-cp_height)], - // Mid -> Bottom - // [Mirror previous cp] - [bottomX,dy>0?Math.max(midY, bottomY-cp_height):Math.min(midY, bottomY+cp_height)], - // Bottom -> Dest - // [Mirror previous cp] - [(destX+bottomX)/2,destY] - ]; - if (cp[2][1] === topY+scy*cp_height) { - if (Math.abs(dy) < cp_height*10) { - cp[1][1] = topY-scy*cp_height/2; - cp[3][1] = bottomY-scy*cp_height/2; - } - cp[2][0] = topX; - } - return "M "+origX+" "+origY+ - " C "+ - cp[0][0]+" "+cp[0][1]+" "+ - cp[1][0]+" "+cp[1][1]+" "+ - topX+" "+topY+ - " S "+ - cp[2][0]+" "+cp[2][1]+" "+ - midX+" "+midY+ - " S "+ - cp[3][0]+" "+cp[3][1]+" "+ - bottomX+" "+bottomY+ - " S "+ + [ origX + sc*25 , origY + startCurveHeight - 5 ], + [ origX + sc*15 , origY + startCurveHeight ], + [ origX , origY + startCurveHeight ], + + [ destX - sc*15, origY + startCurveHeight ], + [ destX - sc*25, origY + startCurveHeight - 5 ], + [ destX - sc*25, destY + endCurveHeight/2 ], + + [ destX - sc*25, destY + 5 ], + [ destX - sc*15, destY ], + [ destX, destY ], + ] + + return "M "+origX+" "+origY+ + " C "+ + cp[0][0]+" "+cp[0][1]+" "+ + cp[1][0]+" "+cp[1][1]+" "+ + cp[2][0]+" "+cp[2][1]+" "+ + " C " + + cp[3][0]+" "+cp[3][1]+" "+ cp[4][0]+" "+cp[4][1]+" "+ - destX+" "+destY + cp[5][0]+" "+cp[5][1]+" "+ + " h "+dx+ + " C "+ + cp[6][0]+" "+cp[6][1]+" "+ + cp[7][0]+" "+cp[7][1]+" "+ + cp[8][0]+" "+cp[8][1]+" "+ + " C " + + cp[9][0]+" "+cp[9][1]+" "+ + cp[10][0]+" "+cp[10][1]+" "+ + cp[11][0]+" "+cp[11][1]+" " + // +genCP(cp[0])+genCP(cp[1])+genCP(cp[2])+genCP(cp[3])+genCP(cp[4]) + // +genCP(cp[5])+genCP(cp[6])+genCP(cp[7])+genCP(cp[8])+genCP(cp[9])+genCP(cp[10]) + } else { + var cp_height = node_height/2; + var y1 = (destY + midY)/2 + topX = origX + sc*node_width*scale; + topY = dy>0?Math.min(y1 - dy/2 , origY+cp_height):Math.max(y1 - dy/2 , origY-cp_height); + bottomX = destX - sc*node_width*scale; + bottomY = dy>0?Math.max(y1, destY-cp_height):Math.min(y1, destY+cp_height); + var x1 = (origX+topX)/2; + var scy = dy>0?1:-1; + cp = [ + // Orig -> Top + [x1,origY], + [topX,dy>0?Math.max(origY, topY-cp_height):Math.min(origY, topY+cp_height)], + // Top -> Mid + // [Mirror previous cp] + [x1,dy>0?Math.min(midY, topY+cp_height):Math.max(midY, topY-cp_height)], + // Mid -> Bottom + // [Mirror previous cp] + [bottomX,dy>0?Math.max(midY, bottomY-cp_height):Math.min(midY, bottomY+cp_height)], + // Bottom -> Dest + // [Mirror previous cp] + [(destX+bottomX)/2,destY] + ]; + if (cp[2][1] === topY+scy*cp_height) { + if (Math.abs(dy) < cp_height*10) { + cp[1][1] = topY-scy*cp_height/2; + cp[3][1] = bottomY-scy*cp_height/2; + } + cp[2][0] = topX; + } + return "M "+origX+" "+origY+ + " C "+ + cp[0][0]+" "+cp[0][1]+" "+ + cp[1][0]+" "+cp[1][1]+" "+ + topX+" "+topY+ + " S "+ + cp[2][0]+" "+cp[2][1]+" "+ + midX+" "+midY+ + " S "+ + cp[3][0]+" "+cp[3][1]+" "+ + bottomX+" "+bottomY+ + " S "+ + cp[4][0]+" "+cp[4][1]+" "+ + destX+" "+destY + + // +genCP(cp[0])+genCP(cp[1])+genCP(cp[2])+genCP(cp[3])+genCP(cp[4]) + } } } @@ -1722,7 +1770,7 @@ RED.view = (function() { var portY = -((numOutputs-1)/2)*13 +13*sourcePort; var sc = (drag_line.portType === PORT_TYPE_OUTPUT)?1:-1; - drag_line.el.attr("d",generateLinkPath(drag_line.node.x+sc*drag_line.node.w/2,drag_line.node.y+portY,mousePos[0],mousePos[1],sc)); + drag_line.el.attr("d",generateLinkPath(drag_line.node.x+sc*drag_line.node.w/2,drag_line.node.y+portY,mousePos[0],mousePos[1],sc, !!drag_line.node.status)); } d3.event.preventDefault(); } else if (mouse_mode == RED.state.MOVING) { @@ -5067,7 +5115,7 @@ RED.view = (function() { // " C "+(d.x1+scale*node_width)+" "+(d.y1+scaleY*node_height)+" "+ // (d.x2-scale*node_width)+" "+(d.y2-scaleY*node_height)+" "+ // d.x2+" "+d.y2; - var path = generateLinkPath(d.x1,d.y1,d.x2,d.y2,1); + var path = generateLinkPath(d.x1,d.y1,d.x2,d.y2,1, !!(d.source.status || d.target.status)); if (/NaN/.test(path)) { path = "" } From 11f9ad8ca3772e59e4e117d8787e120917ec9fbb Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 23 Jun 2023 12:29:33 +0100 Subject: [PATCH 2/3] Remove debug for wiring --- packages/node_modules/@node-red/editor-client/src/js/ui/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b7dd48b66..50ee25dfa 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 @@ -1059,7 +1059,7 @@ RED.view = (function() { [(destX-sc*(scale)*node_width), (destY-scaleY*node_height)] ] return `M ${origX} ${origY} C ${cp[0][0]} ${cp[0][1]} ${cp[1][0]} ${cp[1][1]} ${destX} ${destY}` - + ` ${genCP(cp[0])} ${genCP(cp[1])}` + // + ` ${genCP(cp[0])} ${genCP(cp[1])}` } else { let topX, topY, bottomX, bottomY let cp From 56ed32e4a19bf68e51fd10743e2e62d991d28d5e Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 23 Jun 2023 16:09:34 +0100 Subject: [PATCH 3/3] Add background to node status --- .../@node-red/editor-client/src/js/ui/view.js | 41 ++++++++++++++----- .../editor-client/src/sass/flow.scss | 6 ++- 2 files changed, 35 insertions(+), 12 deletions(-) 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 50ee25dfa..a49133af7 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 @@ -4160,21 +4160,27 @@ RED.view = (function() { nodeEl.__statusGroup__.style.display = "none"; } else { nodeEl.__statusGroup__.style.display = "inline"; + let backgroundWidth = 12 var fill = status_colours[d.status.fill]; // Only allow our colours for now if (d.status.shape == null && fill == null) { + backgroundWidth = 0 nodeEl.__statusShape__.style.display = "none"; + nodeEl.__statusBackground__.setAttribute("x", 17) nodeEl.__statusGroup__.setAttribute("transform","translate(-14,"+(d.h+3)+")"); } else { nodeEl.__statusGroup__.setAttribute("transform","translate(3,"+(d.h+3)+")"); var statusClass = "red-ui-flow-node-status-"+(d.status.shape||"dot")+"-"+d.status.fill; nodeEl.__statusShape__.style.display = "inline"; nodeEl.__statusShape__.setAttribute("class","red-ui-flow-node-status "+statusClass); + nodeEl.__statusBackground__.setAttribute("x", 3) } if (d.status.hasOwnProperty('text')) { nodeEl.__statusLabel__.textContent = d.status.text; } else { nodeEl.__statusLabel__.textContent = ""; } + const textSize = nodeEl.__statusLabel__.getBBox() + nodeEl.__statusBackground__.setAttribute('width', backgroundWidth + textSize.width + 6) } delete d.dirtyStatus; } @@ -4580,17 +4586,30 @@ RED.view = (function() { statusEl.style.display = "none"; node[0][0].__statusGroup__ = statusEl; - var statusRect = document.createElementNS("http://www.w3.org/2000/svg","rect"); - statusRect.setAttribute("class","red-ui-flow-node-status"); - statusRect.setAttribute("x",6); - statusRect.setAttribute("y",1); - statusRect.setAttribute("width",9); - statusRect.setAttribute("height",9); - statusRect.setAttribute("rx",2); - statusRect.setAttribute("ry",2); - statusRect.setAttribute("stroke-width","3"); - statusEl.appendChild(statusRect); - node[0][0].__statusShape__ = statusRect; + var statusBackground = document.createElementNS("http://www.w3.org/2000/svg","rect"); + statusBackground.setAttribute("class","red-ui-flow-node-status-background"); + statusBackground.setAttribute("x",3); + statusBackground.setAttribute("y",-1); + statusBackground.setAttribute("width",200); + statusBackground.setAttribute("height",13); + statusBackground.setAttribute("rx",1); + statusBackground.setAttribute("ry",1); + + statusEl.appendChild(statusBackground); + node[0][0].__statusBackground__ = statusBackground; + + + var statusIcon = document.createElementNS("http://www.w3.org/2000/svg","rect"); + statusIcon.setAttribute("class","red-ui-flow-node-status"); + statusIcon.setAttribute("x",6); + statusIcon.setAttribute("y",1); + statusIcon.setAttribute("width",9); + statusIcon.setAttribute("height",9); + statusIcon.setAttribute("rx",2); + statusIcon.setAttribute("ry",2); + statusIcon.setAttribute("stroke-width","3"); + statusEl.appendChild(statusIcon); + node[0][0].__statusShape__ = statusIcon; var statusLabel = document.createElementNS("http://www.w3.org/2000/svg","text"); statusLabel.setAttribute("class","red-ui-flow-node-status-label"); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/flow.scss b/packages/node_modules/@node-red/editor-client/src/sass/flow.scss index 0eb68656b..bd83e3eff 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/flow.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/flow.scss @@ -304,7 +304,11 @@ g.red-ui-flow-node-selected { stroke: var(--red-ui-node-status-colors-#{"" + $current-color}); } } - +.red-ui-flow-node-status-background { + stroke: none; + fill: var(--red-ui-view-background); + fill-opacity: 0.9; +} .red-ui-flow-node-status-label { @include disable-selection; stroke-width: 0;