You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2018/12/10 16:59:25 UTC

[3/3] qpid-dispatch git commit: DISPATCH-1217 Treat node.fixed as bitmap

DISPATCH-1217 Treat node.fixed as bitmap


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/81e58b46
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/81e58b46
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/81e58b46

Branch: refs/heads/master
Commit: 81e58b4628173d1392d32dcfedce0312065bea41
Parents: e9b7bd5
Author: Ernest Allen <ea...@redhat.com>
Authored: Mon Dec 10 11:58:58 2018 -0500
Committer: Ernest Allen <ea...@redhat.com>
Committed: Mon Dec 10 11:58:58 2018 -0500

----------------------------------------------------------------------
 console/stand-alone/plugin/css/dispatch.css     |   10 -
 .../stand-alone/plugin/html/qdrTopology.html    |  179 ++-
 console/stand-alone/plugin/js/amqp/utilities.js |   39 +-
 .../plugin/js/dlgDetailController.js            |   53 +-
 .../stand-alone/plugin/js/topology/legend.js    |  138 +++
 console/stand-alone/plugin/js/topology/links.js |   54 +-
 console/stand-alone/plugin/js/topology/map.js   |   69 +-
 console/stand-alone/plugin/js/topology/nodes.js |   99 +-
 .../plugin/js/topology/qdrTopology.js           | 1086 ++++++++----------
 .../stand-alone/plugin/js/topology/svgUtils.js  |  249 ++++
 .../stand-alone/plugin/js/topology/topoUtils.js |  242 ++--
 .../stand-alone/plugin/js/topology/traffic.js   |  144 ++-
 console/stand-alone/test/links.js               |   54 +-
 13 files changed, 1359 insertions(+), 1057 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/css/dispatch.css
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/css/dispatch.css b/console/stand-alone/plugin/css/dispatch.css
index f41754b..709ce43 100644
--- a/console/stand-alone/plugin/css/dispatch.css
+++ b/console/stand-alone/plugin/css/dispatch.css
@@ -1143,12 +1143,6 @@ svg {
     /*height: 100%; */
   }
   
-  div#topologyForm .ngViewport, div#topologyForm .gridStyle {
-    height: auto !important;
-    min-height: initial !important;
-    overflow: initial;
-  }
-  
   div#multiple_details, div#link_details {
       height: 300px;
       width: 700px;
@@ -1819,10 +1813,6 @@ span.logo {
     top: 10px;
   }
   
-  #topologyForm > div {
-    width: auto;
-  }
-  
   div.chartContainer {
     width: auto;
     margin-top: 1em;

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/html/qdrTopology.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrTopology.html b/console/stand-alone/plugin/html/qdrTopology.html
index 5ba514b..0057fab 100644
--- a/console/stand-alone/plugin/html/qdrTopology.html
+++ b/console/stand-alone/plugin/html/qdrTopology.html
@@ -18,7 +18,7 @@ under the License.
 -->
 
 <style>
-@media (min-width: 768px) {
+    @media (min-width: 768px) {
   .showLeft {
       display: block;
   }
@@ -27,6 +27,9 @@ under the License.
   .showLeft {
       display: none;
   }
+  #backgroundMap {
+      display: none;
+  }
   div.qdrTopology div.legend-container.page-menu {
       top: 0;
       right: auto;
@@ -35,7 +38,7 @@ under the License.
   }
 }
 
-#popover-div, #fixed-popup {
+#popover-div {
     position: absolute;
     z-index: 200;
     border-radius: 4px;
@@ -53,41 +56,6 @@ under the License.
     font-size: 10px;
   }
 
-#topologyForm {
-  border-right: 1px solid lightgray;
-  border-bottom: 1px solid lightgray;
-  padding: 2px;
-  /* position: absolute; */
-  background-color: #333333;
-  width: 300px;
-}
-
-  #topologyForm .infoGrid span {
-      display: inline-block;
-      width: 50%;
-      height: 28px;
-      padding: 3px 6px 2px 6px;
-      border-right: 1px solid #666666;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-      overflow: hidden;
-  }
-
-  #topologyForm .infoGrid span:last-child {
-      text-align: right;
-      border-right: 0;
-  }
-  #topologyForm .infoGrid div {
-      height: 28px;
-  }
-  #topologyForm .infoGrid div.odd {
-      background-color: #444444;
-  }
-
-  #topologyForm .infoGrid div.listening-on {
-      background-color: #336633;
-  }
-
   .legend-container {
       position: absolute;
       top: 1em;
@@ -135,8 +103,8 @@ under the License.
     margin-bottom: 0;
     padding-bottom: 0;
 }
-  /* the checkboxes for the addresses */
-  #topo_legend ul li input[type=checkbox]:checked + label::before {
+/* the checkboxes for the addresses */
+#topo_legend ul li input[type=checkbox]:checked + label::before {
     content:'\2713';
     font-weight: bold;
     font-size: 16px;
@@ -146,12 +114,12 @@ under the License.
     position: absolute;
     top: -8px;
     left: -1px;
-  }
-  /* The aggregate addresses need a black checkbox on the white background */
-  #topo_legend ul li input[type=checkbox]:checked + label.aggregate::before {
+}
+/* The aggregate addresses need a black checkbox on the white background */
+#topo_legend ul li input[type=checkbox]:checked + label.aggregate::before {
     color: black;
-    /* left: 1px; */
-  }
+/* left: 1px; */
+}
 #topo_legend ul.addresses button.btn-default {
     background-image: none;
     color: white;
@@ -159,8 +127,8 @@ under the License.
 }
 
 #topo_legend li.legend-sublist ul {
-        margin-bottom: 0.5em;
-    }
+    margin-bottom: 0.5em;
+}
 
 #topo_legend li.legend-sublist ul.addresses{
     max-height: 11.6em;   /* show up to 4 addresses */
@@ -171,11 +139,11 @@ li.legend-sublist > ul ul {
     margin-left: 1em;
 }
 
-#popover-div h5, #fixed-popup h5 {
+#popover-div h5 {
     margin-top: 1em;
     margin-bottom: 0;
 }
