You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by sc...@apache.org on 2018/02/20 21:28:23 UTC

[1/5] nifi git commit: NIFI-3502: - Ensuring that upon deselection, the monitor palette is updated accordingly.

Repository: nifi
Updated Branches:
  refs/heads/master 91e98aa50 -> ba9e72ed8


NIFI-3502:
- Ensuring that upon deselection, the monitor palette is updated accordingly.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/bf72d058
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/bf72d058
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/bf72d058

Branch: refs/heads/master
Commit: bf72d058254968a06cc7f640f39a35a155fb4abb
Parents: 9cd631f
Author: Matt Gilman <ma...@gmail.com>
Authored: Thu Feb 15 13:12:41 2018 -0500
Committer: Scott Aslan <sc...@gmail.com>
Committed: Tue Feb 20 14:51:44 2018 -0500

----------------------------------------------------------------------
 .../nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js         | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/bf72d058/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
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 3f72123..4ef2f2c 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();
                                 }
                             }
 


[4/5] nifi git commit: NIFI-3502: - Upgrading to D3 version 4.

Posted by sc...@apache.org.
NIFI-3502:
- Upgrading to D3 version 4.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/9cd631f9
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/9cd631f9
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/9cd631f9

Branch: refs/heads/master
Commit: 9cd631f963a0df85ed03ca046780bb762626d848
Parents: 91e98aa
Author: Matt Gilman <ma...@gmail.com>
Authored: Wed Feb 7 08:36:34 2018 -0500
Committer: Scott Aslan <sc...@gmail.com>
Committed: Tue Feb 20 14:51:44 2018 -0500

----------------------------------------------------------------------
 nifi-assembly/LICENSE                           |  31 ++
 .../src/main/resources/META-INF/LICENSE         |  31 ++
 .../nifi-framework/nifi-web/nifi-web-ui/pom.xml |   6 +-
 .../nifi-web-ui/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 +-
 .../src/main/webapp/js/nf/canvas/nf-actions.js  |  11 +-
 .../src/main/webapp/js/nf/canvas/nf-birdseye.js |  41 +-
 .../main/webapp/js/nf/canvas/nf-canvas-utils.js |  57 ++-
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   | 410 ++++++++++---------
 .../main/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 +++--
 .../src/main/webapp/js/nf/canvas/nf-settings.js |   4 +-
 .../webapp/js/nf/canvas/nf-variable-registry.js |   2 +-
 .../src/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(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-assembly/LICENSE
----------------------------------------------------------------------
diff --git a/nifi-assembly/LICENSE b/nifi-assembly/LICENSE
index 0edf519..69a03dc 100644
--- a/nifi-assembly/LICENSE
+++ b/nifi-assembly/LICENSE
@@ -234,6 +234,37 @@ The source is available under an MIT LICENSE.
 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
     All rights reserved.
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework-nar/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
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 78eb4c1..e72b324 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
@@ -263,6 +263,37 @@ 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
     All rights reserved.
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
----------------------------------------------------------------------
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 c88a851..699e55d 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 @@
                                     <filtering>false</filtering>
                                     <includes>
                                         <!-- D3 -->
-                                        <include>d3/d3.min.js*</include>
+                                        <include>d3/build/d3.min.js*</include>
                                         <include>d3/LICENSE</include>
+                                        <!-- D3 selection multi -->
+                                        <include>d3-selection-multi/build/d3-selection-multi.min.js*</include>
+                                        <include>d3-selection-multi/LICENSE</include>
                                         <!-- angular -->
                                         <include>angular/angular.min.js*</include>
                                         <include>angular/LICENSE.md</include>
@@ -895,7 +898,6 @@
                                 <exclude>nbactions.xml</exclude>
                                 <exclude>src/main/frontend/package.json</exclude>
                                 <exclude>src/main/webapp/js/jquery/jquery.base64.js</exclude>
-                                <exclude>src/main/webapp/js/d3/d3.min.js</exclude>
                                 <exclude>src/main/webapp/js/codemirror/</exclude>
                                 <exclude>src/main/webapp/fonts/**/*</exclude>
                             </excludes>

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/frontend/package.json
----------------------------------------------------------------------
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 4e56011..9670209 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.",

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
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 6d29fb0..2aced50 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
@@ -211,6 +211,37 @@ 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
     All rights reserved.
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
----------------------------------------------------------------------
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 52fc43c..0d14cd2 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 @@
         </script>
         <script type="text/javascript" src="assets/url-search-params/build/url-search-params.js"></script>
         <script type="text/javascript" src="js/codemirror/lib/codemirror-compressed.js"></script>
-        <script type="text/javascript" src="assets/d3/d3.min.js"></script>
+        <script type="text/javascript" src="assets/d3/build/d3.min.js"></script>
+        <script type="text/javascript" src="assets/d3-selection-multi/build/d3-selection-multi.min.js"></script>
         <script type="text/javascript" src="assets/jquery/dist/jquery.min.js"></script>
         <script type="text/javascript" src="assets/jquery-ui-dist/jquery-ui.min.js"></script>
         <script type="text/javascript" src="js/jquery/jquery.base64.js"></script>

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/provenance.jsp
----------------------------------------------------------------------
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 b4eb6a0..d4bcccc 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 @@
         <link rel="stylesheet" href="fonts/flowfont/flowfont.css" type="text/css" />
         <link rel="stylesheet" href="assets/angular-material/angular-material.min.css" type="text/css" />
         <link rel="stylesheet" href="assets/font-awesome/css/font-awesome.min.css" type="text/css" />
-        <script type="text/javascript" src="assets/d3/d3.min.js"></script>
+        <script type="text/javascript" src="assets/d3/build/d3.min.js"></script>
+        <script type="text/javascript" src="assets/d3-selection-multi/build/d3-selection-multi.min.js"></script>
         <script type="text/javascript" src="assets/jquery/dist/jquery.min.js"></script>
         <script type="text/javascript" src="js/jquery/jquery.base64.js"></script>
         <script type="text/javascript" src="js/jquery/jquery.center.js"></script>

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/summary.jsp
----------------------------------------------------------------------
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 1746e6b..cc5ae43 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 @@
         <link rel="stylesheet" href="assets/angular-material/angular-material.min.css" type="text/css" />
         <link rel="stylesheet" href="assets/font-awesome/css/font-awesome.min.css" type="text/css" />
         <script type="text/javascript" src="js/codemirror/lib/codemirror-compressed.js"></script>
-        <script type="text/javascript" src="assets/d3/d3.min.js"></script>
         <script type="text/javascript" src="assets/jquery/dist/jquery.min.js"></script>
         <script type="text/javascript" src="assets/jquery-ui-dist/jquery-ui.min.js"></script>
         <script type="text/javascript" src="js/jquery/jquery.base64.js"></script>

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/users.jsp
----------------------------------------------------------------------
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 42d0791..2444baa 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 @@
         <link rel="stylesheet" href="css/slick-nifi-theme.css" type="text/css" />
         <link rel="stylesheet" href="fonts/flowfont/flowfont.css" type="text/css" />
         <link rel="stylesheet" href="assets/font-awesome/css/font-awesome.min.css" type="text/css" />
-        <script type="text/javascript" src="assets/d3/d3.min.js"></script>
         <script type="text/javascript" src="assets/jquery/dist/jquery.min.js"></script>
         <script type="text/javascript" src="assets/jquery-ui-dist/jquery-ui.min.js"></script>
         <script type="text/javascript" src="js/jquery/jquery.base64.js"></script>

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css
----------------------------------------------------------------------
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 4c77066..95fbbbd 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;

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css
----------------------------------------------------------------------
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 17200d7..0c23683 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;

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/status-history.css
----------------------------------------------------------------------
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 e421f61..57a5baa 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;

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/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
----------------------------------------------------------------------
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 46dc70f..4eb27a5 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;

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/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
----------------------------------------------------------------------
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 f6b45f9..911063f 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();

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/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
----------------------------------------------------------------------
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 3af00da..55adc4d 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
----------------------------------------------------------------------
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 64b0eab..2b09d14 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();

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js
----------------------------------------------------------------------
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 4355e05..6cacb7f 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'
                 })

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
----------------------------------------------------------------------
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 162da36..3dce37e 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();
         },
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
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 00dd4a8..3f72123 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js
----------------------------------------------------------------------
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 91d29f6..0418bef 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 + ')'
                                     })


