From 2350540a983a726ff8d06119a85a914e01893cf8 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Sun, 7 Aug 2022 22:28:08 +0100 Subject: [PATCH] Introduce RED.utils.createSVGElement --- .../editor-client/src/js/ui/utils.js | 14 +- .../src/js/ui/view-annotations.js | 3 +- .../editor-client/src/js/ui/view-navigator.js | 227 +++++++------ .../@node-red/editor-client/src/js/ui/view.js | 307 +++++++++--------- 4 files changed, 286 insertions(+), 265 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js b/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js index 2c4cdca6b..2f30f1dc4 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js @@ -1397,6 +1397,17 @@ RED.utils = (function() { return r; } + function createSVGElement(tag, attrs = {}, parent) { + const element = document.createElementNS('http://www.w3.org/2000/svg', tag) + for (const k in attrs) { + element.setAttribute(k, attrs[k]) + } + if (parent) { + parent.appendChild(element) + } + return element + } + return { createObjectElement: createObjectElement, getMessageProperty: getMessageProperty, @@ -1420,6 +1431,7 @@ RED.utils = (function() { getDarkerColor: getDarkerColor, parseModuleList: parseModuleList, checkModuleAllowed: checkModuleAllowed, - getBrowserInfo: getBrowserInfo + getBrowserInfo: getBrowserInfo, + createSVGElement: createSVGElement } })(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js index 1df8c4bd1..d6a14e3cb 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js @@ -91,8 +91,7 @@ RED.view.annotations = (function() { function addAnnotation(id,evt) { var opts = annotations[id]; evt.el.__annotations__ = evt.el.__annotations__ || []; - var annotationGroup = document.createElementNS("http://www.w3.org/2000/svg","g"); - annotationGroup.setAttribute("class",opts.class || ""); + var annotationGroup = RED.utils.createSVGElement("g", { class: opts.class || '' }) evt.el.__annotations__.push({ id:id, element: annotationGroup diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js index a3001e474..2a29c7d10 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js @@ -15,133 +15,128 @@ **/ - RED.view.navigator = (function() { +RED.view.navigator = (function() { + var nav_scale = 25; + var nav_width = 5000/nav_scale; + var nav_height = 5000/nav_scale; - var nav_scale = 25; - var nav_width = 5000/nav_scale; - var nav_height = 5000/nav_scale; + var navContainer; + var navBox; + var navBorder; + var scrollPos; + var scaleFactor; + var chartSize; + var dimensions; + var isDragging; + var isShowing = false; - var navContainer; - var navBox; - var navBorder; - var navVis; - var scrollPos; - var scaleFactor; - var chartSize; - var dimensions; - var isDragging; - var isShowing = false; + var domSelection - function refreshNodes() { - if (!isShowing) { - return; - } - var navNode = navVis.selectAll(".red-ui-navigator-node").data(RED.view.getActiveNodes(),function(d){return d.id}); - navNode.exit().remove(); - navNode.enter().insert("rect") - .attr('class','red-ui-navigator-node') - .attr("pointer-events", "none"); - navNode.each(function(d) { - d3.select(this).attr("x",function(d) { return (d.x-d.w/2)/nav_scale }) - .attr("y",function(d) { return (d.y-d.h/2)/nav_scale }) - .attr("width",function(d) { return Math.max(9,d.w/nav_scale) }) - .attr("height",function(d) { return Math.max(3,d.h/nav_scale) }) - .attr("fill",function(d) { return RED.utils.getNodeColor(d.type,d._def);}) - }); - } - function onScroll() { - if (!isDragging) { - resizeNavBorder(); - } - } - function resizeNavBorder() { - if (navBorder) { - scaleFactor = RED.view.scale(); - chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()]; - scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()]; - navBorder.attr('x',scrollPos[0]/nav_scale) - .attr('y',scrollPos[1]/nav_scale) - .attr('width',chartSize[0]/nav_scale/scaleFactor) - .attr('height',chartSize[1]/nav_scale/scaleFactor) - } - } - function toggle() { - if (!isShowing) { - isShowing = true; - $("#red-ui-view-navigate").addClass("selected"); - resizeNavBorder(); - refreshNodes(); - $("#red-ui-workspace-chart").on("scroll",onScroll); - navContainer.fadeIn(200); - } else { - isShowing = false; - navContainer.fadeOut(100); - $("#red-ui-workspace-chart").off("scroll",onScroll); - $("#red-ui-view-navigate").removeClass("selected"); - } - } + function refreshNodes() { + if (!isShowing) { + return; + } + domSelection.refresh(RED.view.getActiveNodes()) + } - return { - init: function() { + function onScroll() { + if (!isDragging) { + resizeNavBorder(); + } + } + function resizeNavBorder() { + if (navBorder) { + scaleFactor = RED.view.scale(); + chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()]; + scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()]; - $(window).on("resize", resizeNavBorder); - RED.events.on("sidebar:resize",resizeNavBorder); - RED.actions.add("core:toggle-navigator",toggle); - var hideTimeout; + navBorder.attr('x', scrollPos[0]/nav_scale) + navBorder.attr('y', scrollPos[1]/nav_scale) + navBorder.attr('width',chartSize[0]/nav_scale/scaleFactor) + navBorder.attr('height',chartSize[1]/nav_scale/scaleFactor) + } + } + function toggle() { + if (!isShowing) { + isShowing = true; + $("#red-ui-view-navigate").addClass("selected"); + resizeNavBorder(); + refreshNodes(); + $("#red-ui-workspace-chart").on("scroll",onScroll); + navContainer.fadeIn(200); + } else { + isShowing = false; + navContainer.fadeOut(100); + $("#red-ui-workspace-chart").off("scroll",onScroll); + $("#red-ui-view-navigate").removeClass("selected"); + } + } - navContainer = $('
').css({ - "position":"absolute", - "bottom":$("#red-ui-workspace-footer").height(), - "right":0, - zIndex: 1 - }).appendTo("#red-ui-workspace").hide(); + return { + init: function() { - navBox = d3.select(navContainer[0]) - .append("svg:svg") - .attr("width", nav_width) - .attr("height", nav_height) - .attr("pointer-events", "all") - .attr("id","red-ui-navigator-canvas") + $(window).on("resize", resizeNavBorder); + RED.events.on("sidebar:resize",resizeNavBorder); + RED.actions.add("core:toggle-navigator",toggle); - navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({ - fill:"none", - stroke:"none", - pointerEvents:"all" - }).on("mousedown", function() { - // Update these in case they have changed - scaleFactor = RED.view.scale(); - chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()]; - dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor]; - var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]); - var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]); - navBorder.attr('x',newX).attr('y',newY); - isDragging = true; - $("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor); - $("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor); - }).on("mousemove", function() { - if (!isDragging) { return } - if (d3.event.buttons === 0) { - isDragging = false; - return; - } - var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]); - var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]); - navBorder.attr('x',newX).attr('y',newY); - $("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor); - $("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor); - }).on("mouseup", function() { - isDragging = false; - }) + navContainer = $('
').css({ + "position":"absolute", + "bottom":$("#red-ui-workspace-footer").height(), + "right":0, + zIndex: 1 + }).appendTo("#red-ui-workspace").hide(); - navBorder = navBox.append("rect").attr("class","red-ui-navigator-border") + navBox = $(RED.utils.createSVGElement('svg', {id: "red-ui-navigator-canvas", width: nav_width, height: nav_height, 'pointer-events': 'all'})).appendTo(navContainer) - navVis = navBox.append("svg:g") + const navBoxBody = $(RED.utils.createSVGElement("rect", { x: 0, y: 0, width: nav_width, height: nav_height, fill: 'none', stroke: 'none', 'pointer-events': 'all'})) + .css({'cursor': 'pointer'}) + navBoxBody.on('mousedown',function(event) { + // Update these in case they have changed + scaleFactor = RED.view.scale(); + chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()]; + dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor]; + var newX = Math.max(0,Math.min(event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]); + var newY = Math.max(0,Math.min(event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]); + navBorder.attr('x',newX) + navBorder.attr('y',newY); + isDragging = true; + $("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor); + $("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor); + }).on('mousemove', function(event) { + if (!isDragging) { return } + if (event.buttons === 0) { + isDragging = false; + return; + } + var newX = Math.max(0,Math.min(event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]); + var newY = Math.max(0,Math.min(event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]); + navBorder.attr('x',newX) + navBorder.attr('y',newY); + $("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor); + $("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor); + }).on('mouseup', function() { + isDragging = false; + }).appendTo(navBox) - RED.statusBar.add({ - id: "view-navigator", - align: "right", - element: $('') - }) + navBorder = $(RED.utils.createSVGElement("rect", { "class": "red-ui-navigator-border" })).appendTo(navBox) + + const navVis = $(RED.utils.createSVGElement('g')).appendTo(navBox) + + domSelection = RED.utils.domSelection(navVis[0], '.red-ui-navigator-node', function() { + return RED.utils.createSVGElement('rect', { class: 'red-ui-navigator-node', 'pointer-events': 'none' }) + }, function(node) { + node.setAttribute('x', (this.x-this.w/2)/nav_scale) + node.setAttribute('y', (this.y-this.h/2)/nav_scale) + node.setAttribute('width', Math.max(9,this.w/nav_scale)) + node.setAttribute('height', Math.max(3,this.h/nav_scale)) + node.setAttribute('fill', RED.utils.getNodeColor(this.type,this._def)) + }) + + RED.statusBar.add({ + id: "view-navigator", + align: "right", + element: $('') + }) $("#red-ui-view-navigate").on("click", function(evt) { evt.preventDefault(); 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 6de33872e..37084d5cb 100755 --- 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 @@ -700,11 +700,11 @@ RED.view = (function() { type: "badge", class: "red-ui-flow-node-changed", element: function() { - var changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle"); - changeBadge.setAttribute("cx",5); - changeBadge.setAttribute("cy",5); - changeBadge.setAttribute("r",5); - return changeBadge; + return RED.utils.createSVGElement("circle", { + cx: 5, + cy: 5, + r: 5 + }) }, show: function(n) { return n.changed||n.moved } }) @@ -713,9 +713,9 @@ RED.view = (function() { type: "badge", class: "red-ui-flow-node-error", element: function(d) { - var errorBadge = document.createElementNS("http://www.w3.org/2000/svg","path"); - errorBadge.setAttribute("d","M 0,9 l 10,0 -5,-8 z"); - return errorBadge + return RED.utils.createSVGElement("path", { + d: "M 0,9 l 10,0 -5,-8 z" + }) }, tooltip: function(d) { if (d.validationErrors && d.validationErrors.length > 0) { @@ -4233,13 +4233,14 @@ RED.view = (function() { d.resize = true; d.dirty = true; - var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect"); + var mainRect = RED.utils.createSVGElement("rect", { + class: "red-ui-flow-subflow-port", + rx: 8, + ry: 8, + width: 40, + height: 40, + }) mainRect.__data__ = d; - mainRect.setAttribute("class", "red-ui-flow-subflow-port"); - mainRect.setAttribute("rx", 8); - mainRect.setAttribute("ry", 8); - mainRect.setAttribute("width", 40); - mainRect.setAttribute("height", 40); node[0][0].__mainRect__ = mainRect; d3.select(mainRect) .on("mouseup",nodeMouseUp) @@ -4248,50 +4249,50 @@ RED.view = (function() { .on("touchend",nodeTouchEnd) nodeContents.appendChild(mainRect); - var output_groupEl = document.createElementNS("http://www.w3.org/2000/svg","g"); - output_groupEl.setAttribute("x",0); - output_groupEl.setAttribute("y",0); + var output_groupEl = RED.utils.createSVGElement("g", { x: 0, y: 0 }) node[0][0].__outputLabelGroup__ = output_groupEl; - var output_output = document.createElementNS("http://www.w3.org/2000/svg","text"); - output_output.setAttribute("class","red-ui-flow-port-label"); + var output_output = RED.utils.createSVGElement("text", { class: "red-ui-flow-port-label" }) output_output.style["font-size"] = "10px"; output_output.textContent = "output"; output_groupEl.appendChild(output_output); node[0][0].__outputOutput__ = output_output; - var output_number = document.createElementNS("http://www.w3.org/2000/svg","text"); - output_number.setAttribute("class","red-ui-flow-port-label red-ui-flow-port-index"); - output_number.setAttribute("x",0); - output_number.setAttribute("y",0); + var output_number = RED.utils.createSVGElement("text", { + class: "red-ui-flow-port-label red-ui-flow-port-index", + x: 0, + y: 0 + }) output_number.textContent = d.i+1; output_groupEl.appendChild(output_number); node[0][0].__outputNumber__ = output_number; - var output_border = document.createElementNS("http://www.w3.org/2000/svg","path"); - output_border.setAttribute("d","M 40 1 l 0 38") - output_border.setAttribute("class", "red-ui-flow-node-icon-shade-border") + var output_border = RED.utils.createSVGElement("path", { + d: "M 40 1 l 0 38", + class: "red-ui-flow-node-icon-shade-border" + }) output_groupEl.appendChild(output_border); node[0][0].__outputBorder__ = output_border; nodeContents.appendChild(output_groupEl); - var text = document.createElementNS("http://www.w3.org/2000/svg","g"); - text.setAttribute("class","red-ui-flow-port-label"); - text.setAttribute("transform","translate(38,0)"); - text.setAttribute('style', 'fill : #888'); // hard coded here! + var text = RED.utils.createSVGElement("g", { + class: "red-ui-flow-port-label", + transform: "translate(38,0)", + style: 'fill : #888' // hard coded here! + }) node[0][0].__textGroup__ = text; nodeContents.append(text); - var portEl = document.createElementNS("http://www.w3.org/2000/svg","g"); - portEl.setAttribute('transform','translate(-5,15)') + var portEl = RED.utils.createSVGElement("g", { transform: 'translate(-5,15)'}) - var port = document.createElementNS("http://www.w3.org/2000/svg","rect"); - port.setAttribute("class","red-ui-flow-port"); - port.setAttribute("rx",3); - port.setAttribute("ry",3); - port.setAttribute("width",10); - port.setAttribute("height",10); + var port = RED.utils.createSVGElement("rect", { + class: "red-ui-flow-port", + rx: 3, + ry: 3, + width: 10, + height: 10 + }) portEl.appendChild(port); port.__data__ = d; @@ -4420,10 +4421,11 @@ RED.view = (function() { } for (var i=0; i