-#popover-div h5:first-of-type, #fixed-popup h5:first-of-type {
+#popover-div h5:first-of-type {
     margin-top:0;
 }
 
@@ -198,23 +166,23 @@ table.popupTable td {
 }
 
 .graticule {
-  fill: none;
-  stroke: #777;
-  stroke-width: .5px;
-  stroke-opacity: .5;
+    fill: none;
+    stroke: #777;
+    stroke-width: .5px;
+    stroke-opacity: .5;
 }
 
 g.geo path.land {
-  fill: #dcedf7;
-  stroke: #000;
-  stroke-opacity: 1;
-  stroke-width: 1px;
+    fill: #dcedf7;
+    stroke: #000;
+    stroke-opacity: 1;
+    stroke-width: 1px;
 }
 
 .boundary {
-  fill: none;
-  stroke: #333;
-  stroke-width: 5px;
+    fill: none;
+    stroke: #333;
+    stroke-width: 5px;
 }
 
 .panel-group {
@@ -254,40 +222,44 @@ td.more-info {
     <div class="legend-container page-menu navbar-collapse collapse">
         <uib-accordion id="topo_legend" close-others="false">
             <div uib-accordion-group class="panel-default" is-open="legend.status.optionsOpen" heading="Show Traffic">
-              <ul class="options">
-                  <li class="legend-sublist" ng-hide="!legendOptions.showTraffic">
-                    <ul>
-                        <li><label>
-                            <input type='radio' ng-model="legendOptions.trafficType" value="dots" />
-                        Message path by address
-                        </label></li>
-                        <li>
-                            <ul class="addresses" ng-show="legendOptions.trafficType === 'dots'">
+                <ul class="options">
+                    <li class="legend-sublist" ng-hide="!legendOptions.showTraffic">
+                        <ul>
+                            <li><label>
+                                    <input type='radio' ng-model="legendOptions.trafficType" value="dots" />
+                                    Message path by address
+                                </label></li>
+                            <li>
+                                <ul class="addresses" ng-show="legendOptions.trafficType === 'dots'">
                                     <li ng-repeat="(address, color) in addresses" class="legend-line">
-                                        <checkbox style="background-color: {{addressColors[address]}};"
-                                        title="{{address}}" ng-change="addressFilterChanged()"
-                                        ng-model="addresses[address]" ng-mouseenter="enterLegend(address)" ng-mouseleave="leaveLegend()"></checkbox>
-                                        <span class="legend-text" ng-mouseenter="enterLegend(address)" ng-mouseleave="leaveLegend()" ng-click="addressClick(address)" title="{{address}}">{{address | limitTo : 15}}{{address.length>15 ? '…' : ''}}</span>
+                                        <checkbox style="background-color: {{addressColors[address]}};" title="{{address}}"
+                                            ng-change="addressFilterChanged()" ng-model="addresses[address]"
+                                            ng-mouseenter="enterLegend(address)" ng-mouseleave="leaveLegend()"></checkbox>
+                                        <span class="legend-text" ng-mouseenter="enterLegend(address)" ng-mouseleave="leaveLegend()"
+                                            ng-click="addressClick(address)" title="{{address}}">{{address | limitTo :
+                                            15}}{{address.length>15 ? '…' : ''}}</span>
                                     </li>
-                            </ul>
-                        </li>
-                    </ul>
-                    <ul>
-                        <li><label>
-                            <input type='radio' ng-model="legendOptions.trafficType" value="congestion" />
-                        Link utilization
-                        </label></li>
-                        <li>
-                            <ul class="congestion" ng-show="legendOptions.trafficType === 'congestion'">
+                                </ul>
+                            </li>
+                        </ul>
+                        <ul>
+                            <li><label>
+                                    <input type='radio' ng-model="legendOptions.trafficType" value="congestion" />
+                                    Link utilization
+                                </label></li>
+                            <li>
+                                <ul class="congestion" ng-show="legendOptions.trafficType === 'congestion'">
                                     <li>
-                                        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" preserveAspectRatio="xMidYMid meet" width="140" height="40">
+                                        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+                                            version="1.1" preserveAspectRatio="xMidYMid meet" width="140" height="40">
                                             <defs>
-                                                <linearGradient xmlns="http://www.w3.org/2000/svg" id="gradienta1bEihLEHL" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="100%" y2="0%">
-                                                    <stop style="stop-color: #000000;stop-opacity: 1" offset="0"/>
-                                                    <stop style="stop-color: #000000;stop-opacity: 1" offset="0.06"/>
-                                                    <stop style="stop-color: #00FF00;stop-opacity: 1" offset="0.333"/>
-                                                    <stop style="stop-color: #FFA500;stop-opacity: 1" offset="0.666"/>
-                                                    <stop style="stop-color: #FF0000;stop-opacity: 1" offset="1"/></linearGradient>
+                                                <linearGradient xmlns="http://www.w3.org/2000/svg" id="gradienta1bEihLEHL"
+                                                    gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="100%" y2="0%">
+                                                    <stop style="stop-color: #999999;stop-opacity: 1" offset="0" />
+                                                    <stop style="stop-color: #00FF00;stop-opacity: 1" offset="0.333" />
+                                                    <stop style="stop-color: #FFA500;stop-opacity: 1" offset="0.666" />
+                                                    <stop style="stop-color: #FF0000;stop-opacity: 1" offset="1" />
+                                                </linearGradient>
                                             </defs>
                                             <g>
                                                 <rect width="140" height="20" x="0" y="0" fill="url(#gradienta1bEihLEHL)"></rect>
@@ -295,34 +267,39 @@ td.more-info {
                                                 <text x="106" y="30" class="label">Busy</text>
                                             </g>
                                         </svg></li>
-                            </ul>
-                        </li>
-                    </ul>
-                </li>
-              </ul>
+                                </ul>
+                            </li>
+                        </ul>
+                    </li>
+                </ul>
             </div>
             <div uib-accordion-group class="panel-default" is-open="legend.status.legendOpen" heading="Legend">
                 <div id="topo_svg_legend"></div>
             </div>
-            <div uib-accordion-group class="panel-default" is-open="legend.status.mapOpen" heading="Background map">
+            <div id="backgroundMap" uib-accordion-group class="panel-default" is-open="legend.status.mapOpen" heading="Background map">
                 <div id="topo_mapOptions">
                     <div class="colorPicker">
                         <ul>
                             <li>
-                                <label><span class='map-label'>Land</span> <input id="areaColor" name="areaColor" type="color" ng-model="mapOptions.areaColor"/></label>
+                                <label><span class='map-label'>Land</span> <input id="areaColor" name="areaColor" type="color"
+                                        ng-model="mapOptions.areaColor" /></label>
                             </li>
                             <li>
-                                <label><span class='map-label'>Ocean</span> <input id="oceanColor" name="oceanColor" type="color" ng-model="mapOptions.oceanColor"/></label>
+                                <label><span class='map-label'>Ocean</span> <input id="oceanColor" name="oceanColor"
+                                        type="color" ng-model="mapOptions.oceanColor" /></label>
                             </li>
                         </ul>
                     </div>
                 </div>
             </div>
-          </uib-accordion>
+        </uib-accordion>
     </div>
     <div class="diagram">
-        <div id="topology"><!-- d3 toplogy here --></div>
-        <div id="crosssection"></div><div id="crosshtml" ng-bind-html="crosshtml"></div>
+        <div id="topology">
+            <!-- d3 toplogy here -->
+        </div>
+        <div id="crosssection"></div>
+        <div id="crosshtml" ng-bind-html="crosshtml"></div>
 
         <div id="node_context_menu" class="contextMenu">
             <ul>
@@ -344,4 +321,4 @@ td.more-info {
 </script>
 <script type="text/ng-template" id="titleCellTemplate.html">
     <div title="{{row.entity.attributeValue}}" class="ui-grid-cell-contents">{{COL_FIELD CUSTOM_FILTERS | pretty}}</div>
-</script>
+</script>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/js/amqp/utilities.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/amqp/utilities.js b/console/stand-alone/plugin/js/amqp/utilities.js
index 517b4e1..34f1d7d 100644
--- a/console/stand-alone/plugin/js/amqp/utilities.js
+++ b/console/stand-alone/plugin/js/amqp/utilities.js
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Red Hat Inc.
+ * Copyright 2018 Red Hat Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
  */
 
 /* global d3 */
-var ddd = typeof window === 'undefined' ? require ('d3') : d3;
+var ddd = typeof window === 'undefined' ? require('d3') : d3;
 
 var utils = {
   isAConsole: function (properties, connectionId, nodeType, key) {
@@ -40,7 +40,7 @@ var utils = {
     if (!attributes || !result)
       return {};
     var flat = {};
-    attributes.forEach(function(attr, i) {
+    attributes.forEach(function (attr, i) {
       if (result && result.length > i)
         flat[attr] = result[i];
     });
@@ -48,9 +48,11 @@ var utils = {
   },
   flattenAll: function (entity, filter) {
     if (!filter)
-      filter = function (e) {return e;};
+      filter = function (e) {
+        return e;
+      };
     let results = [];
-    for (let i=0; i<entity.results.length; i++) {
+    for (let i = 0; i < entity.results.length; i++) {
       let f = filter(this.flatten(entity.attributeNames, entity.results[i]));
       if (f)
         results.push(f);
@@ -72,7 +74,7 @@ var utils = {
   addr_text: function (addr) {
     if (!addr)
       return '-';
-    if (addr[0] === addr[0].toLowerCase()) 
+    if (addr[0] === addr[0].toLowerCase())
       return addr;
     if (addr[0] == 'M')
       return addr.substring(2);
@@ -122,7 +124,7 @@ var utils = {
   countsFor: function (aAr, vAr, key) {
     let counts = {};
     let idx = aAr.indexOf(key);
-    for (let i=0; i<vAr.length; i++) {
+    for (let i = 0; i < vAr.length; i++) {
       if (!counts[vAr[i][idx]])
         counts[vAr[i][idx]] = 0;
       counts[vAr[i][idx]]++;
@@ -139,7 +141,7 @@ var utils = {
 
     var parts = id.split('/');
     // remove $management
-    parts.pop(); 
+    parts.pop();
 
     // remove the area if present
     if (parts[2] === '0')
@@ -171,18 +173,21 @@ var utils = {
       list.shift();
     }
     let rates = {};
-    list.push({date: new Date(), val: Object.assign({}, obj)});
+    list.push({
+      date: new Date(),
+      val: Object.assign({}, obj)
+    });
 
-    for (let i=0; i<fields.length; i++) {
+    for (let i = 0; i < fields.length; i++) {
       let cumulative = 0;
       let field = fields[i];
-      for (let j=0; j<list.length-1; j++) {
-        let elapsed = list[j+1].date - list[j].date;
-        let diff = list[j+1].val[field] - list[j].val[field];
+      for (let j = 0; j < list.length - 1; j++) {
+        let elapsed = list[j + 1].date - list[j].date;
+        let diff = list[j + 1].val[field] - list[j].val[field];
         if (elapsed > 100)
-          cumulative += diff/(elapsed / 1000);
+          cumulative += diff / (elapsed / 1000);
       }
-      rates[field] = list.length > 1 ? cumulative / (list.length-1) : 0;
+      rates[field] = list.length > 1 ? cumulative / (list.length - 1) : 0;
     }
     return rates;
   },
@@ -216,4 +221,6 @@ var utils = {
   }
 
 };
-export { utils };
\ No newline at end of file
+export {
+  utils
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/js/dlgDetailController.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/dlgDetailController.js b/console/stand-alone/plugin/js/dlgDetailController.js
index 1c9b45a..dba5d3b 100644
--- a/console/stand-alone/plugin/js/dlgDetailController.js
+++ b/console/stand-alone/plugin/js/dlgDetailController.js
@@ -33,7 +33,7 @@ export class DetailDialogController {
     // count the number of characters in an array of strings
     let countChars = function (ar) {
       let count = 0;
-      ar.forEach( a => count += a.length);
+      ar.forEach(a => count += a.length);
       return count;
     };
 
@@ -110,7 +110,7 @@ export class DetailDialogController {
     };
     // keep an array of column sizes
     let updateSizes = function (fields, sizes, obj) {
-      fields.forEach( function (key) {
+      fields.forEach(function (key) {
         if (!sizes[key])
           sizes[key] = utils.humanify(key).length;
         sizes[key] = Math.max(sizes[key], utils.pretty(obj[key]).length);
@@ -128,8 +128,8 @@ export class DetailDialogController {
       // queued function to get the .router info for an edge router
       let q_getEdgeInfo = function (n, infoPerId, callback) {
         let nodeId = utils.idFromName(n.container, '_edge');
-        QDRService.management.topology.fetchEntities(nodeId, 
-          [{entity: 'router', attrs: []},
+        QDRService.management.topology.fetchEntities(nodeId,
+          [{ entity: 'router', attrs: [] },
           ],
           function (results) {
             let r = results[nodeId].router;
@@ -142,21 +142,22 @@ export class DetailDialogController {
             callback(null);
           });
       };
-      return new Promise( (function (resolve) {
+      return new Promise((function (resolve) {
         let infoPerId = {};
         // we are getting info for an edge router
         if (d.nodeType === 'edge') {
           // called for each expanded row to get further details about the edge router
           $scope.detail.moreInfo = function (id) {
             let nodeId = utils.idFromName(id, '_edge');
-            QDRService.management.topology.fetchEntities(nodeId, 
-              [{entity: 'router.link', attrs: []},
-                {entity: 'linkRoute', attrs: $scope.fields.linkRouteFields.cols},
-                {entity: 'autoLink', attrs: $scope.fields.autoLinkFields.cols},
-                {entity: 'address', attrs: []},
+            QDRService.management.topology.fetchEntities(nodeId,
+              [
+                { entity: 'router.link', attrs: [] },
+                { entity: 'linkRoute', attrs: $scope.fields.linkRouteFields.cols },
+                { entity: 'autoLink', attrs: $scope.fields.autoLinkFields.cols },
+                { entity: 'address', attrs: [] },
               ],
               function (results) {
-                $timeout( function () {
+                $timeout(function () {
                   // save the results (and sizes) for each entity requested
                   infoPerId[id].linkRouteSizes = {};
                   infoPerId[id].linkRoutes = utils.flattenAll(results[nodeId].linkRoute,
@@ -165,13 +166,13 @@ export class DetailDialogController {
                       return route;
                     });
                   infoPerId[id].autoLinkSizes = {};
-                  infoPerId[id].autoLinks = utils.flattenAll(results[nodeId].autoLink, 
+                  infoPerId[id].autoLinks = utils.flattenAll(results[nodeId].autoLink,
                     function (link) {
                       updateSizes($scope.fields.autoLinkFields.cols, infoPerId[id].autoLinkSizes, link);
                       return link;
                     });
                   infoPerId[id].addressSizes = {};
-                  infoPerId[id].addresses = utils.flattenAll(results[nodeId].address, 
+                  infoPerId[id].addresses = utils.flattenAll(results[nodeId].address,
                     function (addr) {
                       updateSizes($scope.fields.addressFields.cols, infoPerId[id].addressSizes, addr);
                       return addr;
@@ -182,7 +183,7 @@ export class DetailDialogController {
 
           // async send up to 10 requests
           let q = d3.queue(10);
-          for (let n=0; n<d.normals.length; n++) {
+          for (let n = 0; n < d.normals.length; n++) {
             q.defer(q_getEdgeInfo, d.normals[n], infoPerId);
             if (expandedRows.has(d.normals[n].container)) {
               $scope.detail.moreInfo(d.normals[n].container);
@@ -200,14 +201,14 @@ export class DetailDialogController {
           });
         } else {
           // we are getting info for a group of clients or consoles
-          $scope.detail.moreInfo = function () {};
+          $scope.detail.moreInfo = function () { };
           let attrs = utils.copy($scope.fields.linkFields.cols);
           attrs.unshift('connectionId');
-          QDRService.management.topology.fetchEntities(d.key, 
-            [{entity: 'router.link', attrs: attrs}],
+          QDRService.management.topology.fetchEntities(d.key,
+            [{ entity: 'router.link', attrs: attrs }],
             function (results) {
               let links = results[d.key]['router.link'];
-              for (let i=0; i<d.normals.length; i++) {
+              for (let i = 0; i < d.normals.length; i++) {
                 let n = d.normals[i];
                 let conn = {};
                 infoPerId[n.container] = conn;
@@ -231,7 +232,7 @@ export class DetailDialogController {
               let count = d.normals.length;
               let verb = count > 1 ? 'are' : 'is';
               let preposition = d.cdir === 'in' ? 'to' : d.cdir === 'both' ? 'for' : 'from';
-              let plural = count > 1 ? 's': '';
+              let plural = count > 1 ? 's' : '';
               $scope.detail.template = 'clients.html';
               $scope.detail.title = 'for client';
               resolve({
@@ -242,16 +243,16 @@ export class DetailDialogController {
         }
       }));
     };
-  
+
     let updateDetail = function () {
       groupDetail.call(this)
-        .then( function (det) {
-          $timeout( function () {
+        .then(function (det) {
+          $timeout(function () {
             $scope.detail.title = `for ${d.normals.length} ${$scope.detail.title}${d.normals.length > 1 ? 's' : ''}`;
             $scope.detail.description = det.description;
-            $scope.detail.infoPerId = Object.keys(det.infoPerId).map( function (id) {
+            $scope.detail.infoPerId = Object.keys(det.infoPerId).map(function (id) {
               return det.infoPerId[id];
-            }).sort( function (a, b) {
+            }).sort(function (a, b) {
               return a.name > b.name ? 1 : -1;
             });
           });
@@ -266,7 +267,7 @@ DetailDialogController.$inject = ['QDRService', '$scope', '$timeout', '$uibModal
 
 // SubTable directive
 export class SubTable {
-  constructor () {
+  constructor() {
     this.restrict = 'E';
     this.scope = {
       sizes: '=sizes',
@@ -275,7 +276,7 @@ export class SubTable {
     };
     this.templateUrl = 'sub-table.html';
   }
-  link (scope) {
+  link(scope) {
     scope.fieldWidth = function (val, sizes) {
       if (!sizes)
         return '10%';

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/js/topology/legend.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/legend.js b/console/stand-alone/plugin/js/topology/legend.js
new file mode 100644
index 0000000..b3908c5
--- /dev/null
+++ b/console/stand-alone/plugin/js/topology/legend.js
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* global d3 */
+
+import { Nodes } from "./nodes.js";
+import { appendCircle, appendContent, appendTitle } from "./svgUtils.js";
+// for testing, window will be undefined
+var ddd = typeof window === 'undefined' ? require('d3') : d3;
+
+const lookFor = [
+  { role: "inter-router", title: "Router", text: "", cls: '' },
+  { role: "edge", title: "Router", text: "Edge", cls: 'edge' },
+  { role: "normal", title: "Console", text: "console", cls: 'console', props: { console_identifier: "Dispatch console" } },
+  { role: "normal", title: "Sender", text: "Sender", cls: 'client.in', cdir: "in" },
+  { role: "normal", title: "Receiver", text: "Receiver", cls: 'client.out', cdir: "out" },
+  { role: "normal", title: "Sender/Receiver", text: "Sender/Receiver", cls: 'client.inout', cdir: "both" },
+  { role: "route-container", title: "Qpid broker", text: "Qpid broker", cls: 'client.route-container', props: { product: "qpid-cpp" } },
+  { role: "route-container", title: "Artemis broker", text: "Artemis broker", cls: 'route-container', props: { product: "apache-activemp-artemis" } },
+  { role: "route-container", title: "Service", text: "Service", cls: 'route-container', props: { product: " External Service" } }
+];
+
+export class Legend {
+  constructor(svg, QDRLog, urlPrefix) {
+    this.svg = svg;
+    this.log = QDRLog;
+    this.urlPrefix = urlPrefix;
+  }
+
+  // create a new legend container svg
+  init() {
+    return ddd
+      .select("#topo_svg_legend")
+      .append("svg")
+      .attr("id", "svglegend")
+      .append("svg:g")
+      .attr(
+        "transform",
+        `translate(${Nodes.maxRadius()}, ${Nodes.maxRadius()})`
+      )
+      .selectAll("g");
+  }
+
+  // create or update the legend
+  update() {
+    let lsvg;
+    if (ddd.select("#topo_svg_legend svg").empty()) {
+      lsvg = this.init();
+    } else {
+      lsvg = ddd.select("#topo_svg_legend svg g").selectAll("g");
+    }
+    // add a node to legendNodes for each node type that is currently in the svg
+    let legendNodes = new Nodes(this.log);
+    lookFor.forEach(function (node, i) {
+      if (!node.cls || !this.svg.selectAll(`circle.${node.cls}`).empty()) {
+        let lnode = legendNodes.addUsing(
+          node.title,
+          node.text,
+          node.role,
+          undefined,
+          0, 0, i, 0,
+          false,
+          node.props ? node.props : {}
+        );
+        if (node.cdir)
+          lnode.cdir = node.cdir;
+      }
+    }, this);
+
+    // determine the y coordinate of the last existing node in the legend 
+    let cury = 0;
+    lsvg.each(function (d) {
+      cury += Nodes.radius(d.nodeType) * 2 + 10;
+    });
+
+    // associate the legendNodes with lsvg
+    lsvg = lsvg.data(legendNodes.nodes, function (d) {
+      return d.uid();
+    });
+
+    // add any new nodes
+    let legendEnter = lsvg
+      .enter()
+      .append("svg:g")
+      .attr("transform", function (d) {
+        let t = `translate(0, ${cury})`;
+        cury += Nodes.radius(d.nodeType) * 2 + 10;
+        return t;
+      });
+    appendCircle(legendEnter, this.urlPrefix);
+    appendContent(legendEnter);
+    appendTitle(legendEnter);
+    legendEnter.append("svg:text")
+      .attr("x", 35)
+      .attr("y", 6)
+      .attr("class", "label")
+      .text(function (d) {
+        return d.key;
+      });
+
+    // remove any nodes that dropped out of legendNodes
+    lsvg.exit().remove();
+
+    // position the legend based on it's size
+    let svgEl = document.getElementById("svglegend");
+    if (svgEl) {
+      let bb;
+      // firefox can throw an exception on getBBox on an svg element
+      try {
+        bb = svgEl.getBBox();
+      } catch (e) {
+        bb = {
+          y: 0,
+          height: 200,
+          x: 0,
+          width: 200
+        };
+      }
+      svgEl.style.height = bb.y + bb.height + "px";
+      svgEl.style.width = bb.x + bb.width + "px";
+    }
+  }
+}
+
+

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/js/topology/links.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/links.js b/console/stand-alone/plugin/js/topology/links.js
index 16b086c..1260415 100644
--- a/console/stand-alone/plugin/js/topology/links.js
+++ b/console/stand-alone/plugin/js/topology/links.js
@@ -17,7 +17,9 @@ specific language governing permissions and limitations
 under the License.
 */
 
-import { utils } from "../amqp/utilities.js";
+import {
+  utils
+} from "../amqp/utilities.js";
 
 class Link {
   constructor(source, target, dir, cls, uid) {
@@ -29,15 +31,13 @@ class Link {
     this.uid = uid;
   }
   markerId(end) {
-    let selhigh = this.highlighted
-      ? "highlighted"
-      : this.selected
-        ? "selected"
-        : "";
+    let selhigh = this.highlighted ?
+      "highlighted" :
+      (this.selected ?
+        "selected" :
+        "");
     if (selhigh === "" && (!this.left && !this.right)) selhigh = "unknown";
-    return `-${selhigh}-${
-      end === "end" ? this.target.radius() : this.source.radius()
-    }`;
+    return `-${selhigh}-${end === "end" ? this.target.radius() : this.source.radius()}`;
   }
 }
 
@@ -46,6 +46,9 @@ export class Links {
     this.links = [];
     this.logger = logger;
   }
+  reset() {
+    this.links.length = 0;
+  }
   getLinkSource(nodesIndex) {
     for (let i = 0; i < this.links.length; ++i) {
       if (this.links[i].target === nodesIndex) return i;
@@ -70,7 +73,7 @@ export class Links {
     }
     //this.logger.debug("creating new link (" + (links.length) + ") between " + nodes[_source].name + " and " + nodes[_target].name);
     if (
-      this.links.some(function(l) {
+      this.links.some(function (l) {
         return l.uid === uid;
       })
     )
@@ -88,10 +91,8 @@ export class Links {
     return null;
   }
 
-  getPosition(name, nodes, source, client, localStorage, height) {
-    let position = localStorage[name]
-      ? JSON.parse(localStorage[name])
-      : undefined;
+  getPosition(name, nodes, source, client, height, localStorage) {
+    let position = localStorage[name] ? JSON.parse(localStorage[name]) : undefined;
     if (typeof position == "undefined") {
       position = {
         x: Math.round(
@@ -109,10 +110,12 @@ export class Links {
         nodes.get(source).y + 40 + Math.cos(client / (Math.PI * 2.0))
       );
     }
+    position.fixed = position.fixed ? true : false;
     return position;
   }
 
-  initialize(nodeInfo, nodes, unknowns, localStorage, height) {
+  initialize(nodeInfo, nodes, unknowns, height, localStorage) {
+    this.reset();
     let connectionsPerContainer = {};
     let nodeIds = Object.keys(nodeInfo);
     // collect connection info for each router
@@ -158,7 +161,10 @@ export class Links {
     // create map of type:id:dir to [containers]
     for (let container in connectionsPerContainer) {
       let key = getKey(connectionsPerContainer[container]);
-      if (!unique[key]) unique[key] = { c: [], nodes: [] };
+      if (!unique[key]) unique[key] = {
+        c: [],
+        nodes: []
+      };
       unique[key].c.push(container);
     }
     for (let key in unique) {
@@ -176,8 +182,8 @@ export class Links {
           nodes,
           container.source,
           container.resultsIndex,
-          localStorage,
-          height
+          height,
+          localStorage
         );
 
         let node = nodes.getOrCreateNode(
@@ -242,7 +248,7 @@ export class Links {
   }
 }
 
-var getContainerIndex = function(_id, nodeInfo) {
+var getContainerIndex = function (_id, nodeInfo) {
   let nodeIndex = 0;
   for (let id in nodeInfo) {
     if (utils.nameFromId(id) === _id) return nodeIndex;
@@ -251,7 +257,7 @@ var getContainerIndex = function(_id, nodeInfo) {
   return -1;
 };
 
-var getLinkDir = function(connection, onode) {
+var getLinkDir = function (connection, onode) {
   let links = onode["router.link"];
   if (!links) {
     return "unknown";
@@ -261,12 +267,12 @@ var getLinkDir = function(connection, onode) {
   let typeIndex = links.attributeNames.indexOf("linkType");
   let connectionIdIndex = links.attributeNames.indexOf("connectionId");
   let dirIndex = links.attributeNames.indexOf("linkDir");
-  links.results.forEach(function(linkResult) {
+  links.results.forEach(function (linkResult) {
     if (
       linkResult[typeIndex] === "endpoint" &&
       linkResult[connectionIdIndex] === connection.identity
     )
-      if (linkResult[dirIndex] === "in") ++inCount;
+      if (linkResult[dirIndex] === "in")++inCount;
       else ++outCount;
   });
   if (inCount > 0 && outCount > 0) return "both";
@@ -274,7 +280,7 @@ var getLinkDir = function(connection, onode) {
   if (outCount > 0) return "out";
   return "unknown";
 };
-var getKey = function(containers) {
+var getKey = function (containers) {
   let parts = [];
   let connection = containers[0].connection;
   let d = {
@@ -291,4 +297,4 @@ var getKey = function(containers) {
     parts.push(`${container.source}-${container.linksDir}`);
   }
   return `${connectionType}:${parts.join(":")}`;
-};
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/js/topology/map.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/map.js b/console/stand-alone/plugin/js/topology/map.js
index 972d894..c03cfa5 100644
--- a/console/stand-alone/plugin/js/topology/map.js
+++ b/console/stand-alone/plugin/js/topology/map.js
@@ -30,8 +30,14 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
     this.$scope = $scope;
     this.initialized = false;
     this.notify = notifyFn;
-    $scope.mapOptions = angular.fromJson(localStorage[MAPOPTIONSKEY]) || {areaColor: defaultLandColor, oceanColor: defaultOceanColor};
-    this.last = {translate: [0,0], scale: null};
+    $scope.mapOptions = angular.fromJson(localStorage[MAPOPTIONSKEY]) || {
+      areaColor: defaultLandColor,
+      oceanColor: defaultOceanColor
+    };
+    this.last = {
+      translate: [0, 0],
+      scale: null
+    };
   }
   updateLandColor(color) {
     localStorage[MAPOPTIONSKEY] = JSON.stringify(this.$scope.mapOptions);
@@ -55,7 +61,7 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
   }
 
   init($scope, svg, width, height) {
-    return new Promise( (function (resolve, reject) {
+    return new Promise((function (resolve, reject) {
 
       if (this.initialized) {
         resolve();
@@ -82,9 +88,9 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
 
       // setup the projection with some defaults
       this.projection = d3.geo.mercator()
-        .rotate([this.rotate,0])
+        .rotate([this.rotate, 0])
         .scale(1)
-        .translate([width/2, height/2]);
+        .translate([width / 2, height / 2]);
 
       // this path will hold the land coordinates once they are loaded
       this.geoPath = d3.geo.path()
@@ -92,22 +98,26 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
 
       // set up the scale extent and initial scale for the projection
       var b = getMapBounds(this.projection, Math.max(maxnorth, maxsouth)),
-        s = width/(b[1][0]-b[0][0]);
-      this.scaleExtent = [s, 15*s];
+        s = width / (b[1][0] - b[0][0]);
+      this.scaleExtent = [s, 15 * s];
 
       this.projection
         .scale(this.scaleExtent[0]);
-      this.lastProjection = angular.fromJson(localStorage[MAPPOSITIONKEY]) || {rotate: 20, scale: this.scaleExtent[0], translate: [width/2, height/2]};
+      this.lastProjection = angular.fromJson(localStorage[MAPPOSITIONKEY]) || {
+        rotate: 20,
+        scale: this.scaleExtent[0],
+        translate: [width / 2, height / 2]
+      };
 
       this.zoom = d3.behavior.zoom()
         .scaleExtent(this.scaleExtent)
         .scale(this.projection.scale())
-        .translate([0,0])               // not linked directly to projection
+        .translate([0, 0]) // not linked directly to projection
         .on('zoom', this.zoomed.bind(this));
 
       this.geo = svg.append('g')
         .attr('class', 'geo')
-        .style('opacity', this.$scope.legend.status.mapOpen ? '1': '0');
+        .style('opacity', this.$scope.legend.status.mapOpen ? '1' : '0');
 
       this.geo.append('rect')
         .attr('class', 'ocean')
@@ -115,13 +125,14 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
         .attr('height', height)
         .attr('fill', '#FFF');
 
-      if (this.$scope.legend.status.mapOpen)
+      if (this.$scope.legend.status.mapOpen) {
         this.svg.call(this.zoom)
           .on('dblclick.zoom', null);
+      }
 
       // async load of data file. calls resolve when this completes to let caller know
-      d3.json('plugin/data/countries.json', function(error, world) {
-        if (error) 
+      d3.json('plugin/data/countries.json', function (error, world) {
+        if (error)
           reject(error);
 
         this.geo.append('path')
@@ -148,6 +159,8 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
 
   setMapOpacity(opacity) {
     opacity = opacity ? 1 : 0;
+    if (this.width && this.width < 768)
+      opacity = 0;
     if (this.geo)
       this.geo.style('opacity', opacity);
   }
@@ -180,11 +193,11 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
   }
 
   zoomed() {
-    if (d3.event && !this.$scope.current_node && !this.$scope.mousedown_node && this.$scope.legend.status.mapOpen) { 
+    if (d3.event && !this.$scope.current_node && !this.$scope.mousedown_node && this.$scope.legend.status.mapOpen) {
       let scale = d3.event.scale,
         t = d3.event.translate,
-        dx = t[0]-this.last.translate[0],
-        dy = t[1]-this.last.translate[1],
+        dx = t[0] - this.last.translate[0],
+        dy = t[1] - this.last.translate[1],
         yaw = this.projection.rotate()[0],
         tp = this.projection.translate();
       // zoomed
@@ -209,21 +222,21 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
         dy = my - this.projection([0, lonlat[1]])[1];
 
         // rotate the map so that the longitude under the mouse is where it was before the scale
-        this.projection.rotate([yaw+dx ,0, 0]);
+        this.projection.rotate([yaw + dx, 0, 0]);
 
         // translate the map so that the lattitude under the mouse is where it was before the scale
-        this.projection.translate([tp[0], tp[1]+dy]);
+        this.projection.translate([tp[0], tp[1] + dy]);
       } else {
         // rotate instead of translate in the x direction
-        this.projection.rotate([yaw+360.0*dx/this.width*this.scaleExtent[0]/scale, 0, 0]);
+        this.projection.rotate([yaw + 360.0 * dx / this.width * this.scaleExtent[0] / scale, 0, 0]);
         // translate only in the y direction. don't translate beyond the max lattitude north or south
         var bnorth = getMapBounds(this.projection, maxnorth),
           bsouth = getMapBounds(this.projection, maxsouth);
-        if (bnorth[0][1] + dy > 0) 
+        if (bnorth[0][1] + dy > 0)
           dy = -bnorth[0][1];
-        else if (bsouth[1][1] + dy < this.height) 
-          dy = this.height-bsouth[1][1];
-        this.projection.translate([tp[0],tp[1]+dy]);
+        else if (bsouth[1][1] + dy < this.height)
+          dy = this.height - bsouth[1][1];
+        this.projection.translate([tp[0], tp[1] + dy]);
       }
       this.last.scale = scale;
       this.last.translate = t;
@@ -247,8 +260,8 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
 // find the top left and bottom right of current projection
 function getMapBounds(projection, maxlat) {
   var yaw = projection.rotate()[0],
-    xymax = projection([-yaw+180-1e-6,-maxlat]),
-    xymin = projection([-yaw-180+1e-6, maxlat]);
-  
-  return [xymin,xymax];
-}
+    xymax = projection([-yaw + 180 - 1e-6, -maxlat]),
+    xymin = projection([-yaw - 180 + 1e-6, maxlat]);
+
+  return [xymin, xymax];
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/81e58b46/console/stand-alone/plugin/js/topology/nodes.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/nodes.js b/console/stand-alone/plugin/js/topology/nodes.js
index 50c9a37..26ac9bc 100644
--- a/console/stand-alone/plugin/js/topology/nodes.js
+++ b/console/stand-alone/plugin/js/topology/nodes.js
@@ -17,7 +17,9 @@ specific language governing permissions and limitations
 under the License.
 */
 
-import { utils } from "../amqp/utilities.js";
+import {
+  utils
+} from "../amqp/utilities.js";
 
 /* global d3 Promise */
 export class Node {
@@ -43,7 +45,7 @@ export class Node {
     this.y = y;
     this.id = nodeIndex;
     this.resultIndex = resultIndex;
-    this.fixed = !!+fixed;
+    this.fixed = fixed ? true : false;
     this.cls = "";
     this.container = connectionContainer;
     this.isConsole = utils.isConsole(this);
@@ -71,11 +73,11 @@ export class Node {
   }
   toolTip(topology) {
     return new Promise(
-      function(resolve) {
+      function (resolve) {
         if (this.nodeType === "normal" || this.nodeType === "edge") {
           resolve(this.clientTooltip());
         } else
-          this.routerTooltip(topology).then(function(toolTip) {
+          this.routerTooltip(topology).then(function (toolTip) {
             resolve(toolTip);
           });
       }.bind(this)
@@ -99,19 +101,23 @@ export class Node {
 
   routerTooltip(topology) {
     return new Promise(
-      function(resolve) {
+      function (resolve) {
         topology.ensureEntities(
           this.key,
-          [
-            { entity: "listener", attrs: ["role", "port", "http"] },
-            { entity: "router", attrs: ["name", "version", "hostName"] }
+          [{
+            entity: "listener",
+            attrs: ["role", "port", "http"]
+          },
+          {
+            entity: "router",
+            attrs: ["name", "version", "hostName"]
+          }
           ],
-          function(foo, nodes) {
+          function (foo, nodes) {
             // update all the router title text
             let node = nodes[this.key];
             const err = `<table class="popupTable"><tr><td>Error</td><td>Unable to get router info for ${
-              this.key
-            }</td></tr></table>`;
+              this.key}</td></tr></table>`;
             if (!node) {
               resolve(err);
               return;
@@ -154,32 +160,43 @@ export class Node {
     return nodeProperties[this.nodeType].radius;
   }
   uid() {
-    if (!this.uuid) this.uuid = this.container;
+    if (!this.uuid)
+      this.uuid = `${this.container}`;
     return this.normals ? `${this.uuid}-${this.normals.length}` : this.uuid;
   }
   setFixed(fixed) {
-    if (!fixed) this.lat = this.lon = null;
-    this.fixed = fixed;
+    if (!fixed & 1)
+      this.lat = this.lon = null;
+    this.fixed = fixed & 1 ? true : false;
   }
 }
 const nodeProperties = {
   // router types
   "inter-router": {
     radius: 28,
-    refX: { end: 32, start: -19 },
+    refX: {
+      end: 32,
+      start: -19
+    },
     linkDistance: [150, 70],
     charge: [-1800, -900]
   },
   edge: {
     radius: 20,
-    refX: { end: 24, start: -12 },
+    refX: {
+      end: 24,
+      start: -12
+    },
     linkDistance: [110, 55],
     charge: [-1350, -900]
   },
   // generated nodes from connections. key is from connection.role
   normal: {
     radius: 15,
-    refX: { end: 20, start: -7 },
+    refX: {
+      end: 20,
+      start: -7
+    },
     linkDistance: [75, 40],
     charge: [-900, -900]
   }
@@ -240,7 +257,13 @@ export class Nodes {
   gravity(d, nodeCount) {
     return Nodes.forceScale(nodeCount, [0.0001, 0.1]);
   }
-
+  setFixed(d, fixed) {
+    let n = this.find(d.container, d.properties, d.name);
+    if (n) {
+      n.fixed = fixed;
+    }
+    d.setFixed(fixed);
+  }
   getLength() {
     return this.nodes.length;
   }
@@ -253,14 +276,6 @@ export class Nodes {
     );
     return undefined;
   }
-  setNodesFixed(name, b) {
-    this.nodes.some(function(n) {
-      if (n.name === name) {
-        n.fixed(b);
-        return true;
-      }
-    });
-  }
   nodeFor(name) {
     for (let i = 0; i < this.nodes.length; ++i) {
       if (this.nodes[i].name == name) return this.nodes[i];
@@ -268,7 +283,7 @@ export class Nodes {
     return null;
   }
   nodeExists(connectionContainer) {
-    return this.nodes.findIndex(function(node) {
+    return this.nodes.findIndex(function (node) {
       return node.container === connectionContainer;
     });
   }
@@ -277,9 +292,12 @@ export class Nodes {
     for (let i = 0; i < this.nodes.length; ++i) {
       if (this.nodes[i].normals) {
         if (
-          this.nodes[i].normals.some(function(normal, j) {
+          this.nodes[i].normals.some(function (normal, j) {
             if (normal.container === connectionContainer && i !== j) {
-              normalInfo = { nodesIndex: i, normalsIndex: j };
+              normalInfo = {
+                nodesIndex: i,
+                normalsIndex: j
+              };
               return true;
             }
             return false;
@@ -295,11 +313,11 @@ export class Nodes {
     if (Object.prototype.toString.call(nodes) !== "[object Array]") {
       nodes = [nodes];
     }
-    this.nodes.forEach(function(d) {
+    this.nodes.forEach(function (d) {
       localStorage[d.name] = JSON.stringify({
         x: Math.round(d.x),
         y: Math.round(d.y),
-        fixed: d.fixed & 1 ? 1 : 0
+        fixed: d.fixed
       });
     });
   }
@@ -413,24 +431,23 @@ export class Nodes {
       fixed,
       properties
     );
-    this.nodes.push(obj);
-    return obj;
+    return this.add(obj);
   }
   clearHighlighted() {
     for (let i = 0; i < this.nodes.length; ++i) {
       this.nodes[i].highlighted = false;
     }
   }
-  initialize(nodeInfo, localStorage, width, height) {
+
+  initialize(nodeInfo, width, height, localStorage) {
+    this.nodes.length = 0;
     let nodeCount = Object.keys(nodeInfo).length;
     let yInit = 50;
     let animate = false;
     for (let id in nodeInfo) {
       let name = utils.nameFromId(id);
       // if we have any new nodes, animate the force graph to position them
-      let position = localStorage[name]
-        ? JSON.parse(localStorage[name])
-        : undefined;
+      let position = localStorage[name] ? JSON.parse(localStorage[name]) : undefined;
       if (!position) {
         animate = true;
         position = {
@@ -439,7 +456,7 @@ export class Nodes {
           ),
           y: Math.round(
             height / 2 +
-              (Math.sin(this.nodes.length / (Math.PI * 2.0)) * height) / 4
+            (Math.sin(this.nodes.length / (Math.PI * 2.0)) * height) / 4
           ),
           fixed: false
         };
@@ -448,6 +465,7 @@ export class Nodes {
         position.y = 200 - yInit;
         yInit *= -1;
       }
+      position.fixed = position.fixed ? true : false;
       let parts = id.split("/");
       this.addUsing(
         id,
@@ -458,10 +476,9 @@ export class Nodes {
         position.y,
         name,
         undefined,
-        position.fixed,
-        {}
+        position.fixed, {}
       );
     }
     return animate;
   }
-}
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org