From ab9b778fc4095c49996e9ccf12d9ad3e244eca49 Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Wed, 7 Feb 2018 08:36:34 -0500 Subject: [PATCH 1/3] NIFI-3502: - Upgrading to D3 version 4. --- nifi-assembly/LICENSE | 31 ++ .../src/main/resources/META-INF/LICENSE | 31 ++ .../nifi-web/nifi-web-ui/pom.xml | 6 +- .../src/main/frontend/package.json | 3 +- .../src/main/resources/META-INF/LICENSE | 31 ++ .../src/main/webapp/WEB-INF/pages/canvas.jsp | 3 +- .../main/webapp/WEB-INF/pages/provenance.jsp | 3 +- .../src/main/webapp/WEB-INF/pages/summary.jsp | 1 - .../src/main/webapp/WEB-INF/pages/users.jsp | 1 - .../nifi-web-ui/src/main/webapp/css/graph.css | 2 +- .../src/main/webapp/css/navigation.css | 2 +- .../src/main/webapp/css/status-history.css | 2 +- .../nf-ng-canvas-navigate-controller.js | 42 +- .../nf-ng-canvas-toolbox-controller.js | 4 +- .../components/nf-ng-processor-component.js | 2 +- .../main/webapp/js/nf/canvas/nf-actions.js | 11 +- .../main/webapp/js/nf/canvas/nf-birdseye.js | 41 +- .../webapp/js/nf/canvas/nf-canvas-utils.js | 57 ++- .../src/main/webapp/js/nf/canvas/nf-canvas.js | 410 +++++++++--------- .../webapp/js/nf/canvas/nf-connectable.js | 14 +- .../main/webapp/js/nf/canvas/nf-connection.js | 189 ++++---- .../js/nf/canvas/nf-controller-service.js | 6 +- .../js/nf/canvas/nf-controller-services.js | 4 +- .../main/webapp/js/nf/canvas/nf-draggable.js | 12 +- .../src/main/webapp/js/nf/canvas/nf-funnel.js | 38 +- .../src/main/webapp/js/nf/canvas/nf-graph.js | 4 +- .../src/main/webapp/js/nf/canvas/nf-label.js | 56 ++- .../src/main/webapp/js/nf/canvas/nf-port.js | 62 ++- .../webapp/js/nf/canvas/nf-process-group.js | 173 ++++---- .../main/webapp/js/nf/canvas/nf-processor.js | 128 +++--- .../js/nf/canvas/nf-remote-process-group.js | 100 +++-- .../main/webapp/js/nf/canvas/nf-settings.js | 4 +- .../js/nf/canvas/nf-variable-registry.js | 2 +- .../main/webapp/js/nf/nf-status-history.js | 259 +++++------ .../js/nf/provenance/nf-provenance-lineage.js | 106 ++--- .../js/nf/provenance/nf-provenance-table.js | 2 +- 36 files changed, 982 insertions(+), 860 deletions(-) diff --git a/nifi-assembly/LICENSE b/nifi-assembly/LICENSE index 0edf519b535a..69a03dc5d575 100644 --- a/nifi-assembly/LICENSE +++ b/nifi-assembly/LICENSE @@ -232,6 +232,37 @@ The source is available under an MIT LICENSE. THE SOFTWARE. This product bundles 'Javascript D3 Library' which is available under a +"3-clause BSD" license. + + Copyright 2010-2017 Mike Bostock + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This product bundles 'Javascript D3 Selection Multi Library' which is available under a "3-clause BSD" license. Copyright (c) 2010-2016, Michael Bostock diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework-nar/src/main/resources/META-INF/LICENSE b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework-nar/src/main/resources/META-INF/LICENSE index 78eb4c174add..e72b32455456 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework-nar/src/main/resources/META-INF/LICENSE +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework-nar/src/main/resources/META-INF/LICENSE @@ -261,6 +261,37 @@ licenses. THE SOFTWARE. This product bundles 'Javascript D3 Library' which is available under a +"3-clause BSD" license. + + Copyright 2010-2017 Mike Bostock + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This product bundles 'Javascript D3 Selection Multi Library' which is available under a "3-clause BSD" license. Copyright (c) 2010-2016, Michael Bostock diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml index c88a85130b6c..699e55d37351 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml @@ -151,8 +151,11 @@ false - d3/d3.min.js* + d3/build/d3.min.js* d3/LICENSE + + d3-selection-multi/build/d3-selection-multi.min.js* + d3-selection-multi/LICENSE angular/angular.min.js* angular/LICENSE.md @@ -895,7 +898,6 @@ nbactions.xml src/main/frontend/package.json src/main/webapp/js/jquery/jquery.base64.js - src/main/webapp/js/d3/d3.min.js src/main/webapp/js/codemirror/ src/main/webapp/fonts/**/* diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/frontend/package.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/frontend/package.json index 4e56011f726b..967020972eb5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/frontend/package.json +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/frontend/package.json @@ -14,7 +14,8 @@ "jsonlint": "1.6.2", "JSON2": "0.1.0", "reset.css": "2.0.2", - "d3": "3.5.17", + "d3": "4.13.0", + "d3-selection-multi": "1.0.1", "url-search-params": "0.6.1" }, "description": "Apache NiFi 3rd party client side resources.", diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/META-INF/LICENSE b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/META-INF/LICENSE index 6d29fb05a50d..2aced50c4c43 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/META-INF/LICENSE +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/META-INF/LICENSE @@ -209,6 +209,37 @@ subcomponents is subject to the terms and conditions of the following licenses. This product bundles 'Javascript D3 Library' which is available under a +"3-clause BSD" license. + + Copyright 2010-2017 Mike Bostock + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This product bundles 'Javascript D3 Selection Multi Library' which is available under a "3-clause BSD" license. Copyright (c) 2010-2016, Michael Bostock diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp index 52fc43cea373..0d14cd2bf1ee 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp @@ -46,7 +46,8 @@ - + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/provenance.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/provenance.jsp index b4eb6a035b97..d4bcccc936e6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/provenance.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/provenance.jsp @@ -33,7 +33,8 @@ - + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/summary.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/summary.jsp index 1746e6bcab7d..cc5ae4324635 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/summary.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/summary.jsp @@ -39,7 +39,6 @@ - diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/users.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/users.jsp index 42d07914cb2d..2444baa11f59 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/users.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/users.jsp @@ -32,7 +32,6 @@ - diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css index 4c77066e36da..95fbbbd9496a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css @@ -150,7 +150,7 @@ g.component.connectable-destination rect.border { stroke-width: 3; } -rect.selection, rect.drag-selection, rect.label-drag { +rect.component-selection, rect.drag-selection, rect.label-drag { stroke: #444444; stroke-opacity: 0.5; fill: transparent; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css index 17200d713993..0c23683d9644 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css @@ -225,7 +225,7 @@ div.button-spacer-large { border: 1px solid #e5ebed; } -.brush .extent { +.brush .selection { stroke: #666; fill-opacity: .125; shape-rendering: crispEdges; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/status-history.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/status-history.css index e421f6158183..57a5baa98252 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/status-history.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/status-history.css @@ -167,7 +167,7 @@ div.legend-label { stroke-width: 2.5px; } -.brush .extent { +.brush .selection { stroke: #666; fill-opacity: .125; shape-rendering: crispEdges; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js index 46dc70fafb18..4eb27a50697b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js @@ -44,66 +44,34 @@ * Zoom in on the canvas. */ this.zoomIn = function () { - nfCanvasUtils.zoomCanvasViewIn(); - - // hide the context menu - nfContextMenu.hide(); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - transition: true - }); + nfCanvasUtils.zoomInCanvas(); }; /** * Zoom out on the canvas. */ this.zoomOut = function () { - nfCanvasUtils.zoomCanvasViewOut(); - - // hide the context menu - nfContextMenu.hide(); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - transition: true - }); + nfCanvasUtils.zoomOutCanvas(); }; /** * Zoom fit on the canvas. */ this.zoomFit = function () { - nfCanvasUtils.fitCanvasView(); - - // hide the context menu - nfContextMenu.hide(); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - transition: true - }); + nfCanvasUtils.fitCanvas(); }; /** * Zoom actual size on the canvas. */ this.zoomActualSize = function () { - nfCanvasUtils.actualSizeCanvasView(); - - // hide the context menu - nfContextMenu.hide(); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - transition: true - }); + nfCanvasUtils.actualSizeCanvas(); }; } NavigateCtrl.prototype = { constructor: NavigateCtrl - } + }; var navigateCtrl = new NavigateCtrl(); return navigateCtrl; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-toolbox-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-toolbox-controller.js index f6b45f9a36e5..911063f2be7d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-toolbox-controller.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-toolbox-controller.js @@ -130,8 +130,8 @@ nfContextMenu.hide(); }, stop: function (e, ui) { - var translate = nfCanvasUtils.translateCanvasView(); - var scale = nfCanvasUtils.scaleCanvasView(); + var translate = nfCanvasUtils.getCanvasTranslate(); + var scale = nfCanvasUtils.getCanvasScale(); var mouseX = e.originalEvent.pageX; var mouseY = e.originalEvent.pageY - nfCanvasUtils.getCanvasOffset(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js index 3af00da597da..55adc4d7e2ba 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js @@ -512,7 +512,7 @@ text: 'all groups', value: '' }]; - groups.forEach(function (group) { + groups.each(function (group) { options.push({ text: group, value: group diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js index 64b0eaba26af..2b09d144c3d0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js @@ -493,11 +493,6 @@ // center on the component nfCanvasUtils.centerBoundingBox(box); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - transition: true - }); } }, @@ -996,7 +991,7 @@ }); // remove all the non connections in the snippet first - components.forEach(function (type, ids) { + components.each(function (ids, type) { if (type !== 'Connection') { nfCanvasUtils.getComponentByType(type).remove(ids); } @@ -1709,8 +1704,8 @@ paste: function (selection, evt) { if (nfCommon.isDefinedAndNotNull(evt)) { // get the current scale and translation - var scale = nfCanvasUtils.scaleCanvasView(); - var translate = nfCanvasUtils.translateCanvasView(); + var scale = nfCanvasUtils.getCanvasScale(); + var translate = nfCanvasUtils.getCanvasTranslate(); var mouseX = evt.pageX; var mouseY = evt.pageY - nfCanvasUtils.getCanvasOffset(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js index 4355e05a7b72..6cacb7f64b96 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js @@ -53,8 +53,8 @@ // refreshes the birdseye var refresh = function (components) { - var translate = nfCanvasUtils.translateCanvasView(); - var scale = nfCanvasUtils.scaleCanvasView(); + var translate = nfCanvasUtils.getCanvasTranslate(); + var scale = nfCanvasUtils.getCanvasScale(); // scale the translation translate = [translate[0] / scale, translate[1] / scale]; @@ -148,7 +148,7 @@ // update the brush d3.select('rect.birdseye-brush') - .attr({ + .attrs({ 'width': screenWidth, 'height': screenHeight, 'stroke-width': (2 / birdseyeScale), @@ -272,17 +272,14 @@ .attr('pointer-events', 'none'); // define the brush drag behavior - var brush = d3.behavior.drag() - .origin(function (d) { + var brush = d3.drag() + .subject(function (d) { return { x: d.x, - y: d.y + y: d.y, + source: 'birdseye' }; }) - .on('dragstart', function () { - // hide the context menu - nfContextMenu.hide(); - }) .on('drag', function (d) { d.x += d3.event.dx; d.y += d3.event.dy; @@ -291,25 +288,11 @@ d3.select(this).attr('transform', function () { return 'translate(' + d.x + ', ' + d.y + ')'; }); - // get the current transformation - var scale = nfCanvasUtils.scaleCanvasView(); - var translate = nfCanvasUtils.translateCanvasView(); - - // update the translation according to the delta - translate = [(-d3.event.dx * scale) + translate[0], (-d3.event.dy * scale) + translate[1]]; - - // record the current transforms - nfCanvasUtils.translateCanvasView(translate); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - persist: false, - transition: false, - refreshComponents: false, - refreshBirdseye: false - }); + + // transform the canvas + nfCanvasUtils.translateCanvas([-d3.event.dx, -d3.event.dy]); }) - .on('dragend', function () { + .on('end', function () { // update component visibility nfGraph.updateVisibility(); @@ -322,7 +305,7 @@ // context area birdseyeGroup.append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'birdseye-brush-container' }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js index 162da3694529..3dce37e5a24e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js @@ -115,7 +115,7 @@ }); // refresh all component types as necessary (handle components that have been removed) - componentMap.forEach(function (type, ids) { + componentMap.each(function (ids, type) { nfCanvasUtils.getComponentByType(type).remove(ids); }); @@ -576,7 +576,10 @@ * @param {type} boundingBox */ centerBoundingBox: function (boundingBox) { - var scale = nfCanvas.View.scale(); + var scale = nfCanvas.View.getScale(); + if (nfCommon.isDefinedAndNotNull(boundingBox.scale)) { + scale = boundingBox.scale; + } // get the canvas normalized width and height var canvasContainer = $('#canvas-container'); @@ -587,7 +590,7 @@ var center = [(screenWidth / 2) - (boundingBox.width / 2), (screenHeight / 2) - (boundingBox.height / 2)]; // calculate the difference between the center point and the position of this component and convert to screen space - nfCanvas.View.translate([(center[0] - boundingBox.x) * scale, (center[1] - boundingBox.y) * scale]); + nfCanvas.View.transform([(center[0] - boundingBox.x) * scale, (center[1] - boundingBox.y) * scale], scale); }, /** @@ -701,7 +704,7 @@ var line = []; var tspan = selection.append('tspan') - .attr({ + .attrs({ 'x': x, 'y': y, 'width': width @@ -726,7 +729,7 @@ // create the tspan for the next line tspan = selection.append('tspan') - .attr({ + .attrs({ 'x': x, 'dy': '1.2em', 'width': width @@ -1560,9 +1563,9 @@ var name = config.storage.namePrefix + nfCanvas.getGroupId(); // create the item to store - var translate = nfCanvas.View.translate(); + var translate = nfCanvas.View.getTranslate(); var item = { - scale: nfCanvas.View.scale(), + scale: nfCanvas.View.getScale(), translateX: translate[0], translateY: translate[1] }; @@ -1652,13 +1655,7 @@ if (nfCommon.isDefinedAndNotNull(item)) { if (isFinite(item.scale) && isFinite(item.translateX) && isFinite(item.translateY)) { // restore previous view - nfCanvas.View.translate([item.translateX, item.translateY]); - nfCanvas.View.scale(item.scale); - - // refresh the canvas - nfCanvas.View.refresh({ - transition: true - }); + nfCanvas.View.transform([item.translateX, item.translateY], item.scale); // mark the view was restore viewRestored = true; @@ -1902,57 +1899,53 @@ }, /** - * Refreshes the view based on the configured translation and scale. - * - * @param {object} options Options for the refresh operation + * Gets the current scale. */ - refreshCanvasView: function (options) { - return nfCanvas.View.refresh(options); + getCanvasScale: function () { + return nfCanvas.View.getScale(); }, /** - * Sets/gets the current scale. - * - * @param {number} scale The new scale + * Gets the current translation. */ - scaleCanvasView: function (scale) { - return nfCanvas.View.scale(scale); + getCanvasTranslate: function () { + return nfCanvas.View.getTranslate(); }, /** - * Sets/gets the current translation. + * Translate the canvas by the specified [x, y] * - * @param {array} translate [x, y] + * @param {array} translate [x, y] to translate by */ - translateCanvasView: function (translate) { - return nfCanvas.View.translate(translate); + translateCanvas: function (translate) { + nfCanvas.View.translate(translate); }, /** * Zooms to fit the entire graph on the canvas. */ - fitCanvasView: function () { + fitCanvas: function () { return nfCanvas.View.fit(); }, /** * Zooms in a single zoom increment. */ - zoomCanvasViewIn: function () { + zoomInCanvas: function () { return nfCanvas.View.zoomIn(); }, /** * Zooms out a single zoom increment. */ - zoomCanvasViewOut: function () { + zoomOutCanvas: function () { return nfCanvas.View.zoomOut(); }, /** * Zooms to the actual size (1 to 1). */ - actualSizeCanvasView: function () { + actualSizeCanvas: function () { return nfCanvas.View.actualSize(); }, diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js index 00dd4a8601c7..3f7212399b4f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js @@ -91,7 +91,6 @@ var canvas = null; var canvasClicked = false; - var panning = false; var config = { urls: { @@ -305,7 +304,7 @@ defs.selectAll('marker') .data(['normal', 'ghost', 'unauthorized', 'full']) .enter().append('marker') - .attr({ + .attrs({ 'id': function (d) { return d; }, @@ -332,7 +331,7 @@ // filter for drop shadow var componentDropShadowFilter = defs.append('filter') - .attr({ + .attrs({ 'id': 'component-drop-shadow', 'height': '140%', 'y': '-20%' @@ -340,7 +339,7 @@ // blur componentDropShadowFilter.append('feGaussianBlur') - .attr({ + .attrs({ 'in': 'SourceAlpha', 'stdDeviation': 3, 'result': 'blur' @@ -348,7 +347,7 @@ // offset componentDropShadowFilter.append('feOffset') - .attr({ + .attrs({ 'in': 'blur', 'dx': 0, 'dy': 1, @@ -357,7 +356,7 @@ // color/opacity componentDropShadowFilter.append('feFlood') - .attr({ + .attrs({ 'flood-color': '#000000', 'flood-opacity': 0.4, 'result': 'offsetColor' @@ -365,7 +364,7 @@ // combine componentDropShadowFilter.append('feComposite') - .attr({ + .attrs({ 'in': 'offsetColor', 'in2': 'offsetBlur', 'operator': 'in', @@ -381,7 +380,7 @@ // filter for drop shadow var connectionFullDropShadowFilter = defs.append('filter') - .attr({ + .attrs({ 'id': 'connection-full-drop-shadow', 'height': '140%', 'y': '-20%' @@ -389,7 +388,7 @@ // blur connectionFullDropShadowFilter.append('feGaussianBlur') - .attr({ + .attrs({ 'in': 'SourceAlpha', 'stdDeviation': 3, 'result': 'blur' @@ -397,7 +396,7 @@ // offset connectionFullDropShadowFilter.append('feOffset') - .attr({ + .attrs({ 'in': 'blur', 'dx': 0, 'dy': 1, @@ -406,7 +405,7 @@ // color/opacity connectionFullDropShadowFilter.append('feFlood') - .attr({ + .attrs({ 'flood-color': '#ba554a', 'flood-opacity': 1, 'result': 'offsetColor' @@ -414,7 +413,7 @@ // combine connectionFullDropShadowFilter.append('feComposite') - .attr({ + .attrs({ 'in': 'offsetColor', 'in2': 'offsetBlur', 'operator': 'in', @@ -430,7 +429,7 @@ // create the canvas element canvas = svg.append('g') - .attr({ + .attrs({ 'transform': 'translate(' + TRANSLATE + ') scale(' + SCALE + ')', 'pointer-events': 'all', 'id': 'canvas' @@ -455,14 +454,14 @@ .attr('ry', 6) .attr('x', position[0]) .attr('y', position[1]) - .attr('class', 'selection') + .attr('class', 'component-selection') .attr('width', 0) .attr('height', 0) .attr('stroke-width', function () { - return 1 / nfCanvas.View.scale(); + return 1 / nfCanvas.View.getScale(); }) .attr('stroke-dasharray', function () { - return 4 / nfCanvas.View.scale(); + return 4 / nfCanvas.View.getScale(); }) .datum(position); @@ -474,106 +473,100 @@ d3.event.preventDefault(); } }) - .on('mousemove.selection', function () { - // update selection box if shift is held down - if (d3.event.shiftKey) { - // get the selection box - var selectionBox = d3.select('rect.selection'); - if (!selectionBox.empty()) { - // get the original position - var originalPosition = selectionBox.datum(); - var position = d3.mouse(canvas.node()); - - var d = {}; - if (originalPosition[0] < position[0]) { - d.x = originalPosition[0]; - d.width = position[0] - originalPosition[0]; - } else { - d.x = position[0]; - d.width = originalPosition[0] - position[0]; - } + .on('mousemove.selection', function () { + // update selection box if shift is held down + if (d3.event.shiftKey) { + // get the selection box + var selectionBox = d3.select('rect.component-selection'); + if (!selectionBox.empty()) { + // get the original position + var originalPosition = selectionBox.datum(); + var position = d3.mouse(canvas.node()); + + var d = {}; + if (originalPosition[0] < position[0]) { + d.x = originalPosition[0]; + d.width = position[0] - originalPosition[0]; + } else { + d.x = position[0]; + d.width = originalPosition[0] - position[0]; + } - if (originalPosition[1] < position[1]) { - d.y = originalPosition[1]; - d.height = position[1] - originalPosition[1]; - } else { - d.y = position[1]; - d.height = originalPosition[1] - position[1]; - } + if (originalPosition[1] < position[1]) { + d.y = originalPosition[1]; + d.height = position[1] - originalPosition[1]; + } else { + d.y = position[1]; + d.height = originalPosition[1] - position[1]; + } - // update the selection box - selectionBox.attr(d); + // update the selection box + selectionBox.attrs(d); - // prevent further propagation (to parents) - d3.event.stopPropagation(); - } - } - }) - .on('mouseup.selection', function () { - // ensure this originated from clicking the canvas, not a component. - // when clicking on a component, the event propagation is stopped so - // it never reaches the canvas. we cannot do this however on up events - // since the drag events break down - if (canvasClicked === false) { - return; + // prevent further propagation (to parents) + d3.event.stopPropagation(); } + } + }) + .on('mouseup.selection', function () { + // ensure this originated from clicking the canvas, not a component. + // when clicking on a component, the event propagation is stopped so + // it never reaches the canvas. we cannot do this however on up events + // since the drag events break down + if (canvasClicked === false) { + return; + } - // reset the canvas click flag - canvasClicked = false; + // reset the canvas click flag + canvasClicked = false; + + // get the selection box + var selectionBox = d3.select('rect.component-selection'); + if (!selectionBox.empty()) { + var selectionBoundingBox = { + x: parseInt(selectionBox.attr('x'), 10), + y: parseInt(selectionBox.attr('y'), 10), + width: parseInt(selectionBox.attr('width'), 10), + height: parseInt(selectionBox.attr('height'), 10) + }; + + // see if a component should be selected or not + d3.selectAll('g.component').classed('selected', function (d) { + // consider it selected if its already selected or enclosed in the bounding box + return d3.select(this).classed('selected') || + d.position.x >= selectionBoundingBox.x && (d.position.x + d.dimensions.width) <= (selectionBoundingBox.x + selectionBoundingBox.width) && + d.position.y >= selectionBoundingBox.y && (d.position.y + d.dimensions.height) <= (selectionBoundingBox.y + selectionBoundingBox.height); + }); - // get the selection box - var selectionBox = d3.select('rect.selection'); - if (!selectionBox.empty()) { - var selectionBoundingBox = { - x: parseInt(selectionBox.attr('x'), 10), - y: parseInt(selectionBox.attr('y'), 10), - width: parseInt(selectionBox.attr('width'), 10), - height: parseInt(selectionBox.attr('height'), 10) - }; + // see if a connection should be selected or not + d3.selectAll('g.connection').classed('selected', function (d) { + // consider all points + var points = [d.start].concat(d.bends, [d.end]); - // see if a component should be selected or not - d3.selectAll('g.component').classed('selected', function (d) { - // consider it selected if its already selected or enclosed in the bounding box - return d3.select(this).classed('selected') || - d.position.x >= selectionBoundingBox.x && (d.position.x + d.dimensions.width) <= (selectionBoundingBox.x + selectionBoundingBox.width) && - d.position.y >= selectionBoundingBox.y && (d.position.y + d.dimensions.height) <= (selectionBoundingBox.y + selectionBoundingBox.height); + // determine the bounding box + var x = d3.extent(points, function (pt) { + return pt.x; }); - - // see if a connection should be selected or not - d3.selectAll('g.connection').classed('selected', function (d) { - // consider all points - var points = [d.start].concat(d.bends, [d.end]); - - // determine the bounding box - var x = d3.extent(points, function (pt) { - return pt.x; - }); - var y = d3.extent(points, function (pt) { - return pt.y; - }); - - // consider it selected if its already selected or enclosed in the bounding box - return d3.select(this).classed('selected') || - x[0] >= selectionBoundingBox.x && x[1] <= (selectionBoundingBox.x + selectionBoundingBox.width) && - y[0] >= selectionBoundingBox.y && y[1] <= (selectionBoundingBox.y + selectionBoundingBox.height); + var y = d3.extent(points, function (pt) { + return pt.y; }); - // remove the selection box - selectionBox.remove(); + // consider it selected if its already selected or enclosed in the bounding box + return d3.select(this).classed('selected') || + x[0] >= selectionBoundingBox.x && x[1] <= (selectionBoundingBox.x + selectionBoundingBox.width) && + y[0] >= selectionBoundingBox.y && y[1] <= (selectionBoundingBox.y + selectionBoundingBox.height); + }); - // update URL deep linking params - nfCanvasUtils.setURLParameters(); - } else if (panning === false) { - // deselect as necessary if we are not panning - nfCanvasUtils.getSelection().classed('selected', false); + // remove the selection box + selectionBox.remove(); - // update URL deep linking params - nfCanvasUtils.setURLParameters(); - } + // update URL deep linking params + nfCanvasUtils.setURLParameters(); + } - // inform Angular app values have changed - nfNgBridge.digest(); - }); + // inform Angular app values have changed + nfNgBridge.digest(); + }); // define a function for update the graph dimensions var updateGraphSize = function () { @@ -594,7 +587,7 @@ 'height': canvasHeight + 'px', 'bottom': bottom + 'px' }); - svg.attr({ + svg.attrs({ 'height': canvasContainer.height(), 'width': $(window).width() }); @@ -972,22 +965,63 @@ // initialize the zoom behavior var behavior; + var x = 0, y = 0, k = SCALE; return { + init: function () { var refreshed; + var zoomed = false; + var panning = false; + + // filters zoom events as programmatically modifying the translate or scale now triggers the handlers + var isBirdseyeEvent = function(sourceEvent) { + if (nfCommon.isDefinedAndNotNull(sourceEvent)) { + if (nfCommon.isDefinedAndNotNull(sourceEvent.subject)) { + return sourceEvent.subject.source === 'birdseye'; + } else { + return false; + } + } else { + return false; + } + }; + + // see if the scale has changed during this zoom event, + // we want to only transition when zooming in/out as running + // the transitions during pan events is undesirable + var shouldTransition = function(sourceEvent) { + if (nfCommon.isDefinedAndNotNull(sourceEvent)) { + if (isBirdseyeEvent(sourceEvent)) { + return false; + } + + return sourceEvent.type === 'wheel' || sourceEvent.type === 'mousewheel'; + } else { + return true; + } + }; // define the behavior - behavior = d3.behavior.zoom() + behavior = d3.zoom() .scaleExtent([MIN_SCALE, MAX_SCALE]) - .translate(TRANSLATE) - .scale(SCALE) - .on('zoomstart', function () { + .on('start', function () { // hide the context menu nfContextMenu.hide(); }) .on('zoom', function () { + // update the current translation and scale + if (!isNaN(d3.event.transform.x)) { + x = d3.event.transform.x; + } + if (!isNaN(d3.event.transform.y)) { + y = d3.event.transform.y; + } + if (!isNaN(d3.event.transform.k)) { + k = d3.event.transform.k; + } + // if we have zoomed, indicate that we are panning // to prevent deselection elsewhere if (zoomed) { @@ -996,34 +1030,39 @@ zoomed = true; } - // see if the scale has changed during this zoom event, - // we want to only transition when zooming in/out as running - // the transitions during pan events is - var transition = d3.event.sourceEvent.type === 'wheel' || d3.event.sourceEvent.type === 'mousewheel'; - // refresh the canvas refreshed = nfCanvas.View.refresh({ persist: false, - transition: transition, + transition: shouldTransition(d3.event.sourceEvent), refreshComponents: false, refreshBirdseye: false }); }) - .on('zoomend', function () { - // ensure the canvas was actually refreshed - if (nfCommon.isDefinedAndNotNull(refreshed)) { - nfGraph.updateVisibility(); - - // refresh the birdseye - refreshed.done(function () { - nfBirdseye.refresh(); - }); + .on('end', function () { + if (!isBirdseyeEvent(d3.event.sourceEvent)) { + // ensure the canvas was actually refreshed + if (nfCommon.isDefinedAndNotNull(refreshed)) { + nfGraph.updateVisibility(); + + // refresh the birdseye + refreshed.done(function () { + nfBirdseye.refresh(); + }); - // persist the users view - nfCanvasUtils.persistUserView(); + // persist the users view + nfCanvasUtils.persistUserView(); - // reset the refreshed deferred - refreshed = null; + // reset the refreshed deferred + refreshed = null; + } + + if (panning === false) { + // deselect as necessary if we are not panning + nfCanvasUtils.getSelection().classed('selected', false); + + // update URL deep linking params + nfCanvasUtils.setURLParameters(); + } } panning = false; @@ -1040,91 +1079,71 @@ * @returns {Boolean} */ shouldRenderPerScale: function () { - return nfCanvas.View.scale() >= MIN_SCALE_TO_RENDER; + return nfCanvas.View.getScale() >= MIN_SCALE_TO_RENDER; }, /** - * Sets/gets the current translation. + * Translates by the specified [x, y]. * - * @param {array} translate [x, y] + * @param {array} translate [x, y] to translate by */ translate: function (translate) { - if (nfCommon.isUndefined(translate)) { - return behavior.translate(); - } else { - behavior.translate(translate); - } + behavior.translateBy(svg, translate[0], translate[1]); }, /** - * Sets/gets the current scale. + * Scales by the specified scale. * - * @param {number} scale The new scale + * @param {number} scale The factor to scale by */ scale: function (scale) { - if (nfCommon.isUndefined(scale)) { - return behavior.scale(); - } else { - behavior.scale(scale); - } + behavior.scaleBy(svg, scale); }, /** - * Zooms in a single zoom increment. + * Sets the current transform. + * + * @param translate + * @param scale */ - zoomIn: function () { - var translate = nfCanvas.View.translate(); - var scale = nfCanvas.View.scale(); - var newScale = Math.min(scale * INCREMENT, MAX_SCALE); + transform: function (translate, scale) { + behavior.transform(svg, d3.zoomIdentity.translate(translate[0], translate[1]).scale(scale)); + }, - // get the canvas normalized width and height - var canvasContainer = $('#canvas-container'); - var screenWidth = canvasContainer.width() / scale; - var screenHeight = canvasContainer.height() / scale; + /** + * Gets the current translate. + */ + getTranslate: function () { + return [x, y]; + }, - // adjust the scale - nfCanvas.View.scale(newScale); + /** + * Gets the current scale. + */ + getScale: function () { + return k; + }, - // center around the center of the screen accounting for the translation accordingly - nfCanvasUtils.centerBoundingBox({ - x: (screenWidth / 2) - (translate[0] / scale), - y: (screenHeight / 2) - (translate[1] / scale), - width: 1, - height: 1 - }); + /** + * Zooms in a single zoom increment. + */ + zoomIn: function () { + nfCanvas.View.scale(INCREMENT); }, /** * Zooms out a single zoom increment. */ zoomOut: function () { - var translate = nfCanvas.View.translate(); - var scale = nfCanvas.View.scale(); - var newScale = Math.max(scale / INCREMENT, MIN_SCALE); - - // get the canvas normalized width and height - var canvasContainer = $('#canvas-container'); - var screenWidth = canvasContainer.width() / scale; - var screenHeight = canvasContainer.height() / scale; - - // adjust the scale - nfCanvas.View.scale(newScale); - - // center around the center of the screen accounting for the translation accordingly - nfCanvasUtils.centerBoundingBox({ - x: (screenWidth / 2) - (translate[0] / scale), - y: (screenHeight / 2) - (translate[1] / scale), - width: 1, - height: 1 - }); + nfCanvas.View.scale(1 / INCREMENT); }, /** * Zooms to fit the entire graph on the canvas. */ fit: function () { - var translate = nfCanvas.View.translate(); - var scale = nfCanvas.View.scale(); + var translate = nfCanvas.View.getTranslate(); + var scale = nfCanvas.View.getScale(); var newScale; // get the canvas normalized width and height @@ -1139,7 +1158,6 @@ var graphLeft = graphBox.left / scale; var graphTop = (graphBox.top - nfCanvas.CANVAS_OFFSET) / scale; - // adjust the scale to ensure the entire graph is visible if (graphWidth > canvasWidth || graphHeight > canvasHeight) { newScale = Math.min(canvasWidth / graphWidth, canvasHeight / graphHeight); @@ -1154,15 +1172,13 @@ graphTop -= 50; } - // set the new scale - nfCanvas.View.scale(newScale); - // center as appropriate nfCanvasUtils.centerBoundingBox({ x: graphLeft - (translate[0] / scale), y: graphTop - (translate[1] / scale), width: canvasWidth / newScale, - height: canvasHeight / newScale + height: canvasHeight / newScale, + scale: newScale }); }, @@ -1170,15 +1186,12 @@ * Zooms to the actual size (1 to 1). */ actualSize: function () { - var translate = nfCanvas.View.translate(); - var scale = nfCanvas.View.scale(); + var translate = nfCanvas.View.getTranslate(); + var scale = nfCanvas.View.getScale(); // get the first selected component var selection = nfCanvasUtils.getSelection(); - // set the updated scale - nfCanvas.View.scale(1); - // box to zoom towards var box; @@ -1192,7 +1205,8 @@ x: (selectionBox.left / scale) - (translate[0] / scale), y: ((selectionBox.top - nfCanvas.CANVAS_OFFSET) / scale) - (translate[1] / scale), width: selectionBox.width / scale, - height: selectionBox.height / scale + height: selectionBox.height / scale, + scale: 1 }; } else { // get the offset @@ -1207,7 +1221,8 @@ x: (screenWidth / 2) - (translate[0] / scale), y: (screenHeight / 2) - (translate[1] / scale), width: 1, - height: 1 + height: 1, + scale: 1 }; } @@ -1246,14 +1261,17 @@ nfCanvasUtils.persistUserView(); } + var t = nfCanvas.View.getTranslate(); + var s = nfCanvas.View.getScale(); + // update the canvas if (transition === true) { canvas.transition() .duration(500) .attr('transform', function () { - return 'translate(' + behavior.translate() + ') scale(' + behavior.scale() + ')'; + return 'translate(' + t + ') scale(' + s + ')'; }) - .each('end', function () { + .on('end', function () { // refresh birdseye if appropriate if (refreshBirdseye === true) { nfBirdseye.refresh(); @@ -1263,7 +1281,7 @@ }); } else { canvas.attr('transform', function () { - return 'translate(' + behavior.translate() + ') scale(' + behavior.scale() + ')'; + return 'translate(' + t + ') scale(' + s + ')'; }); // refresh birdseye if appropriate diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js index 91d29f612cdc..0418bef2a50c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js @@ -57,7 +57,7 @@ * @returns {boolean} */ var allowConnection = function () { - return !d3.event.shiftKey && d3.select('rect.drag-selection').empty() && d3.select('rect.selection').empty(); + return !d3.event.shiftKey && d3.select('rect.drag-selection').empty() && d3.select('rect.component-selection').empty(); }; return { @@ -65,15 +65,15 @@ canvas = d3.select('#canvas'); // dragging behavior for the connector - connect = d3.behavior.drag() - .origin(function (d) { + connect = d3.drag() + .subject(function (d) { origin = d3.mouse(canvas.node()); return { x: origin[0], y: origin[1] }; }) - .on('dragstart', function (d) { + .on('start', function (d) { // stop further propagation d3.event.sourceEvent.stopPropagation(); @@ -98,7 +98,7 @@ 'x': position[0], 'y': position[1] }) - .attr({ + .attrs({ 'class': 'connector', 'd': function (pathDatum) { return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + pathDatum.x + ' ' + pathDatum.y; @@ -168,7 +168,7 @@ } }); }) - .on('dragend', function (d) { + .on('end', function (d) { // stop further propagation d3.event.sourceEvent.stopPropagation(); @@ -243,7 +243,7 @@ origY: y }) .call(connect) - .attr({ + .attrs({ 'class': 'add-connect', 'transform': 'translate(' + x + ', ' + y + ')' }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js index 9e974a2eefff..611e143dee4e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js @@ -274,13 +274,20 @@ }); }; + /** + * Renders the connections in the specified selection. + * + * @param {selection} entered The selection of connections to be rendered + * @param {boolean} selected Whether the element should be selected + * @return the entered selection + */ var renderConnections = function (entered, selected) { if (entered.empty()) { - return; + return entered; } var connection = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -290,21 +297,21 @@ // create a connection between the two components connection.append('path') - .attr({ + .attrs({ 'class': 'connection-path', 'pointer-events': 'none' }); // path to show when selection connection.append('path') - .attr({ + .attrs({ 'class': 'connection-selection-path', 'pointer-events': 'none' }); // path to make selection easier connection.append('path') - .attr({ + .attrs({ 'class': 'connection-path-selectable', 'pointer-events': 'stroke' }) @@ -316,6 +323,8 @@ nfCanvasUtils.setURLParameters(); }) .call(nfContextMenu.activate); + + return connection; }; // determines whether the specified connection contains an unsupported relationship @@ -584,21 +593,21 @@ // update the connection paths nfCanvasUtils.transition(connection.select('path.connection-path'), transition) - .attr({ + .attrs({ 'd': function () { var datum = [d.start].concat(d.bends, [d.end]); return lineGenerator(datum); } }); nfCanvasUtils.transition(connection.select('path.connection-selection-path'), transition) - .attr({ + .attrs({ 'd': function () { var datum = [d.start].concat(d.bends, [d.end]); return lineGenerator(datum); } }); nfCanvasUtils.transition(connection.select('path.connection-path-selectable'), transition) - .attr({ + .attrs({ 'd': function () { var datum = [d.start].concat(d.bends, [d.end]); return lineGenerator(datum); @@ -624,8 +633,8 @@ startpoints = startpoints.data([d.start]); // create a point for the start - startpoints.enter().append('rect') - .attr({ + var startpointsEntered = startpoints.enter().append('rect') + .attrs({ 'class': 'startpoint linepoint', 'pointer-events': 'all', 'width': 8, @@ -641,7 +650,7 @@ .call(nfContextMenu.activate); // update the start point - nfCanvasUtils.transition(startpoints, transition) + nfCanvasUtils.transition(startpoints.merge(startpointsEntered), transition) .attr('transform', function (p) { return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')'; }); @@ -656,9 +665,9 @@ var endpoints = endpoints.data([d.end]); // create a point for the end - endpoints.enter().append('rect') + var endpointsEntered = endpoints.enter().append('rect') .call(endpointDrag) - .attr({ + .attrs({ 'class': 'endpoint linepoint', 'pointer-events': 'all', 'width': 8, @@ -674,7 +683,7 @@ .call(nfContextMenu.activate); // update the end point - nfCanvasUtils.transition(endpoints, transition) + nfCanvasUtils.transition(endpoints.merge(endpointsEntered), transition) .attr('transform', function (p) { return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')'; }); @@ -689,8 +698,8 @@ var midpoints = midpoints.data(d.bends); // create a point for the end - midpoints.enter().append('rect') - .attr({ + var midpointsEntered = midpoints.enter().append('rect') + .attrs({ 'class': 'midpoint linepoint', 'pointer-events': 'all', 'width': 8, @@ -757,7 +766,7 @@ .call(nfContextMenu.activate); // update the midpoints - nfCanvasUtils.transition(midpoints, transition) + nfCanvasUtils.transition(midpoints.merge(midpointsEntered), transition) .attr('transform', function (p) { return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')'; }); @@ -783,7 +792,7 @@ if (connectionLabelContainer.empty()) { // connection label container connectionLabelContainer = connection.insert('g', 'rect.startpoint') - .attr({ + .attrs({ 'class': 'connection-label-container', 'pointer-events': 'all' }) @@ -798,7 +807,7 @@ // connection label connectionLabelContainer.append('rect') - .attr({ + .attrs({ 'class': 'body', 'width': dimensions.width, 'x': 0, @@ -807,7 +816,7 @@ // processor border connectionLabelContainer.append('rect') - .attr({ + .attrs({ 'class': 'border', 'width': dimensions.width, 'fill': 'transparent', @@ -835,13 +844,13 @@ // see if the connection from label is already rendered if (connectionFrom.empty()) { connectionFrom = connectionLabelContainer.append('g') - .attr({ + .attrs({ 'class': 'connection-from-container' }); // background backgrounds.push(connectionFrom.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-background', 'width': dimensions.width, 'height': rowHeight @@ -849,14 +858,14 @@ // border borders.push(connectionFrom.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-border', 'width': dimensions.width, 'height': 1 })); connectionFrom.append('text') - .attr({ + .attrs({ 'class': 'stats-label', 'x': 5, 'y': 14 @@ -864,7 +873,7 @@ .text('From'); connectionFrom.append('text') - .attr({ + .attrs({ 'class': 'stats-value connection-from', 'x': 43, 'y': 14, @@ -872,7 +881,7 @@ }); connectionFrom.append('text') - .attr({ + .attrs({ 'class': 'connection-from-run-status', 'x': 185, 'y': 14 @@ -944,13 +953,13 @@ // see if the connection to label is already rendered if (connectionTo.empty()) { connectionTo = connectionLabelContainer.append('g') - .attr({ + .attrs({ 'class': 'connection-to-container' }); // background backgrounds.push(connectionTo.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-background', 'width': dimensions.width, 'height': rowHeight @@ -958,14 +967,14 @@ // border borders.push(connectionTo.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-border', 'width': dimensions.width, 'height': 1 })); connectionTo.append('text') - .attr({ + .attrs({ 'class': 'stats-label', 'x': 5, 'y': 14 @@ -973,7 +982,7 @@ .text('To'); connectionTo.append('text') - .attr({ + .attrs({ 'class': 'stats-value connection-to', 'x': 25, 'y': 14, @@ -981,7 +990,7 @@ }); connectionTo.append('text') - .attr({ + .attrs({ 'class': 'connection-to-run-status', 'x': 185, 'y': 14 @@ -1056,13 +1065,13 @@ // see if the connection name label is already rendered if (connectionName.empty()) { connectionName = connectionLabelContainer.append('g') - .attr({ + .attrs({ 'class': 'connection-name-container' }); // background backgrounds.push(connectionName.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-background', 'width': dimensions.width, 'height': rowHeight @@ -1070,14 +1079,14 @@ // border borders.push(connectionName.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-border', 'width': dimensions.width, 'height': 1 })); connectionName.append('text') - .attr({ + .attrs({ 'class': 'stats-label', 'x': 5, 'y': 14 @@ -1085,7 +1094,7 @@ .text('Name'); connectionName.append('text') - .attr({ + .attrs({ 'class': 'stats-value connection-name', 'x': 45, 'y': 14, @@ -1136,13 +1145,13 @@ var queued = connectionLabelContainer.select('g.queued-container'); if (queued.empty()) { queued = connectionLabelContainer.append('g') - .attr({ + .attrs({ 'class': 'queued-container' }); // background backgrounds.push(queued.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-background', 'width': dimensions.width, 'height': rowHeight + HEIGHT_FOR_BACKPRESSURE @@ -1150,14 +1159,14 @@ // border borders.push(queued.append('rect') - .attr({ + .attrs({ 'class': 'connection-label-border', 'width': dimensions.width, 'height': 1 })); queued.append('text') - .attr({ + .attrs({ 'class': 'stats-label', 'x': 5, 'y': 14 @@ -1165,7 +1174,7 @@ .text('Queued'); var queuedText = queued.append('text') - .attr({ + .attrs({ 'class': 'stats-value queued', 'x': 55, 'y': 14 @@ -1173,19 +1182,19 @@ // queued count queuedText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // queued size queuedText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // expiration icon queued.append('text') - .attr({ + .attrs({ 'class': 'expiration-icon', 'x': 185, 'y': 14 @@ -1201,7 +1210,7 @@ // start queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-tick object', 'width': 1, 'height': 3, @@ -1212,7 +1221,7 @@ // bar var backpressureCountOffset = 6; queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-object', 'width': backpressureBarWidth, 'height': 3, @@ -1223,7 +1232,7 @@ // end queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-tick object', 'width': 1, 'height': 3, @@ -1233,7 +1242,7 @@ // percent full queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-percent object', 'width': 0, 'height': 3, @@ -1245,7 +1254,7 @@ // start queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-tick data-size', 'width': 1, 'height': 3, @@ -1256,7 +1265,7 @@ // bar var backpressureDataSizeOffset = (dimensions.width / 2) + 10 + 1; queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-data-size', 'width': backpressureBarWidth, 'height': 3, @@ -1267,7 +1276,7 @@ // end queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-tick data-size', 'width': 1, 'height': 3, @@ -1277,7 +1286,7 @@ // percent full queued.append('rect') - .attr({ + .attrs({ 'class': 'backpressure-percent data-size', 'width': 0, 'height': 3, @@ -1411,7 +1420,7 @@ var backpressurePercentDataSize = updated.select('rect.backpressure-percent.data-size'); backpressurePercentDataSize.transition() .duration(400) - .attr({ + .attrs({ 'width': function (d) { if (nfCommon.isDefinedAndNotNull(d.status.aggregateSnapshot.percentUseBytes)) { return (backpressureBarWidth * d.status.aggregateSnapshot.percentUseBytes) / 100; @@ -1419,7 +1428,7 @@ return 0; } } - }).each('end', function () { + }).on('end', function () { backpressurePercentDataSize .classed('warning', function (d) { return isWarningBytes(d); @@ -1451,7 +1460,7 @@ var backpressurePercentObject = updated.select('rect.backpressure-percent.object'); backpressurePercentObject.transition() .duration(400) - .attr({ + .attrs({ 'width': function (d) { if (nfCommon.isDefinedAndNotNull(d.status.aggregateSnapshot.percentUseCount)) { return (backpressureBarWidth * d.status.aggregateSnapshot.percentUseCount) / 100; @@ -1459,7 +1468,7 @@ return 0; } } - }).each('end', function () { + }).on('end', function () { backpressurePercentObject .classed('warning', function (d) { return isWarningCount(d); @@ -1487,7 +1496,7 @@ .classed('full', function (d) { return isFullCount(d) || isFullBytes(d); }) - .attr({ + .attrs({ 'marker-end': getEndMarker }); @@ -1499,7 +1508,7 @@ // drop shadow updated.select('rect.body') - .attr({ + .attrs({ 'filter': getDropShadow }); }); @@ -1575,24 +1584,24 @@ // create the connection container connectionContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'stroke', 'class': 'connections' }); // define the line generator - lineGenerator = d3.svg.line() + lineGenerator = d3.line() .x(function (d) { return d.x; }) .y(function (d) { return d.y; }) - .interpolate('linear'); + .curve(d3.curveLinear); // handle bend point drag events - bendPointDrag = d3.behavior.drag() - .on('dragstart', function () { + bendPointDrag = d3.drag() + .on('start', function () { // stop further propagation d3.event.sourceEvent.stopPropagation(); }) @@ -1606,7 +1615,7 @@ 'updateLabel': false }); }) - .on('dragend', function () { + .on('end', function () { var connection = d3.select(this.parentNode); var connectionData = connection.datum(); var bends = connection.selectAll('rect.midpoint').data(); @@ -1649,8 +1658,8 @@ }); // handle endpoint drag events - endpointDrag = d3.behavior.drag() - .on('dragstart', function (d) { + endpointDrag = d3.drag() + .on('start', function (d) { // indicate that dragging has begun d.dragging = true; @@ -1672,7 +1681,7 @@ 'updateLabel': false }); }) - .on('dragend', function (d) { + .on('end', function (d) { // indicate that dragging as stopped d.dragging = false; @@ -1780,8 +1789,8 @@ }); // label drag behavior - labelDrag = d3.behavior.drag() - .on('dragstart', function (d) { + labelDrag = d3.drag() + .on('start', function (d) { // stop further propagation d3.event.sourceEvent.stopPropagation(); }) @@ -1806,10 +1815,10 @@ .attr('width', width) .attr('height', height) .attr('stroke-width', function () { - return 1 / nfCanvasUtils.scaleCanvasView(); + return 1 / nfCanvasUtils.getCanvasScale(); }) .attr('stroke-dasharray', function () { - return 4 / nfCanvasUtils.scaleCanvasView(); + return 4 / nfCanvasUtils.getCanvasScale(); }) .datum({ x: position.x, @@ -1864,7 +1873,7 @@ }); } }) - .on('dragend', function (d) { + .on('end', function (d) { if (d.bends.length > 1) { // get the drag selection var drag = d3.select('rect.label-drag'); @@ -1935,10 +1944,15 @@ add(connectionEntities); } - // apply the selection and handle new connections + // select var selection = select(); - selection.enter().call(renderConnections, selectAll); - selection.call(updateConnections, { + + // enter + var entered = renderConnections(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateConnections, { 'updatePath': true, 'updateLabel': false }).call(sort); @@ -1955,6 +1969,7 @@ if (selection.empty()) { return false; } + var connections = d3.map(); var components = d3.map(); var isDisconnected = true; @@ -1980,12 +1995,11 @@ } }); }); - if (isDisconnected) { + if (isDisconnected) { // go through each connection to ensure its source and destination are included - connections.forEach(function (id, connection) { + connections.each(function (connection, id) { if (isDisconnected) { - // determine whether this connection and its components are included within the selection isDisconnected = components.has(nfCanvasUtils.getConnectionSourceComponentId(connection)) && components.has(nfCanvasUtils.getConnectionDestinationComponentId(connection)); } @@ -2041,14 +2055,21 @@ set(connectionEntities); } - // apply the selection and handle all new connection + // select var selection = select(); - selection.enter().call(renderConnections, selectAll); - selection.call(updateConnections, { + + // enter + var entered = renderConnections(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateConnections, { 'updatePath': true, 'updateLabel': true, 'transition': transition }).call(sort); + + // exit selection.exit().call(removeConnections); }, @@ -2159,7 +2180,7 @@ */ getComponentConnections: function (id) { var connections = []; - connectionMap.forEach(function (_, entry) { + connectionMap.each(function (entry, _) { // see if this component is the source or destination of this connection if (nfCanvasUtils.getConnectionSourceComponentId(entry) === id || nfCanvasUtils.getConnectionDestinationComponentId(entry) === id) { connections.push(entry); @@ -2189,7 +2210,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js index c97c861d18b6..d576006331ff 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js @@ -415,7 +415,7 @@ }) .map(bulletins, d3.map); - bulletinsBySource.forEach(function (sourceId, sourceBulletins) { + bulletinsBySource.each(function (sourceBulletins, sourceId) { $('div.' + sourceId + '-bulletins').each(function () { updateBulletins(sourceBulletins, $(this)); }); @@ -789,7 +789,7 @@ // start polling for each controller service var polling = []; - services.forEach(function (controllerServiceId) { + services.each(function (controllerServiceId) { getControllerService(controllerServiceId, controllerServiceData).done(function(controllerServiceEntity) { polling.push(stopReferencingSchedulableComponents(controllerServiceEntity, pollCondition)); }); @@ -1080,7 +1080,7 @@ // start polling for each controller service var polling = []; - services.forEach(function (controllerServiceId) { + services.each(function (controllerServiceId) { getControllerService(controllerServiceId, controllerServiceData).done(function(controllerServiceEntity) { if (enabled) { polling.push(enableReferencingServices(controllerServiceEntity, pollCondition)); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js index 30f653049e0b..0a604a9b0d2e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js @@ -566,7 +566,7 @@ text: 'all groups', value: '' }]; - groups.forEach(function (group) { + groups.each(function (group) { options.push({ text: group, value: group @@ -1339,7 +1339,7 @@ .key(function(d) { return d.sourceId; }) .map(controllerServiceBulletins, d3.map); - controllerServiceBulletinsBySource.forEach(function(sourceId, sourceBulletins) { + controllerServiceBulletinsBySource.each(function(sourceBulletins, sourceId) { var controllerService = controllerServicesData.getItemById(sourceId); if (nfCommon.isDefinedAndNotNull(controllerService)) { controllerServicesData.updateItem(sourceId, $.extend(controllerService, { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js index 56ff8f596b51..5b8307b715ff 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js @@ -152,8 +152,8 @@ nfCanvas = canvas; // handle component drag events - drag = d3.behavior.drag() - .on('dragstart', function () { + drag = d3.drag() + .on('start', function () { // stop further propagation d3.event.sourceEvent.stopPropagation(); }) @@ -195,10 +195,10 @@ .attr('width', maxX - minX) .attr('height', maxY - minY) .attr('stroke-width', function () { - return 1 / nfCanvasUtils.scaleCanvasView(); + return 1 / nfCanvasUtils.getCanvasScale(); }) .attr('stroke-dasharray', function () { - return 4 / nfCanvasUtils.scaleCanvasView(); + return 4 / nfCanvasUtils.getCanvasScale(); }) .datum({ original: { @@ -220,7 +220,7 @@ }); } }) - .on('dragend', function () { + .on('end', function () { // stop further propagation d3.event.sourceEvent.stopPropagation(); @@ -390,7 +390,7 @@ }); // refresh the connections - connections.forEach(function (connectionId) { + connections.each(function (connectionId) { nfConnection.refresh(connectionId); }); }).always(function () { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js index ed5051fe65b6..a18640798c57 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js @@ -91,6 +91,7 @@ * * @param {selection} entered The selection of funnels to be rendered * @param {boolean} selected Whether the element should be selected + * @return the entered selection */ var renderFunnels = function (entered, selected) { if (entered.empty()) { @@ -98,7 +99,7 @@ } var funnel = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -109,7 +110,7 @@ // funnel border funnel.append('rect') - .attr({ + .attrs({ 'rx': 2, 'ry': 2, 'class': 'border', @@ -125,7 +126,7 @@ // funnel body funnel.append('rect') - .attr({ + .attrs({ 'rx': 2, 'ry': 2, 'class': 'body', @@ -141,7 +142,7 @@ // funnel icon funnel.append('text') - .attr({ + .attrs({ 'class': 'funnel-icon', 'x': 9, 'y': 34 @@ -150,6 +151,8 @@ // always support selection funnel.call(nfSelectable.activate).call(nfContextMenu.activate); + + return funnel; }; /** @@ -212,7 +215,7 @@ // create the funnel container funnelContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'funnels' }); @@ -252,10 +255,14 @@ add(funnelEntities); } - // apply the selection and handle new funnels + // select var selection = select(); - selection.enter().call(renderFunnels, selectAll); - selection.call(updateFunnels); + + // enter + var entered = renderFunnels(selection.enter(), selectAll); + + // update + updateFunnels(selection.merge(entered)); }, /** @@ -305,10 +312,17 @@ set(funnelEntities); } - // apply the selection and handle all new processors + // select var selection = select(); - selection.enter().call(renderFunnels, selectAll); - selection.call(updateFunnels).call(nfCanvasUtils.position, transition); + + // enter + var entered = renderFunnels(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateFunnels).call(nfCanvasUtils.position, transition); + + // exit selection.exit().call(removeFunnels); }, @@ -404,7 +418,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js index e7a62bd55ce0..16b32a226126 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js @@ -112,8 +112,8 @@ */ var updateComponentVisibility = function () { var canvasContainer = $('#canvas-container'); - var translate = nfCanvasUtils.translateCanvasView(); - var scale = nfCanvasUtils.scaleCanvasView(); + var translate = nfCanvasUtils.getCanvasTranslate(); + var scale = nfCanvasUtils.getCanvasScale(); // scale the translation translate = [translate[0] / scale, translate[1] / scale]; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js index b4c65373286b..c6f97646842c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js @@ -101,14 +101,15 @@ * * @param {selection} entered The selection of labels to be rendered * @param {boolean} selected Whether the label should be selected + * @return the entered selection */ var renderLabels = function (entered, selected) { if (entered.empty()) { - return; + return entered; } var label = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -119,7 +120,7 @@ // label border label.append('rect') - .attr({ + .attrs({ 'class': 'border', 'fill': 'transparent', 'stroke': 'transparent' @@ -127,7 +128,7 @@ // label label.append('rect') - .attr({ + .attrs({ 'class': 'body', 'filter': 'url(#component-drop-shadow)', 'stroke-width': 0 @@ -135,7 +136,7 @@ // label value label.append('text') - .attr({ + .attrs({ 'xml:space': 'preserve', 'font-weight': 'bold', 'fill': 'black', @@ -144,6 +145,8 @@ // always support selecting label.call(nfSelectable.activate).call(nfContextMenu.activate).call(nfQuickSelect.activate); + + return label; }; /** @@ -158,7 +161,7 @@ // update the border using the configured color updated.select('rect.border') - .attr({ + .attrs({ 'width': function (d) { return d.dimensions.width; }, @@ -172,7 +175,7 @@ // update the body fill using the configured color updated.select('rect.body') - .attr({ + .attrs({ 'width': function (d) { return d.dimensions.width; }, @@ -266,8 +269,8 @@ var points = labelPoint.data(pointData); // create a point for the end - points.enter().append('rect') - .attr({ + var pointsEntered = points.enter().append('rect') + .attrs({ 'class': 'labelpoint', 'width': 10, 'height': 10 @@ -275,7 +278,7 @@ .call(labelPointDrag); // update the midpoints - points.attr('transform', function (p) { + points.merge(pointsEntered).attr('transform', function (p) { return 'translate(' + (p.x - 10) + ', ' + (p.y - 10) + ')'; }); @@ -329,14 +332,14 @@ // create the label container labelContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'labels' }); // handle bend point drag events - labelPointDrag = d3.behavior.drag() - .on('dragstart', function () { + labelPointDrag = d3.drag() + .on('start', function () { // stop further propagation d3.event.sourceEvent.stopPropagation(); }) @@ -351,7 +354,7 @@ // redraw this connection updateLabels(label); }) - .on('dragend', function () { + .on('end', function () { var label = d3.select(this.parentNode); var labelData = label.datum(); @@ -448,10 +451,14 @@ add(labelEntities); } - // apply the selection and handle new labels + // select var selection = select(); - selection.enter().call(renderLabels, selectAll); - selection.call(updateLabels); + + // enter + var entered = renderLabels(selection.enter(), selectAll); + + // update + updateLabels(selection.merge(entered)); }, /** @@ -500,10 +507,17 @@ set(labelEntities); } - // apply the selection and handle all new labels + // select var selection = select(); - selection.enter().call(renderLabels, selectAll); - selection.call(updateLabels).call(nfCanvasUtils.position, transition); + + // enter + var entered = renderLabels(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateLabels).call(nfCanvasUtils.position, transition); + + // exit selection.exit().call(removeLabels); }, @@ -599,7 +613,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js index 1799a86bef56..c43cbf7e617d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js @@ -99,14 +99,15 @@ * * @param {selection} entered The selection of ports to be rendered * @param {boolean} selected Whether the port should be selected + * @return the entered selection */ var renderPorts = function (entered, selected) { if (entered.empty()) { - return; + return entered; } var port = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -123,7 +124,7 @@ // port border port.append('rect') - .attr({ + .attrs({ 'class': 'border', 'width': function (d) { return d.dimensions.width; @@ -137,7 +138,7 @@ // port body port.append('rect') - .attr({ + .attrs({ 'class': 'body', 'width': function (d) { return d.dimensions.width; @@ -157,7 +158,7 @@ // port remote banner port.append('rect') - .attr({ + .attrs({ 'class': 'remote-banner', 'width': function (d) { return d.dimensions.width; @@ -169,7 +170,7 @@ // port icon port.append('text') - .attr({ + .attrs({ 'class': 'port-icon', 'x': 10, 'y': 38 + offset @@ -184,7 +185,7 @@ // port name port.append('text') - .attr({ + .attrs({ 'x': 70, 'y': 25 + offset, 'width': 95, @@ -199,6 +200,8 @@ port.filter(function (d) { return d.permissions.canWrite && d.permissions.canRead; }).call(nfDraggable.activate).call(nfConnectable.activate); + + return port; }; /** @@ -241,7 +244,7 @@ // port transmitting icon details.append('text') - .attr({ + .attrs({ 'class': 'port-transmission-icon', 'x': 10, 'y': 18 @@ -249,7 +252,7 @@ // bulletin background details.append('rect') - .attr({ + .attrs({ 'class': 'bulletin-background', 'x': function (d) { return portData.dimensions.width - offset; @@ -260,7 +263,7 @@ // bulletin icon details.append('text') - .attr({ + .attrs({ 'class': 'bulletin-icon', 'x': function (d) { return portData.dimensions.width - 18; @@ -272,7 +275,7 @@ // run status icon details.append('text') - .attr({ + .attrs({ 'class': 'run-status-icon', 'x': 50, 'y': function () { @@ -285,7 +288,7 @@ // -------- details.append('path') - .attr({ + .attrs({ 'class': 'component-comments', 'transform': 'translate(' + (portData.dimensions.width - 2) + ', ' + (portData.dimensions.height - 10) + ')', 'd': 'm0,0 l0,8 l-8,0 z' @@ -297,7 +300,7 @@ // active thread count details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count-icon', 'y': 43 + offset }) @@ -305,7 +308,7 @@ // active thread icon details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count', 'y': 43 + offset }); @@ -416,7 +419,7 @@ // update the run status updated.select('text.run-status-icon') - .attr({ + .attrs({ 'fill': function (d) { var fill = '#728e9b'; @@ -487,7 +490,7 @@ }); updated.select('text.port-transmission-icon') - .attr({ + .attrs({ 'font-family': function (d) { if (d.status.transmitting === true) { return 'FontAwesome'; @@ -594,7 +597,7 @@ // create the port container portContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'ports' }); @@ -643,10 +646,14 @@ add(portEntities); } - // apply the selection and handle new ports + // select var selection = select(); - selection.enter().call(renderPorts, selectAll); - selection.call(updatePorts); + + // enter + var entered = renderPorts(selection.enter(), selectAll); + + // update + updatePorts(selection.merge(entered)); }, /** @@ -707,10 +714,17 @@ set(portEntities); } - // apply the selection and handle all new ports + // select var selection = select(); - selection.enter().call(renderPorts, selectAll); - selection.call(updatePorts).call(nfCanvasUtils.position, transition); + + // enter + var entered = renderPorts(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updatePorts).call(nfCanvasUtils.position, transition); + + // exit selection.exit().call(removePorts); }, @@ -813,7 +827,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js index dc7034ae9f9a..dd147c4d0dd8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js @@ -108,14 +108,15 @@ * * @param {selection} entered The selection of process groups to be rendered * @param {boolean} selected Whether the process group should be selected + * @return the entered selection */ var renderProcessGroups = function (entered, selected) { if (entered.empty()) { - return; + return entered; } var processGroup = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -130,7 +131,7 @@ // process group border processGroup.append('rect') - .attr({ + .attrs({ 'class': 'border', 'width': function (d) { return d.dimensions.width; @@ -144,7 +145,7 @@ // process group body processGroup.append('rect') - .attr({ + .attrs({ 'class': 'body', 'width': function (d) { return d.dimensions.width; @@ -158,7 +159,7 @@ // process group name background processGroup.append('rect') - .attr({ + .attrs({ 'width': function (d) { return d.dimensions.width; }, @@ -168,7 +169,7 @@ // process group name processGroup.append('text') - .attr({ + .attrs({ 'x': 10, 'y': 20, 'width': 316, @@ -178,7 +179,7 @@ // process group name processGroup.append('text') - .attr({ + .attrs({ 'x': 10, 'y': 21, 'class': 'version-control' @@ -228,6 +229,8 @@ }) .call(nfDraggable.activate) .call(nfConnectable.activate); + + return processGroup; }; // attempt of space between component count and icon for process group contents @@ -273,7 +276,7 @@ // ------------------- details.append('rect') - .attr({ + .attrs({ 'x': 0, 'y': 32, 'width': function () { @@ -284,7 +287,7 @@ }); details.append('rect') - .attr({ + .attrs({ 'x': 0, 'y': function () { return processGroupData.dimensions.height - 24; @@ -302,7 +305,7 @@ // transmitting icon details.append('text') - .attr({ + .attrs({ 'x': 10, 'y': 49, 'class': 'process-group-transmitting process-group-contents-icon', @@ -315,14 +318,14 @@ // transmitting count details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-transmitting-count process-group-contents-count' }); // not transmitting icon details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-not-transmitting process-group-contents-icon', 'font-family': 'flowfont' @@ -333,14 +336,14 @@ // not transmitting count details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-not-transmitting-count process-group-contents-count' }); // running icon details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-running process-group-contents-icon', 'font-family': 'FontAwesome' @@ -351,14 +354,14 @@ // running count details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-running-count process-group-contents-count' }); // stopped icon details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-stopped process-group-contents-icon', 'font-family': 'FontAwesome' @@ -369,14 +372,14 @@ // stopped count details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-stopped-count process-group-contents-count' }); // invalid icon details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-invalid process-group-contents-icon', 'font-family': 'FontAwesome' @@ -387,14 +390,14 @@ // invalid count details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-invalid-count process-group-contents-count' }); // disabled icon details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-disabled process-group-contents-icon', 'font-family': 'flowfont' @@ -405,14 +408,14 @@ // disabled count details.append('text') - .attr({ + .attrs({ 'y': 49, 'class': 'process-group-disabled-count process-group-contents-count' }); // up to date icon details.append('text') - .attr({ + .attrs({ 'x': 10, 'y': function () { return processGroupData.dimensions.height - 7; @@ -426,7 +429,7 @@ // up to date count details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -435,7 +438,7 @@ // locally modified icon details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -448,7 +451,7 @@ // locally modified count details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -457,7 +460,7 @@ // stale icon details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -470,7 +473,7 @@ // stale count details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -479,7 +482,7 @@ // locally modified and stale icon details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -492,7 +495,7 @@ // locally modified and stale count details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -501,7 +504,7 @@ // sync failure icon details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -514,7 +517,7 @@ // sync failure count details.append('text') - .attr({ + .attrs({ 'y': function () { return processGroupData.dimensions.height - 7; }, @@ -527,7 +530,7 @@ // queued details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -539,7 +542,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -551,7 +554,7 @@ // in details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -563,7 +566,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -575,7 +578,7 @@ // read/write details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -587,7 +590,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -599,7 +602,7 @@ // out details.append('rect') - .attr({ + .attrs({ 'width': function () { return processGroupData.dimensions.width; }, @@ -615,13 +618,13 @@ // stats label container var processGroupStatsLabel = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(6, 75)' }); // queued label processGroupStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'x': 4, @@ -632,7 +635,7 @@ // in label processGroupStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'x': 4, @@ -643,7 +646,7 @@ // read/write label processGroupStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'x': 4, @@ -654,7 +657,7 @@ // out label processGroupStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'x': 4, @@ -665,13 +668,13 @@ // stats value container var processGroupStatsValue = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(95, 75)' }); // queued value var queuedText = processGroupStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'x': 4, @@ -681,19 +684,19 @@ // queued count queuedText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // queued size queuedText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // in value var inText = processGroupStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'x': 4, @@ -703,25 +706,25 @@ // in count inText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // in size inText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // in inText.append('tspan') - .attr({ + .attrs({ 'class': 'ports' }); // read/write value processGroupStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'x': 4, @@ -731,7 +734,7 @@ // out value var outText = processGroupStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'x': 4, @@ -741,31 +744,31 @@ // out ports outText.append('tspan') - .attr({ + .attrs({ 'class': 'ports' }); // out count outText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // out size outText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // stats value container var processGroupStatsInfo = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(335, 75)' }); // in info processGroupStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'x': 4, @@ -776,7 +779,7 @@ // read/write info processGroupStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'x': 4, @@ -787,7 +790,7 @@ // out info processGroupStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'x': 4, @@ -801,7 +804,7 @@ // -------- details.append('path') - .attr({ + .attrs({ 'class': 'component-comments', 'transform': 'translate(' + (processGroupData.dimensions.width - 2) + ', ' + (processGroupData.dimensions.height - 10) + ')', 'd': 'm0,0 l0,8 l-8,0 z' @@ -813,7 +816,7 @@ // active thread count details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count-icon', 'y': 20 }) @@ -821,7 +824,7 @@ // active thread icon details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count', 'y': 20 }); @@ -832,7 +835,7 @@ // bulletin background details.append('rect') - .attr({ + .attrs({ 'class': 'bulletin-background', 'x': function () { return processGroupData.dimensions.width - 24; @@ -844,7 +847,7 @@ // bulletin icon details.append('text') - .attr({ + .attrs({ 'class': 'bulletin-icon', 'x': function () { return processGroupData.dimensions.width - 17; @@ -1090,7 +1093,7 @@ // update version control information var versionControl = processGroup.select('text.version-control') - .style({ + .styles({ 'visibility': isUnderVersionControl(processGroupData) ? 'visible' : 'hidden', 'fill': function () { if (isUnderVersionControl(processGroupData)) { @@ -1198,7 +1201,7 @@ // update the process group name processGroup.select('text.process-group-name') - .attr({ + .attrs({ 'x': function () { if (isUnderVersionControl(processGroupData)) { var versionControlX = parseInt(versionControl.attr('x'), 10); @@ -1236,7 +1239,7 @@ // clear the process group name processGroup.select('text.process-group-name') - .attr({ + .attrs({ 'x': 10, 'width': 316 }) @@ -1414,7 +1417,7 @@ // create the process group container processGroupContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'process-groups' }); @@ -1454,10 +1457,14 @@ add(processGroupEntities); } - // apply the selection and handle new process groups + // select var selection = select(); - selection.enter().call(renderProcessGroups, selectAll); - selection.call(updateProcessGroups); + + // enter + var entered = renderProcessGroups(selection.enter(), selectAll); + + // update + updateProcessGroups(selection.merge(entered)); }, /** @@ -1508,10 +1515,17 @@ set(processGroupEntities); } - // apply the selection and handle all new process group + // select var selection = select(); - selection.enter().call(renderProcessGroups, selectAll); - selection.call(updateProcessGroups).call(nfCanvasUtils.position, transition); + + // enter + var entered = renderProcessGroups(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateProcessGroups).call(nfCanvasUtils.position, transition); + + // exit selection.exit().call(removeProcessGroups); }, @@ -1614,7 +1628,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } @@ -1646,12 +1660,7 @@ // if the view was not restore attempt to fit if (viewRestored === false) { - nfCanvasUtils.fitCanvasView(); - - // refresh the canvas - nfCanvasUtils.refreshCanvasView({ - transition: true - }); + nfCanvasUtils.fitCanvas(); } // update URL deep linking params diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js index 8b991a3d6473..b30c9813e801 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js @@ -93,14 +93,20 @@ }); }; - // renders the processors + /** + * Renders the processors in the specified selection. + * + * @param {selection} entered The selection of processors to be rendered + * @param {boolean} selected Whether the element should be selected + * @return the entered selection + */ var renderProcessors = function (entered, selected) { if (entered.empty()) { - return; + return entered; } var processor = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -111,7 +117,7 @@ // processor border processor.append('rect') - .attr({ + .attrs({ 'class': 'border', 'width': function (d) { return d.dimensions.width; @@ -125,7 +131,7 @@ // processor body processor.append('rect') - .attr({ + .attrs({ 'class': 'body', 'width': function (d) { return d.dimensions.width; @@ -139,7 +145,7 @@ // processor name processor.append('text') - .attr({ + .attrs({ 'x': 75, 'y': 18, 'width': 210, @@ -149,7 +155,7 @@ // processor icon container processor.append('rect') - .attr({ + .attrs({ 'x': 0, 'y': 0, 'width': 50, @@ -159,7 +165,7 @@ // processor icon processor.append('text') - .attr({ + .attrs({ 'x': 9, 'y': 35, 'class': 'processor-icon' @@ -168,7 +174,7 @@ // restricted icon background processor.append('circle') - .attr({ + .attrs({ 'r': 9, 'cx': 12, 'cy': 12, @@ -177,7 +183,7 @@ // restricted icon processor.append('text') - .attr({ + .attrs({ 'x': 7.75, 'y': 17, 'class': 'restricted' @@ -186,7 +192,7 @@ // is primary icon background processor.append('circle') - .attr({ + .attrs({ 'r': 9, 'cx': 38, 'cy': 36, @@ -195,7 +201,7 @@ // is primary icon processor.append('text') - .attr({ + .attrs({ 'x': 34.75, 'y': 40, 'class': 'is-primary' @@ -207,6 +213,8 @@ // make processors selectable processor.call(nfSelectable.activate).call(nfContextMenu.activate).call(nfQuickSelect.activate); + + return processor; }; /** @@ -248,7 +256,7 @@ // run status icon details.append('text') - .attr({ + .attrs({ 'class': 'run-status-icon', 'x': 55, 'y': 23 @@ -256,7 +264,7 @@ // processor type details.append('text') - .attr({ + .attrs({ 'class': 'processor-type', 'x': 75, 'y': 32, @@ -266,7 +274,7 @@ // processor type details.append('text') - .attr({ + .attrs({ 'class': 'processor-bundle', 'x': 75, 'y': 45, @@ -282,7 +290,7 @@ // in details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -294,7 +302,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -306,7 +314,7 @@ // read/write details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -318,7 +326,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -330,7 +338,7 @@ // out details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -342,7 +350,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -354,7 +362,7 @@ // tasks/time details.append('rect') - .attr({ + .attrs({ 'width': function () { return processorData.dimensions.width; }, @@ -366,13 +374,13 @@ // stats label container var processorStatsLabel = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(10, 55)' }); // in label processorStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'y': 9, @@ -382,7 +390,7 @@ // read/write label processorStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'y': 27, @@ -392,7 +400,7 @@ // out label processorStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'y': 46, @@ -402,7 +410,7 @@ // tasks/time label processorStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'y': 65, @@ -412,13 +420,13 @@ // stats value container var processorStatsValue = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(85, 55)' }); // in value var inText = processorStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 9, 'y': 9, @@ -427,19 +435,19 @@ // in count inText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // in size inText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // read/write value processorStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'y': 27, @@ -448,7 +456,7 @@ // out value var outText = processorStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'y': 46, @@ -457,19 +465,19 @@ // out count outText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // out size outText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // tasks/time value processorStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'y': 65, @@ -482,7 +490,7 @@ // in info processorStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'y': 9, @@ -492,7 +500,7 @@ // read/write info processorStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'y': 27, @@ -502,7 +510,7 @@ // out info processorStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'y': 46, @@ -512,7 +520,7 @@ // tasks/time info processorStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'y': 65, @@ -525,7 +533,7 @@ // -------- details.append('path') - .attr({ + .attrs({ 'class': 'component-comments', 'transform': 'translate(' + (processorData.dimensions.width - 2) + ', ' + (processorData.dimensions.height - 10) + ')', 'd': 'm0,0 l0,8 l-8,0 z' @@ -537,7 +545,7 @@ // active thread count details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count-icon', 'y': 45 }) @@ -545,7 +553,7 @@ // active thread background details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count', 'y': 45 }); @@ -556,7 +564,7 @@ // bulletin background details.append('rect') - .attr({ + .attrs({ 'class': 'bulletin-background', 'x': function (d) { return processorData.dimensions.width - 24; @@ -567,7 +575,7 @@ // bulletin icon details.append('text') - .attr({ + .attrs({ 'class': 'bulletin-icon', 'x': function (d) { return processorData.dimensions.width - 17; @@ -799,7 +807,7 @@ // update the run status updated.select('text.run-status-icon') - .attr({ + .attrs({ 'fill': function (d) { var fill = '#728e9b'; @@ -978,7 +986,7 @@ // create the processor container processorContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'processors' }); @@ -1018,10 +1026,14 @@ add(processorEntities); } - // apply the selection and handle new processor + // select var selection = select(); - selection.enter().call(renderProcessors, selectAll); - selection.call(updateProcessors); + + // enter + var entered = renderProcessors(selection.enter(), selectAll); + + // update + updateProcessors(selection.merge(entered)); }, /** @@ -1072,10 +1084,18 @@ set(processorEntities); } - // apply the selection and handle all new processors + // select var selection = select(); - selection.enter().call(renderProcessors, selectAll); - selection.call(updateProcessors).call(nfCanvasUtils.position, transition); + + // enter + var entered = renderProcessors(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateProcessors); + updated.call(nfCanvasUtils.position, transition); + + // exit selection.exit().call(removeProcessors); }, @@ -1178,7 +1198,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js index a58d8db89f03..ce3755cc5330 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js @@ -97,14 +97,15 @@ * * @param {selection} entered The selection of remote process groups to be rendered * @param {boolean} selected Whether the remote process group is selected + * @return the entered selection */ var renderRemoteProcessGroups = function (entered, selected) { if (entered.empty()) { - return; + return entered; } var remoteProcessGroup = entered.append('g') - .attr({ + .attrs({ 'id': function (d) { return 'id-' + d.id; }, @@ -119,7 +120,7 @@ // remote process group border remoteProcessGroup.append('rect') - .attr({ + .attrs({ 'class': 'border', 'width': function (d) { return d.dimensions.width; @@ -133,7 +134,7 @@ // remote process group body remoteProcessGroup.append('rect') - .attr({ + .attrs({ 'class': 'body', 'width': function (d) { return d.dimensions.width; @@ -147,7 +148,7 @@ // remote process group name background remoteProcessGroup.append('rect') - .attr({ + .attrs({ 'width': function (d) { return d.dimensions.width; }, @@ -157,7 +158,7 @@ // remote process group name remoteProcessGroup.append('text') - .attr({ + .attrs({ 'x': 30, 'y': 20, 'width': 305, @@ -167,6 +168,8 @@ // always support selection remoteProcessGroup.call(nfSelectable.activate).call(nfContextMenu.activate).call(nfQuickSelect.activate); + + return remoteProcessGroup; }; /** @@ -205,7 +208,7 @@ // remote process group transmission status details.append('text') - .attr({ + .attrs({ 'class': 'remote-process-group-transmission-status', 'x': 10, 'y': 20 @@ -216,7 +219,7 @@ // ------------------ details.append('rect') - .attr({ + .attrs({ 'x': 0, 'y': 32, 'width': function () { @@ -232,7 +235,7 @@ // remote process group secure transfer details.append('text') - .attr({ + .attrs({ 'class': 'remote-process-group-transmission-secure', 'x': 10, 'y': 48 @@ -240,7 +243,7 @@ // remote process group uri details.append('text') - .attr({ + .attrs({ 'x': 30, 'y': 48, 'width': 305, @@ -254,7 +257,7 @@ // sent details.append('rect') - .attr({ + .attrs({ 'width': function () { return remoteProcessGroupData.dimensions.width; }, @@ -266,7 +269,7 @@ // border details.append('rect') - .attr({ + .attrs({ 'width': function () { return remoteProcessGroupData.dimensions.width; }, @@ -278,7 +281,7 @@ // received details.append('rect') - .attr({ + .attrs({ 'width': function () { return remoteProcessGroupData.dimensions.width; }, @@ -294,13 +297,13 @@ // stats label container var remoteProcessGroupStatsLabel = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(6, 75)' }); // sent label remoteProcessGroupStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'x': 4, @@ -311,7 +314,7 @@ // received label remoteProcessGroupStatsLabel.append('text') - .attr({ + .attrs({ 'width': 73, 'height': 10, 'x': 4, @@ -322,13 +325,13 @@ // stats value container var remoteProcessGroupStatsValue = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(95, 75)' }); // sent value var sentText = remoteProcessGroupStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'x': 4, @@ -338,25 +341,25 @@ // sent count sentText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // sent size sentText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // sent ports sentText.append('tspan') - .attr({ + .attrs({ 'class': 'ports' }); // received value var receivedText = remoteProcessGroupStatsValue.append('text') - .attr({ + .attrs({ 'width': 180, 'height': 10, 'x': 4, @@ -366,31 +369,31 @@ // received ports receivedText.append('tspan') - .attr({ + .attrs({ 'class': 'ports' }); // received count receivedText.append('tspan') - .attr({ + .attrs({ 'class': 'count' }); // received size receivedText.append('tspan') - .attr({ + .attrs({ 'class': 'size' }); // stats value container var processGroupStatsInfo = details.append('g') - .attr({ + .attrs({ 'transform': 'translate(335, 75)' }); // sent info processGroupStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'x': 4, @@ -401,7 +404,7 @@ // received info processGroupStatsInfo.append('text') - .attr({ + .attrs({ 'width': 25, 'height': 10, 'x': 4, @@ -415,7 +418,7 @@ // ------------------- details.append('rect') - .attr({ + .attrs({ 'x': 0, 'y': function () { return remoteProcessGroupData.dimensions.height - 24; @@ -428,7 +431,7 @@ }); details.append('text') - .attr({ + .attrs({ 'x': 10, 'y': 150, 'class': 'remote-process-group-last-refresh' @@ -439,7 +442,7 @@ // -------- details.append('path') - .attr({ + .attrs({ 'class': 'component-comments', 'transform': 'translate(' + (remoteProcessGroupData.dimensions.width - 2) + ', ' + (remoteProcessGroupData.dimensions.height - 10) + ')', 'd': 'm0,0 l0,8 l-8,0 z' @@ -451,7 +454,7 @@ // active thread count details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count-icon', 'y': 20 }) @@ -459,7 +462,7 @@ // active thread icon details.append('text') - .attr({ + .attrs({ 'class': 'active-thread-count', 'y': 20 }); @@ -470,7 +473,7 @@ // bulletin background details.append('rect') - .attr({ + .attrs({ 'class': 'bulletin-background', 'x': function () { return remoteProcessGroupData.dimensions.width - 24; @@ -482,7 +485,7 @@ // bulletin icon details.append('text') - .attr({ + .attrs({ 'class': 'bulletin-icon', 'x': function () { return remoteProcessGroupData.dimensions.width - 17; @@ -867,7 +870,7 @@ // create the process group container remoteProcessGroupContainer = d3.select('#canvas').append('g') - .attr({ + .attrs({ 'pointer-events': 'all', 'class': 'remote-process-groups' }); @@ -907,10 +910,14 @@ add(remoteProcessGroupEntities); } - // apply the selection and handle new remote process groups + // select var selection = select(); - selection.enter().call(renderRemoteProcessGroups, selectAll); - selection.call(updateRemoteProcessGroups); + + // enter + var entered = renderRemoteProcessGroups(selection.enter(), selectAll); + + // update + updateRemoteProcessGroups(selection.merge(entered)); }, /** @@ -961,10 +968,17 @@ set(remoteProcessGroupEntities); } - // apply the selection and handle all new remote process groups + // select var selection = select(); - selection.enter().call(renderRemoteProcessGroups, selectAll); - selection.call(updateRemoteProcessGroups).call(nfCanvasUtils.position, transition); + + // enter + var entered = renderRemoteProcessGroups(selection.enter(), selectAll); + + // update + var updated = selection.merge(entered); + updated.call(updateRemoteProcessGroups).call(nfCanvasUtils.position, transition); + + // exit selection.exit().call(removeRemoteProcessGroups); }, @@ -1075,7 +1089,7 @@ */ expireCaches: function (timestamp) { var expire = function (cache) { - cache.forEach(function (id, entryTimestamp) { + cache.each(function (entryTimestamp, id) { if (timestamp > entryTimestamp) { cache.remove(id); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js index d3289c764651..824312adb558 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js @@ -756,7 +756,7 @@ text: 'all groups', value: '' }]; - groups.forEach(function (group) { + groups.each(function (group) { options.push({ text: group, value: group @@ -1799,7 +1799,7 @@ }) .map(reportingTaskBulletins, d3.map); - reportingTaskBulletinsBySource.forEach(function (sourceId, sourceBulletins) { + reportingTaskBulletinsBySource.each(function (sourceBulletins, sourceId) { var reportingTask = reportingTasksData.getItemById(sourceId); if (nfCommon.isDefinedAndNotNull(reportingTask)) { reportingTasksData.updateItem(sourceId, $.extend(reportingTask, { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-variable-registry.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-variable-registry.js index 24c00ab0a109..7265b7074678 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-variable-registry.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-variable-registry.js @@ -920,7 +920,7 @@ }) .map(bulletins, d3.map); - bulletinsBySource.forEach(function (sourceId, sourceBulletins) { + bulletinsBySource.each(function (sourceBulletins, sourceId) { $('div.' + sourceId + '-affected-bulletins').each(function () { var bulletinIcon = $(this); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-status-history.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-status-history.js index 190160025dfb..83cf5f8d6d07 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-status-history.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-status-history.js @@ -87,9 +87,9 @@ var serverTimeOffset = null; /** - * The current extent of the brush. + * The current selection of the brush. */ - var brushExtent = null; + var brushSelection = null; /** * The currently selected descriptor. @@ -192,7 +192,7 @@ // get the current user time to properly convert the server time var now = new Date(); - // conver the user offset to millis + // convert the user offset to millis var userTimeOffset = now.getTimezoneOffset() * 60 * 1000; // create the proper date by adjusting by the offsets @@ -240,7 +240,7 @@ if (selectedDescriptor !== null) { // clear the current extent if this is a newly selected descriptor if (descriptor === null || descriptor.field !== selectedDescriptor.field) { - brushExtent = null; + brushSelection = null; } // record the currently selected descriptor @@ -296,7 +296,7 @@ // add status history details var detailsContainer = buildDetailsContainer('Status History'); - d3.map(statusHistory.details).forEach(function (label, value) { + d3.map(statusHistory.details).each(function (value, label) { addDetailItem(detailsContainer, label, value); }); @@ -312,7 +312,7 @@ // ------------- // available colors - var color = d3.scale.category10(); + var color = d3.scaleOrdinal(d3.schemeCategory10); // determine the available instances var instanceLabels = []; @@ -351,32 +351,23 @@ // custom time axis formatter // -------------------------- - var customTimeFormat = d3.time.format.multi([ - [':%S.%L', function (d) { - return d.getMilliseconds(); - }], - [':%S', function (d) { - return d.getSeconds(); - }], - ['%H:%M', function (d) { - return d.getMinutes(); - }], - ['%H:%M', function (d) { - return d.getHours(); - }], - ['%a %d', function (d) { - return d.getDay() && d.getDate() !== 1; - }], - ['%b %d', function (d) { - return d.getDate() !== 1; - }], - ['%B', function (d) { - return d.getMonth(); - }], - ['%Y', function () { - return true; - }] - ]); + var customTimeFormat = function (d) { + if (d.getMilliseconds()) { + return d3.timeFormat(':%S.%L')(d); + } else if (d.getSeconds()) { + return d3.timeFormat(':%S')(d); + } else if (d.getMinutes() || d.getHours()) { + return d3.timeFormat('%H:%M')(d); + } else if (d.getDay() && d.getDate() !== 1) { + return d3.timeFormat('%a %d')(d); + } else if (d.getDate() !== 1) { + return d3.timeFormat('%b %d')(d); + } else if (d.getMonth()) { + return d3.timeFormat('%B')(d); + } else { + return d3.timeFormat('%Y')(d); + } + }; // ---------- // main chart @@ -407,28 +398,23 @@ } // define the x axis for the main chart - var x = d3.time.scale() + var x = d3.scaleTime() .range([0, width]); - var xAxis = d3.svg.axis() - .scale(x) + var xAxis = d3.axisBottom(x) .ticks(5) - .tickFormat(customTimeFormat) - .orient('bottom'); + .tickFormat(customTimeFormat); // define the y axis - var y = d3.scale.linear() + var y = d3.scaleLinear() .range([height, 0]); - var yAxis = d3.svg.axis() - .scale(y) - .tickFormat(formatters[selectedDescriptor.formatter]) - .orient('left'); - + var yAxis = d3.axisLeft(y) + .tickFormat(formatters[selectedDescriptor.formatter]); // status line - var line = d3.svg.line() - .interpolate('monotone') + var line = d3.line() + .curve(d3.curveMonotoneX) .x(function (d) { return x(d.timestamp); }) @@ -441,6 +427,7 @@ .attr('style', 'pointer-events: none;') .attr('width', chartContainer.parent().width()) .attr('height', chartContainer.innerHeight()); + // define a clip the path var clipPath = chartSvg.append('defs').append('clipPath') .attr('id', 'clip') @@ -569,27 +556,23 @@ var chartControlContainer = $('#status-history-chart-control-container').empty(); var controlHeight = chartControlContainer.innerHeight() - margin.top - margin.bottom; - var xControl = d3.time.scale() + var xControl = d3.scaleTime() .range([0, width]); - var xControlAxis = d3.svg.axis() - .scale(xControl) + var xControlAxis = d3.axisBottom(xControl) .ticks(5) - .tickFormat(customTimeFormat) - .orient('bottom'); + .tickFormat(customTimeFormat); - var yControl = d3.scale.linear() + var yControl = d3.scaleLinear() .range([controlHeight, 0]); - var yControlAxis = d3.svg.axis() - .scale(yControl) + var yControlAxis = d3.axisLeft(yControl) .tickValues(y.domain()) - .tickFormat(formatters[selectedDescriptor.formatter]) - .orient('left'); + .tickFormat(formatters[selectedDescriptor.formatter]); // status line - var controlLine = d3.svg.line() - .interpolate('monotone') + var controlLine = d3.line() + .curve(d3.curveMonotoneX) .x(function (d) { return xControl(d.timestamp); }) @@ -606,13 +589,9 @@ var control = controlChartSvg.append('g') .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')'); - // increase the y domain slightly - var yControlDomain = y.domain(); - yControlDomain[1] *= 1.04; - // define the domain for the control chart xControl.domain(x.domain()); - yControl.domain(yControlDomain); + yControl.domain(y.domain()); // build the control x axis control.append('g') @@ -651,6 +630,53 @@ return d.label; }); + // -------------------- + // aggregate statistics + // -------------------- + + var updateAggregateStatistics = function () { + // locate the instances that have data points within the current brush + var withinBrush = $.map(statusData, function (d) { + var xDomain = x.domain(); + var yDomain = y.domain(); + + // copy to avoid modifying the original + var copy = $.extend({}, d); + + // update the copy to only include values within the brush + return $.extend(copy, { + values: $.grep(d.values, function (s) { + return s.timestamp.getTime() >= xDomain[0].getTime() && s.timestamp.getTime() <= xDomain[1].getTime() && s.value >= yDomain[0] && s.value <= yDomain[1]; + }) + }); + }); + + // consider visible nodes with data in the brush + var nodes = $.grep(withinBrush, function (d) { + return d.id !== config.nifiInstanceId && d.visible && d.values.length > 0; + }); + + var nodeMinValue = nodes.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMinValue(nodes)); + var nodeMeanValue = nodes.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMeanValue(nodes)); + var nodeMaxValue = nodes.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMaxValue(nodes)); + + // update the currently displayed min/max/mean + $('#node-aggregate-statistics').text(nodeMinValue + ' / ' + nodeMaxValue + ' / ' + nodeMeanValue); + + // only consider the cluster with data in the brush + var cluster = $.grep(withinBrush, function (d) { + return d.id === config.nifiInstanceId && d.visible && d.values.length > 0; + }); + + // determine the cluster values + var clusterMinValue = cluster.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMinValue(cluster)); + var clusterMeanValue = cluster.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMeanValue(cluster)); + var clusterMaxValue = cluster.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMaxValue(cluster)); + + // update the cluster min/max/mean + $('#cluster-aggregate-statistics').text(clusterMinValue + ' / ' + clusterMaxValue + ' / ' + clusterMeanValue); + }; + // ------------------- // configure the brush // ------------------- @@ -679,7 +705,7 @@ return y(v.value); }) .attr('r', function () { - return brush.empty() ? 1.5 : 4; + return d3.brushSelection(brushNode.node()) === null ? 1.5 : 4; }); // update the x axis @@ -692,9 +718,11 @@ * or the control domain if there is no context window. */ var brushed = function () { + brushSelection = d3.brushSelection(brushNode.node()); + // determine the new x and y domains var xContextDomain, yContextDomain; - if (brush.empty()) { + if (brushSelection === null) { // get the all visible instances var visibleInstances = $.grep(statusData, function (d) { return d.visible; @@ -718,16 +746,9 @@ ]; } xContextDomain = xControl.domain(); - - // clear the current extent - brushExtent = null; } else { - var extent = brush.extent(); - xContextDomain = [extent[0][0], extent[1][0]]; - yContextDomain = [extent[0][1], extent[1][1]]; - - // hold onto the current brush - brushExtent = extent; + xContextDomain = [brushSelection[0][0], brushSelection[1][0]].map(xControl.invert, xControl); + yContextDomain = [brushSelection[1][1], brushSelection[0][1]].map(yControl.invert, yControl); } // update the axes accordingly @@ -738,90 +759,34 @@ }; // build the brush - var brush = d3.svg.brush() - .x(xControl) - .y(yControl) + var brush = d3.brush() + .extent([[xControl.range()[0], yControl.range()[1]], [xControl.range()[1], yControl.range()[0]]]) .on('brush', brushed); - // conditionally set the brush extent - if (nfCommon.isDefinedAndNotNull(brushExtent)) { - brush = brush.extent(brushExtent); - } - // context area - control.append('g') + var brushNode = control.append('g') .attr('class', 'brush') + .on('click', brushed) .call(brush); + // conditionally set the brush extent + if (nfCommon.isDefinedAndNotNull(brushSelection)) { + brush = brush.move(brushNode, brushSelection); + } + // add expansion to the extent - control.select('rect.extent') + control.select('rect.selection') .attr('style', 'pointer-events: all;') .on('dblclick', function () { - if (!brush.empty()) { - // get the current extent to get the x range - var extent = brush.extent(); - + if (brushSelection !== null) { // get the y range (this value does not change from the original y domain) - var yRange = yControl.domain(); + var yRange = yControl.range(); // expand the extent vertically - brush.extent([[extent[0][0], yRange[0]], [extent[1][0], yRange[1]]]); - - // update the brush control - control.select('.brush').call(brush); - - // run the brush to update the axes of the main chart - brushed(); + brush.move(brushNode, [[brushSelection[0][0], yRange[1]], [brushSelection[1][0], yRange[0]]]); } }); - // -------------------- - // aggregate statistics - // -------------------- - - var updateAggregateStatistics = function () { - // locate the instances that have data points within the current brush - var withinBrush = $.map(statusData, function (d) { - var xDomain = x.domain(); - var yDomain = y.domain(); - - // copy to avoid modifying the original - var copy = $.extend({}, d); - - // update the copy to only include values within the brush - return $.extend(copy, { - values: $.grep(d.values, function (s) { - return s.timestamp.getTime() >= xDomain[0].getTime() && s.timestamp.getTime() <= xDomain[1].getTime() && s.value >= yDomain[0] && s.value <= yDomain[1]; - }) - }); - }); - - // consider visible nodes with data in the brush - var nodes = $.grep(withinBrush, function (d) { - return d.id !== config.nifiInstanceId && d.visible && d.values.length > 0; - }); - - var nodeMinValue = nodes.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMinValue(nodes)); - var nodeMeanValue = nodes.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMeanValue(nodes)); - var nodeMaxValue = nodes.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMaxValue(nodes)); - - // update the currently displayed min/max/mean - $('#node-aggregate-statistics').text(nodeMinValue + ' / ' + nodeMaxValue + ' / ' + nodeMeanValue); - - // only consider the cluster with data in the brush - var cluster = $.grep(withinBrush, function (d) { - return d.id === config.nifiInstanceId && d.visible && d.values.length > 0; - }); - - // determine the cluster values - var clusterMinValue = cluster.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMinValue(cluster)); - var clusterMeanValue = cluster.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMeanValue(cluster)); - var clusterMaxValue = cluster.length === 0 ? 'NA' : formatters[selectedDescriptor.formatter](getMaxValue(cluster)); - - // update the cluster min/max/mean - $('#cluster-aggregate-statistics').text(clusterMinValue + ' / ' + clusterMaxValue + ' / ' + clusterMeanValue); - }; - // ---------------- // build the legend // ---------------- @@ -906,19 +871,13 @@ // handle resizing // --------------- - var maxWidth, maxHeight, minHeight, resizeExtent, dialog; + var maxWidth, maxHeight, minHeight, dialog; chartContainer.append('
').resizable({ minWidth: 425, minHeight: 150, handles: { 'se': '.ui-resizable-se' }, - start: function (e, ui) { - // record the current extent so it can be reset on stop - if (!brush.empty()) { - resizeExtent = brush.extent(); - } - }, resize: function (e, ui) { // ----------- // containment @@ -1099,7 +1058,7 @@ $('#status-history-details').empty(); // clear the extent and selected descriptor - brushExtent = null; + brushSelection = null; descriptor = null; instances = null; }, diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js index 6295c0b595f9..b67e474f470e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js @@ -238,7 +238,7 @@ // push off processing a node until its deepest point // by removing any descendants from the immediate nodes. // in this case, a link is panning multiple levels - descendantSet.forEach(function (d) { + descendantSet.each(function (d) { immediateSet.remove(d); }); @@ -478,7 +478,7 @@ var startNodes = d3.set(nodeLookup.keys()); // go through the nodes to reset their outgoing links - nodeLookup.forEach(function (id, node) { + nodeLookup.each(function (node, id) { node.outgoing = []; node.incoming = []; @@ -493,7 +493,7 @@ }); // go through the links in order to compute the new layout - linkLookup.forEach(function (id, link) { + linkLookup.each(function (link, id) { // updating the nodes connections link.source.outgoing.push(link); link.target.incoming.push(link); @@ -535,11 +535,11 @@ }); // handle zoom behavior - var lineageZoom = d3.behavior.zoom() + var lineageZoom = d3.zoom() .scaleExtent([0.2, 8]) .on('zoom', function () { d3.select('g.lineage').attr('transform', function () { - return 'translate(' + d3.event.translate + ') scale(' + d3.event.scale + ')'; + return 'translate(' + d3.event.transform.x + ', ' + d3.event.transform.y + ') scale(' + d3.event.transform.k + ')'; }); }); @@ -576,7 +576,7 @@ }); svg.append('rect') - .attr({ + .attrs({ 'width': '100%', 'height': '100%', 'fill': '#f9fafb' @@ -585,7 +585,7 @@ svg.append('defs').selectAll('marker') .data(['FLOWFILE', 'FLOWFILE-SELECTED', 'EVENT', 'EVENT-SELECTED']) .enter().append('marker') - .attr({ + .attrs({ 'id': function (d) { return d; }, @@ -614,7 +614,7 @@ // group everything together var lineageContainer = svg.append('g') - .attr({ + .attrs({ 'transform': 'translate(0, 0) scale(1)', 'pointer-events': 'all', 'class': 'lineage' @@ -638,8 +638,8 @@ }); // hide applicable nodes and lines - linksToHide.transition().duration(400).style('opacity', 0); nodesToHide.transition().delay(200).duration(400).style('opacity', 0); + linksToHide.transition().duration(400).style('opacity', 0); } else { // the slider is ascending @@ -652,8 +652,8 @@ }); // show applicable nodes and lines - nodesToShow.transition().duration(400).style('opacity', 1); linksToShow.transition().delay(200).duration(400).style('opacity', 1); + nodesToShow.transition().duration(400).style('opacity', 1); } // update the event time @@ -679,7 +679,7 @@ // node flowfiles.append('circle') - .attr({ + .attrs({ 'r': 16, 'fill': '#fff', 'stroke': '#000', @@ -704,13 +704,13 @@ }); var icon = flowfiles.append('g') - .attr({ + .attrs({ 'class': 'flowfile-icon', 'transform': function (d) { return 'translate(-9,-9)'; } }).append('text') - .attr({ + .attrs({ 'font-family': 'flowfont', 'font-size': '18px', 'fill': '#ad9897', @@ -1021,7 +1021,7 @@ .classed('event', true) // join node to its label .append('rect') - .attr({ + .attrs({ 'x': 0, 'y': -8, 'height': 16, @@ -1037,7 +1037,7 @@ .classed('selected', function (d) { return d.id === eventId; }) - .attr({ + .attrs({ 'r': 8, 'fill': '#aabbc3', 'stroke': '#000', @@ -1049,7 +1049,7 @@ events .append('text') - .attr({ + .attrs({ 'id': function (d) { return 'event-text-' + d.id; }, @@ -1083,7 +1083,7 @@ }); label.attr('transform', 'translate(10,-14)'); } else { - label.text(d.eventType).attr({ + label.text(d.eventType).attrs({ 'x': 10, 'y': 4 }); @@ -1098,7 +1098,22 @@ return d.id; }); - // add new nodes + // exit + nodes.exit() + .transition() + .delay(200) + .duration(400) + .attr('transform', function (d) { + if (d.incoming.length === 0) { + return 'translate(' + (width / 2) + ',50)'; + } else { + return 'translate(' + d.incoming[0].source.x + ',' + d.incoming[0].source.y + ')'; + } + }) + .style('opacity', 0) + .remove(); + + // enter var nodesEntered = nodes.enter() .append('g') .attr('id', function (d) { @@ -1122,39 +1137,37 @@ return d.type === 'EVENT'; }).call(renderEvent, provenanceTableCtrl); + // merge + nodes = nodes.merge(nodesEntered); + // update the nodes - nodes - .transition() + nodes.transition() .duration(400) .attr('transform', function (d) { return 'translate(' + d.x + ', ' + d.y + ')'; }) .style('opacity', 1); - // remove old nodes - nodes.exit() + // update the link data + links = links.data(linkLookup.values(), function (d) { + return d.id; + }); + + // exit + links.exit() + .attr('marker-end', '') .transition() - .delay(200) .duration(400) - .attr('transform', function (d) { - if (d.incoming.length === 0) { - return 'translate(' + (width / 2) + ',50)'; - } else { - return 'translate(' + d.incoming[0].source.x + ',' + d.incoming[0].source.y + ')'; - } + .attr('d', function (d) { + return 'M' + d.source.x + ',' + d.source.y + 'L' + d.source.x + ',' + d.source.y; }) .style('opacity', 0) .remove(); - // update the link data - links = links.data(linkLookup.values(), function (d) { - return d.id; - }); - // add new links - links.enter() + var linksEntered = links.enter() .insert('path', '.node') - .attr({ + .attrs({ 'class': 'link', 'stroke-width': 1.5, 'stroke': '#000', @@ -1165,13 +1178,15 @@ }) .style('opacity', 0); + // merge + links = links.merge(linksEntered) + .attr('marker-end', ''); + // update the links - links - .attr('marker-end', '') - .transition() + links.transition() .delay(200) .duration(400) - .attr({ + .attrs({ 'marker-end': function (d) { return 'url(#' + d.target.type + ')'; }, @@ -1180,17 +1195,6 @@ } }) .style('opacity', 1); - - // remove old links - links.exit() - .attr('marker-end', '') - .transition() - .duration(400) - .attr('d', function (d) { - return 'M' + d.source.x + ',' + d.source.y + 'L' + d.source.x + ',' + d.source.y; - }) - .style('opacity', 0) - .remove(); }; // show the lineage pane and hide the event search results diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js index 5a426e5a55f2..9094795f91ce 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js @@ -69,7 +69,7 @@ provenance: '../nifi-api/provenance', provenanceEvents: '../nifi-api/provenance-events/', clusterSearch: '../nifi-api/flow/cluster/search-results', - d3Script: 'js/d3/d3.min.js', + d3Script: 'js/d3/build/d3.min.js', lineageScript: 'js/nf/provenance/nf-provenance-lineage.js', uiExtensionToken: '../nifi-api/access/ui-extension-token', downloadToken: '../nifi-api/access/download-token' From 7fc5851709b2ce918aabce6ad9c746b2cac4995a Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Thu, 15 Feb 2018 13:12:41 -0500 Subject: [PATCH 2/3] NIFI-3502: - Ensuring that upon deselection, the monitor palette is updated accordingly. --- .../nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js index 3f7212399b4f..4ef2f2c6c268 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js @@ -1062,6 +1062,9 @@ // update URL deep linking params nfCanvasUtils.setURLParameters(); + + // inform Angular app values have changed + nfNgBridge.digest(); } } From 7de08046d7c05542b9ed1a460e700c21cd4bc6c4 Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Tue, 20 Feb 2018 14:26:46 -0500 Subject: [PATCH 3/3] NIFI-3502: - Preventing digest() during an ongoing apply() or digest() lifecycle. --- .../nf-ng-canvas-navigate-controller.js | 18 +++++++++++++----- .../webapp/js/nf/canvas/nf-canvas-bootstrap.js | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js index 4eb27a50697b..6f1430f3b9d2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js @@ -35,7 +35,7 @@ }(this, function (nfCanvasUtils, nfContextMenu) { 'use strict'; - return function () { + return function ($timeout) { 'use strict'; function NavigateCtrl() { @@ -44,28 +44,36 @@ * Zoom in on the canvas. */ this.zoomIn = function () { - nfCanvasUtils.zoomInCanvas(); + $timeout(function () { + nfCanvasUtils.zoomInCanvas(); + }, 0); }; /** * Zoom out on the canvas. */ this.zoomOut = function () { - nfCanvasUtils.zoomOutCanvas(); + $timeout(function () { + nfCanvasUtils.zoomOutCanvas(); + }, 0); }; /** * Zoom fit on the canvas. */ this.zoomFit = function () { - nfCanvasUtils.fitCanvas(); + $timeout(function () { + nfCanvasUtils.fitCanvas(); + }, 0); }; /** * Zoom actual size on the canvas. */ this.zoomActualSize = function () { - nfCanvasUtils.actualSizeCanvas(); + $timeout(function () { + nfCanvasUtils.actualSizeCanvas(); + }, 0); }; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js index 536f87b6eb2d..4396766953dc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js @@ -259,7 +259,7 @@ templateComponent.$inject = ['serviceProvider']; labelComponent.$inject = ['serviceProvider']; graphControlsCtrl.$inject = ['serviceProvider', 'navigateCtrl', 'operateCtrl']; - navigateCtrl.$inject = []; + navigateCtrl.$inject = ['$timeout']; operateCtrl.$inject = []; breadcrumbsDirective.$inject = ['breadcrumbsCtrl']; draggableDirective.$inject = [];