[2/5] nifi git commit: NIFI-3502: - Upgrading to D3 version 4.

Posted by sc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
----------------------------------------------------------------------
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 8b991a3..b30c981 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);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js
----------------------------------------------------------------------
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 a58d8db..ce3755c 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);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
----------------------------------------------------------------------
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 d3289c7..824312a 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, {

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-variable-registry.js
----------------------------------------------------------------------
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 24c00ab..7265b70 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);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-status-history.js
----------------------------------------------------------------------
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 1901600..83cf5f8 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('<div class="ui-resizable-handle ui-resizable-se"></div>').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;
                     },

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js
----------------------------------------------------------------------
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 6295c0b..b67e474 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js
----------------------------------------------------------------------
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 5a426e5..9094795 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'


[3/5] nifi git commit: NIFI-3502: - Upgrading to D3 version 4.

Posted by sc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js
----------------------------------------------------------------------
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 9e974a2..611e143 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);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js
----------------------------------------------------------------------
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 c97c861..d576006 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));

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
----------------------------------------------------------------------
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 30f6530..0a604a9 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, {

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
----------------------------------------------------------------------
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 56ff8f5..5b8307b 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 () {

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js
----------------------------------------------------------------------
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 ed5051f..a186407 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);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js
----------------------------------------------------------------------
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 e7a62bd..16b32a2 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];

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js
----------------------------------------------------------------------
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 b4c6537..c6f9764 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);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js
----------------------------------------------------------------------
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 1799a86..c43cbf7 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);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd631f9/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js
----------------------------------------------------------------------
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 dc7034a..dd147c4 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


[5/5] nifi git commit: NIFI-3502: - Preventing digest() during an ongoing apply() or digest() lifecycle.

Posted by sc...@apache.org.
NIFI-3502:
- Preventing digest() during an ongoing apply() or digest() lifecycle.

This closes #2471

Signed-off-by: Scott Aslan <sc...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/ba9e72ed
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/ba9e72ed
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/ba9e72ed

Branch: refs/heads/master
Commit: ba9e72ed8b0d1cea08ce206b5cbd71bc6cdaab74
Parents: bf72d05
Author: Matt Gilman <ma...@gmail.com>
Authored: Tue Feb 20 14:26:46 2018 -0500
Committer: Scott Aslan <sc...@gmail.com>
Committed: Tue Feb 20 16:25:12 2018 -0500

----------------------------------------------------------------------
 .../nf-ng-canvas-navigate-controller.js           | 18 +++++++++++++-----
 .../webapp/js/nf/canvas/nf-canvas-bootstrap.js    |  2 +-
 2 files changed, 14 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/ba9e72ed/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
----------------------------------------------------------------------
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 4eb27a5..6f1430f 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);
             };
         }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ba9e72ed/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js
----------------------------------------------------------------------
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 536f87b..4396766 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 = [];