Browse Source

HUE-8687 [frontend] Move reminding chart components into webpack bundles

Johan Ahlen 7 years ago
parent
commit
fd63d8383c
49 changed files with 8739 additions and 9081 deletions
  1. 1 1
      .eslintrc.js
  2. 0 4
      apps/beeswax/src/beeswax/templates/execute.mako
  3. 0 2
      apps/beeswax/src/beeswax/templates/watch_results.mako
  4. 0 1
      apps/oozie/src/oozie/templates/editor2/bundle_editor.mako
  5. 0 1
      apps/oozie/src/oozie/templates/editor2/coordinator_editor.mako
  6. 0 1
      apps/oozie/src/oozie/templates/editor2/workflow_editor.mako
  7. 3 1
      desktop/core/src/desktop/js/hue.js
  8. 363 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.leafletMapChart.js
  9. 1 3
      desktop/core/src/desktop/js/ko/bindings/charts/mapchart/ko.mapChart.js
  10. 181 0
      desktop/core/src/desktop/js/ko/bindings/charts/plotly/ko.plotly.js
  11. 2 1
      desktop/core/src/desktop/js/ko/ko.all.js
  12. 11 11
      desktop/core/src/desktop/js/nvd3/nv.all.js
  13. 483 0
      desktop/core/src/desktop/js/nvd3/nv.d3.growingDiscreteBar.js
  14. 439 0
      desktop/core/src/desktop/js/nvd3/nv.d3.growingDiscreteBarChart.js
  15. 687 0
      desktop/core/src/desktop/js/nvd3/nv.d3.growingMultiBar.js
  16. 651 0
      desktop/core/src/desktop/js/nvd3/nv.d3.growingMultiBarChart.js
  17. 589 0
      desktop/core/src/desktop/js/nvd3/nv.d3.growingPie.js
  18. 141 106
      desktop/core/src/desktop/js/nvd3/nv.d3.growingPieChart.js
  19. 380 0
      desktop/core/src/desktop/js/nvd3/nv.d3.legend.js
  20. 1146 0
      desktop/core/src/desktop/js/nvd3/nv.d3.lineWithBrushChart.js
  21. 1275 0
      desktop/core/src/desktop/js/nvd3/nv.d3.multiBarWithBrushChart.js
  22. 2338 0
      desktop/core/src/desktop/js/utils/hueGeo.js
  23. 0 6
      desktop/core/src/desktop/static/desktop/ext/js/plotly-latest.min.js
  24. 0 355
      desktop/core/src/desktop/static/desktop/js/hue.geo.js
  25. 0 310
      desktop/core/src/desktop/static/desktop/js/ko.charts.leaflet.js
  26. 0 173
      desktop/core/src/desktop/static/desktop/js/ko.charts.plotly.js
  27. 0 42
      desktop/core/src/desktop/static/desktop/js/nv.d3.dom.js
  28. 0 390
      desktop/core/src/desktop/static/desktop/js/nv.d3.growingDiscreteBar.js
  29. 0 387
      desktop/core/src/desktop/static/desktop/js/nv.d3.growingDiscreteBarChart.js
  30. 0 528
      desktop/core/src/desktop/static/desktop/js/nv.d3.growingMultiBar.js
  31. 0 569
      desktop/core/src/desktop/static/desktop/js/nv.d3.growingMultiBarChart.js
  32. 0 481
      desktop/core/src/desktop/static/desktop/js/nv.d3.growingPie.js
  33. 0 300
      desktop/core/src/desktop/static/desktop/js/nv.d3.legend.js
  34. 0 974
      desktop/core/src/desktop/static/desktop/js/nv.d3.lineWithBrushChart.js
  35. 0 1092
      desktop/core/src/desktop/static/desktop/js/nv.d3.multiBarWithBrushChart.js
  36. 0 689
      desktop/core/src/desktop/static/desktop/js/nv.d3.scatter.js
  37. 0 644
      desktop/core/src/desktop/static/desktop/js/nv.d3.scatterChart.js
  38. 0 508
      desktop/core/src/desktop/static/desktop/js/nv.d3.sunburst.js
  39. 0 188
      desktop/core/src/desktop/static/desktop/js/nv.d3.sunburstChart.js
  40. 0 498
      desktop/core/src/desktop/static/desktop/js/nv.d3.tooltip.js
  41. 0 747
      desktop/core/src/desktop/static/desktop/js/nv.d3.utils.js
  42. 0 54
      desktop/core/src/desktop/templates/charting.mako
  43. 0 2
      desktop/core/src/desktop/templates/common_header.mako
  44. 0 3
      desktop/core/src/desktop/templates/common_header_m.mako
  45. 8 2
      desktop/core/src/desktop/templates/hue.mako
  46. 0 1
      desktop/libs/dashboard/src/dashboard/templates/common_search.mako
  47. 3 2
      ext/thirdparty/README.md
  48. 28 0
      package-lock.json
  49. 9 4
      package.json

+ 1 - 1
.eslintrc.js

@@ -10,7 +10,7 @@ const hueGlobals = [
   'USER_HOME_DIR', 'WorkerGlobalScope',
 
   // other misc
-  'ace', 'CodeMirror', 'HueGeo', 'impalaDagre', 'less', 'MediumEditor', 'moment', 'Plotly', 'Role', 'trackOnGA',
+  'ace', 'CodeMirror', 'impalaDagre', 'less', 'MediumEditor', 'moment', 'Role', 'trackOnGA',
 
   // jasmine
   'afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'describe', 'expect', 'fail', 'fdescribe', 'fit', 'it', 'jasmine',

+ 0 - 4
apps/beeswax/src/beeswax/templates/execute.mako

@@ -24,7 +24,6 @@
 %>
 
 <%namespace name="assist" file="/assist.mako" />
-<%namespace name="charting" file="/charting.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 
@@ -1121,12 +1120,9 @@ ${ assist.assistPanel() }
 </style>
 
 <link rel="stylesheet" href="${ static('desktop/ext/css/hue-filetypes.css') }">
-<link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
 
 <script src="${ static('desktop/ext/js/jquery/plugins/jquery-fieldselection.js') }" type="text/javascript"></script>
 
-${ charting.import_charts() }
-
 <script type="text/javascript">
 
 // avoid blinking of the panels

+ 0 - 2
apps/beeswax/src/beeswax/templates/watch_results.mako

@@ -71,8 +71,6 @@ ${layout.menubar(section='query')}
     height: 400px;
   }
 </style>
-<link href="${ static('desktop/ext/css/leaflet.css') }" rel="stylesheet">
-<link href="${ static('desktop/ext/css/leaflet.markercluster.css') }" rel="stylesheet">
 
 <div class="container-fluid">
   <div id="expand"><i class="fa fa-chevron-right" style="color: #FFFFFF"></i></div>

+ 0 - 1
apps/oozie/src/oozie/templates/editor2/bundle_editor.mako

@@ -258,7 +258,6 @@ ${ layout.menubar(section='bundles', is_editor=True, pullright=buttons, is_embed
 
 
 <link rel="stylesheet" href="${ static('desktop/ext/css/hue-filetypes.css') }">
-<link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
 <link rel="stylesheet" href="${ static('oozie/css/common-editor.css') }">
 <link rel="stylesheet" href="${ static('oozie/css/coordinator-editor.css') }">
 

+ 0 - 1
apps/oozie/src/oozie/templates/editor2/coordinator_editor.mako

@@ -110,7 +110,6 @@ ${ scheduler.import_modals() }
 </div>
 
 <link rel="stylesheet" href="${ static('desktop/ext/css/hue-filetypes.css') }">
-<link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
 <link rel="stylesheet" href="${ static('oozie/css/common-editor.css') }">
 <link rel="stylesheet" href="${ static('oozie/css/coordinator-editor.css') }">
 

+ 0 - 1
apps/oozie/src/oozie/templates/editor2/workflow_editor.mako

@@ -584,7 +584,6 @@ ${ workflow.render() }
 </div>
 
 <link rel="stylesheet" href="${ static('desktop/ext/css/hue-filetypes.css') }">
-<link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
 <link rel="stylesheet" href="${ static('oozie/css/common-editor.css') }">
 <link rel="stylesheet" href="${ static('oozie/css/workflow-editor.css') }">
 

+ 3 - 1
desktop/core/src/desktop/js/hue.js

@@ -25,7 +25,7 @@ import d3v3 from 'd3v3';
 import Dropzone from 'dropzone';
 import filesize from 'filesize';
 import localforage from 'localforage';
-import nv from 'ext/nv.d3.1.1.15b.custom';
+import nv from 'nvd3/nv.all';
 import page from 'page';
 import qq from 'ext/fileuploader.custom';
 import sprintf from 'sprintf-js';
@@ -43,6 +43,7 @@ import hueAnalytics from 'utils/hueAnalytics';
 import HueColors from 'utils/hueColors';
 import hueDebug from 'utils/hueDebug';
 import hueDrop from 'utils/hueDrop';
+import HueGeo from 'utils/hueGeo';
 import huePubSub from 'utils/huePubSub';
 import hueUtils from 'utils/hueUtils';
 import I18n from 'utils/i18n';
@@ -83,6 +84,7 @@ window.hueAnalytics = hueAnalytics;
 window.HueColors = HueColors;
 window.hueDebug = hueDebug;
 window.hueDrop = hueDrop;
+window.HueGeo = HueGeo;
 window.huePubSub = huePubSub;
 window.hueUtils = hueUtils;
 window.I18n = I18n;

+ 363 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.leafletMapChart.js

@@ -0,0 +1,363 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import $ from 'jquery';
+import ko from 'knockout';
+import L from 'leaflet';
+
+import huePubSub from 'utils/huePubSub';
+import 'leaflet.markercluster';
+import 'leaflet.heat';
+import 'leaflet-zoombox';
+
+ko.bindingHandlers.leafletMapChart = {
+  update: function(element, valueAccessor) {
+    const _options = valueAccessor();
+    const _data = _options.transformer(valueAccessor().datum);
+
+    function toggleVisibility() {
+      if (
+        !_data.message &&
+        ((_options.visible != null && _options.visible) ||
+          _options.visible == null ||
+          typeof _options == 'undefined')
+      ) {
+        $(element).show();
+        $(element)
+          .siblings('.leaflet-nodata')
+          .remove();
+      } else {
+        $(element).hide();
+        if (
+          (_data.message || (_options.visible != null && _options.visible)) &&
+          !_options.isLoading
+        ) {
+          $(element)
+            .siblings('.leaflet-nodata')
+            .remove();
+          $(element).before(
+            $('<div>')
+              .addClass('leaflet-nodata')
+              .css({ textAlign: 'center', fontSize: '18px', fontWeight: 700, marginTop: '20px' })
+              .text(_data.message || window.I18n('No Data Available.'))
+          );
+        }
+      }
+    }
+
+    if (
+      $(element).data('mapData') == null ||
+      $(element).data('mapData') !== ko.toJSON(_data) ||
+      _options.forceRedraw
+    ) {
+      $(element).data('mapData', ko.toJSON(_data));
+
+      let _hasAtLeastOneLat = false;
+      _data.forEach(item => {
+        if (item.lat != null && $.isNumeric(item.lat)) {
+          _hasAtLeastOneLat = true;
+        }
+      });
+      let _hasAtLeastOneLng = false;
+      _data.forEach(item => {
+        if (item.lng != null && $.isNumeric(item.lng)) {
+          _hasAtLeastOneLng = true;
+        }
+      });
+
+      if (_options.height != null) {
+        $(element).height(_options.height * 1);
+      } else if ($(element).parents('.tab-pane').length > 0) {
+        $(element).height(
+          $(element)
+            .parents('.tab-pane')
+            .height() - 100
+        );
+      } else {
+        $(element).height(300);
+      }
+
+      toggleVisibility();
+
+      let _map = null;
+      if ($(element).data('_map') != null) {
+        _map = $(element).data('_map');
+        _map.removeLayer($(element).data('_markerLayer'));
+        if ($(element).data('_heatLayer')) {
+          _map.removeLayer($(element).data('_heatLayer'));
+          $(element).data('_heatLayer', null);
+        }
+      }
+
+      const _clusterGroup = L.markerClusterGroup({
+        maxClusterRadius: 10,
+        polygonOptions: {
+          weight: 1.5
+        }
+      });
+
+      let heat;
+
+      if (_hasAtLeastOneLat && _hasAtLeastOneLng) {
+        try {
+          if (_map == null) {
+            if (window.LEAFLET_DEFAULTS.mapOptions.crs) {
+              window.LEAFLET_DEFAULTS.mapOptions.crs =
+                L.CRS[window.LEAFLET_DEFAULTS.mapOptions.crs];
+            }
+            _map = L.map(element, window.LEAFLET_DEFAULTS.mapOptions);
+            let tileLayerOptions = {
+              layer: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
+              attribution:
+                '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
+            };
+            if (window.LEAFLET_DEFAULTS.layer) {
+              tileLayerOptions.layer = window.LEAFLET_DEFAULTS.layer;
+            }
+            if (window.LEAFLET_DEFAULTS.attribution) {
+              tileLayerOptions.attribution = window.LEAFLET_DEFAULTS.attribution;
+            }
+            if (window.LEAFLET_DEFAULTS.layerOptions) {
+              tileLayerOptions = $.extend(tileLayerOptions, window.LEAFLET_DEFAULTS.layerOptions);
+            }
+            L.tileLayer(tileLayerOptions.layer, tileLayerOptions).addTo(_map);
+
+            if (L.control.zoomBox) {
+              const _zoomBox = L.control.zoomBox({
+                modal: true
+              });
+              _map.addControl(_zoomBox);
+            }
+
+            if (_options.showMoveCheckbox) {
+              const _command = L.control({
+                position: $(element).width() > 300 ? 'topright' : 'bottomleft'
+              });
+
+              _command.onAdd = function(map) {
+                const div = L.DomUtil.create(
+                  'div',
+                  'leaflet-search-command leaflet-bar leaflet-move-label'
+                );
+                div.innerHTML =
+                  '<button id="command' +
+                  $(element)
+                    .parents('.card-widget')
+                    .attr('id') +
+                  '" type="button" class="btn btn-mini disable-feedback"><i class="fa fa-fw fa-square-o"></i> ' +
+                  (_options.moveCheckboxLabel
+                    ? _options.moveCheckboxLabel
+                    : 'Search as I move the map') +
+                  '</button>';
+                return div;
+              };
+
+              _command.addTo(_map);
+
+              if (_options.onRegionChange == null) {
+                _options.onRegionChange = function() {};
+              }
+
+              let _onRegionChange = function() {};
+
+              $(
+                '#command' +
+                  $(element)
+                    .parents('.card-widget')
+                    .attr('id')
+              ).on('click', function(e) {
+                $(this).toggleClass('btn-primary');
+                $(this)
+                  .find('.fa-fw')
+                  .toggleClass('fa-check-square');
+                if ($(this).hasClass('btn-primary')) {
+                  if (_options.onRegionChange != null) {
+                    _onRegionChange = _options.onRegionChange;
+                  }
+                } else {
+                  _onRegionChange = function() {};
+                }
+              });
+
+              ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
+                $(
+                  '#command' +
+                    $(element)
+                      .parents('.card-widget')
+                      .attr('id')
+                ).off('click');
+              });
+
+              _map.on('boxzoomend', e => {
+                _onRegionChange(e.boxZoomBounds);
+              });
+              _map.on('dragend', () => {
+                _onRegionChange(_map.getBounds());
+              });
+              _map.on('zoomend', () => {
+                _onRegionChange(_map.getBounds());
+              });
+              _map.on('viewreset', () => {
+                huePubSub.publish('leaflet.afterplot', element);
+              });
+            }
+          }
+
+          let heatData = [];
+
+          const sumHeatData = data => {
+            const sumData = [];
+            data.forEach(d => {
+              let found = false;
+              if (d.length === 3) {
+                sumData.forEach(s => {
+                  if (d[0] === s[0] && d[1] === s[1]) {
+                    found = true;
+                    s[2] += d[2];
+                  }
+                });
+              }
+              if (!found) {
+                sumData.push(d);
+              }
+            });
+            return sumData;
+          };
+
+          const getMaxIntensity = data => {
+            let maxIntensity = 0;
+            data.forEach(d => {
+              if (d[2] > maxIntensity) {
+                maxIntensity = d[2];
+              }
+            });
+            return maxIntensity;
+          };
+
+          _data.forEach(item => {
+            if (item && item.lng != null && item.lat != null) {
+              let _addMarker = false;
+              try {
+                const _latLngObj = L.latLng(item.lat, item.lng);
+                _addMarker = true;
+              } catch (e) {
+                if (typeof console != 'undefined') {
+                  console.error(e);
+                }
+              }
+              if (_addMarker) {
+                const _marker = L.marker([item.lat, item.lng]);
+                if (item.isHeat) {
+                  if (item.intensity != null) {
+                    heatData.push([item.lat, item.lng, item.intensity]);
+                  } else {
+                    heatData.push([item.lat, item.lng]);
+                  }
+                } else if (item.label != null) {
+                  _marker.bindPopup($.isArray(item.label) ? item.label.join('') : item.label);
+                }
+                _clusterGroup.addLayer(_marker);
+              }
+            }
+          });
+
+          if (heatData.length > 0) {
+            heatData = sumHeatData(heatData);
+            heat = L.heatLayer(heatData);
+            if (heatData[0].length === 3) {
+              // it has intensity
+              heat.setOptions(getMaxIntensity(heatData));
+            }
+          }
+
+          window.setTimeout(() => {
+            if (
+              !$(
+                '#command' +
+                  $(element)
+                    .parents('.card-widget')
+                    .attr('id')
+              ).is(':checked')
+            ) {
+              _map.fitBounds(_clusterGroup.getBounds());
+            }
+            if (
+              $(element)
+                .find('.leaflet-tile-pane')
+                .children().length > 0
+            ) {
+              if (heatData.length == 0) {
+                _map.addLayer(_clusterGroup);
+                $('.leaflet-heatmap-layer').remove();
+              } else {
+                try {
+                  $('.leaflet-heatmap-layer').remove();
+                  heat.addTo(_map);
+                } catch (e) {} // context2D not initialized yet
+              }
+            }
+            if (_options.onComplete != null) {
+              _options.onComplete();
+            }
+          }, 0);
+
+          const resizeSubscription = huePubSub.subscribe('resize.leaflet.map', () => {
+            if ($(element).data('_map')) {
+              $(element)
+                .data('_map')
+                .invalidateSize();
+              if ($(element).data('_markerLayer')) {
+                try {
+                  $(element)
+                    .data('_map')
+                    .fitBounds(
+                      $(element)
+                        .data('_markerLayer')
+                        .getBounds()
+                    );
+                } catch (e) {}
+              }
+            }
+          });
+
+          ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
+            resizeSubscription.remove();
+          });
+        } catch (err) {
+          $.jHueNotify.error(err.message);
+        }
+      }
+
+      const previousMarkerLayer = $(element).data('_markerLayer');
+      if (previousMarkerLayer) {
+        window.setTimeout(() => {
+          try {
+            previousMarkerLayer.removeLayers(previousMarkerLayer.getLayers());
+          } catch (e) {}
+        }, 0);
+      }
+
+      $(element).data('_map', _map);
+      $(element).data('_markerLayer', _clusterGroup);
+      $(element).data('_heatLayer', heat);
+      if (_options.onComplete != null) {
+        _options.onComplete();
+      }
+    } else {
+      toggleVisibility();
+    }
+  }
+};

+ 1 - 3
desktop/core/src/desktop/js/ko/bindings/charts/mapchart/ko.mapChart.js

@@ -21,6 +21,7 @@ import nv from 'ext/nv.d3.1.1.15b.custom';
 import Datamap from './datamap';
 import huePubSub from 'utils/huePubSub';
 import HueColors from 'utils/hueColors';
+import HueGeo from 'utils/hueGeo';
 
 ko.bindingHandlers.mapChart = {
   render: function(element, valueAccessor) {
@@ -217,7 +218,6 @@ ko.bindingHandlers.mapChart = {
       let _map = null;
 
       function createDatamap(element, options, fills, mapData, nonCountries, mapHovers) {
-        console.log('createDatamap');
         _map = new Datamap({
           element: element,
           fills: fills,
@@ -327,11 +327,9 @@ ko.bindingHandlers.mapChart = {
     $element.data('drawThrottle', timeout);
   },
   init: function(element, valueAccessor) {
-    console.log('init');
     ko.bindingHandlers.mapChart.render(element, valueAccessor);
   },
   update: function(element, valueAccessor, allBindingsAccessor) {
-    console.log('update');
     if (typeof allBindingsAccessor().mapChart.visible != 'undefined') {
       if (
         (typeof allBindingsAccessor().mapChart.visible == 'boolean' &&

+ 181 - 0
desktop/core/src/desktop/js/ko/bindings/charts/plotly/ko.plotly.js

@@ -0,0 +1,181 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+/*
+
+  This is the Plotly replacement for the charts, currently not in use.
+
+ */
+
+import $ from 'jquery';
+import ko from 'knockout';
+import Plotly from 'plotly.js-dist';
+
+import huePubSub from 'utils/huePubSub';
+
+// TODO: Search and replace at source
+window.HUE_CHARTS = {
+  TYPES: {
+    LINECHART: 'lines',
+    BARCHART: 'bars',
+    TIMELINECHART: 'timeline',
+    POINTCHART: 'points',
+    PIECHART: 'pie',
+    MAP: 'map',
+    GRADIENTMAP: 'gradientmap',
+    SCATTERCHART: 'scatter'
+  }
+};
+
+const PLOTLY_COMMON_LAYOUT = {
+  height: 400
+};
+
+const PLOTLY_COMMON_OPTIONS = {
+  displaylogo: false,
+  modeBarButtonsToRemove: ['sendDataToCloud', 'hoverCompareCartesian']
+};
+
+function resizeHandlers(element) {
+  const resizeEvent = function() {
+    try {
+      if ($(element).is(':visible')) {
+        Plotly.Plots.resize(element);
+      }
+    } catch (e) {}
+  };
+  const resizeSubscription = huePubSub.subscribe('resize.plotly.chart', resizeEvent);
+
+  $(window).on('resize', resizeEvent);
+  ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
+    resizeSubscription.remove();
+    $(window).off('resize', resizeEvent);
+  });
+}
+
+function eventEmitterSetup(element) {
+  element.on('plotly_afterplot', () => {
+    huePubSub.publish('plotly.afterplot', element);
+  });
+}
+
+ko.bindingHandlers.pieChart = {
+  init: function(element, valueAccessor) {
+    resizeHandlers(element);
+  },
+  update: function(element, valueAccessor) {
+    const options = valueAccessor();
+    window.clearTimeout(element.plotterTimeout);
+    element.plotterTimeout = window.setTimeout(() => {
+      const data = options.transformer(options.data);
+      const chartData = {
+        values: [],
+        labels: [],
+        type: 'pie'
+      };
+      data.forEach(el => {
+        chartData.values.push(el.value);
+        chartData.labels.push(el.label);
+      });
+      Plotly.newPlot(element, [chartData], PLOTLY_COMMON_LAYOUT, PLOTLY_COMMON_OPTIONS);
+      eventEmitterSetup(element);
+    }, 200);
+  }
+};
+
+function basicChartBuilder(element, valueAccessor, chartType) {
+  const options = valueAccessor();
+  window.clearTimeout(element.plotterTimeout);
+  element.plotterTimeout = window.setTimeout(() => {
+    const data = options.transformer(options.datum);
+    const chartData = [];
+    data.forEach(el => {
+      const chartSerie = {
+        x: [],
+        y: [],
+        name: el.key,
+        type: options.chartType || chartType
+      };
+      el.values.forEach(serie => {
+        chartSerie.x.push(serie.x);
+        chartSerie.y.push(serie.y);
+      });
+      chartData.push(chartSerie);
+    });
+    Plotly.newPlot(element, chartData, PLOTLY_COMMON_LAYOUT, PLOTLY_COMMON_OPTIONS);
+    eventEmitterSetup(element);
+  }, 200);
+}
+
+ko.bindingHandlers.basicChart = {
+  init: function(element, valueAccessor) {
+    resizeHandlers(element);
+  },
+  update: function(element, valueAccessor) {
+    basicChartBuilder(element, valueAccessor);
+  }
+};
+
+ko.bindingHandlers.barChart = {
+  init: function(element, valueAccessor) {
+    resizeHandlers(element);
+  },
+  update: function(element, valueAccessor) {
+    basicChartBuilder(element, valueAccessor, 'bar');
+  }
+};
+
+ko.bindingHandlers.timelineChart = {
+  init: function(element, valueAccessor) {
+    resizeHandlers(element);
+  },
+  update: function(element, valueAccessor) {
+    basicChartBuilder(element, valueAccessor, 'scatter');
+  }
+};
+
+ko.bindingHandlers.lineChart = {
+  init: function(element, valueAccessor) {
+    resizeHandlers(element);
+  },
+  update: function(element, valueAccessor) {
+    basicChartBuilder(element, valueAccessor, 'scatter');
+  }
+};
+
+ko.bindingHandlers.mapChart = {
+  init: function(element, valueAccessor) {
+    $(element).html('To-do.');
+  },
+  update: function(element, valueAccessor, allBindingsAccessor) {
+    $(element).html('To-do.');
+  }
+};
+
+ko.bindingHandlers.scatterChart = {
+  update: function(element, valueAccessor) {
+    $(element).html('To-do.');
+  }
+};
+
+ko.bindingHandlers.partitionChart = {
+  init: function(element, valueAccessor) {
+    $(element).html('To-do.');
+  },
+  update: function(element, valueAccessor) {
+    $(element).html('To-do.');
+  }
+};

+ 2 - 1
desktop/core/src/desktop/js/ko/ko.all.js

@@ -24,8 +24,10 @@ import 'knockout.validation';
 import 'ext/ko.editable.custom';
 import 'ext/ko.selectize.custom';
 
+// import 'ko/bindings/charts/plotly/ko.plotly'; // The Plotly chart replacement
 import 'ko/bindings/charts/mapchart/ko.mapChart';
 import 'ko/bindings/charts/ko.barChart';
+import 'ko/bindings/charts/ko.leafletMapChart';
 import 'ko/bindings/charts/ko.lineChart';
 import 'ko/bindings/charts/ko.partitionChart';
 import 'ko/bindings/charts/ko.pieChart';
@@ -94,7 +96,6 @@ import 'ko/bindings/ko.numericTextInput';
 import 'ko/bindings/ko.onClickOutside';
 import 'ko/bindings/ko.oneClickSelect';
 import 'ko/bindings/ko.parseArguments';
-import 'ko/bindings/ko.plotly';
 import 'ko/bindings/ko.publish';
 import 'ko/bindings/ko.readOnlyAce';
 import 'ko/bindings/ko.resizable';

+ 11 - 11
desktop/core/src/desktop/js/ko/bindings/ko.plotly.js → desktop/core/src/desktop/js/nvd3/nv.all.js

@@ -14,15 +14,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import ko from 'knockout';
+import nv from 'ext/nv.d3.1.1.15b.custom';
+import 'nvd3/nv.d3.growingDiscreteBar';
+import 'nvd3/nv.d3.growingDiscreteBarChart';
+import 'nvd3/nv.d3.growingMultiBar';
+import 'nvd3/nv.d3.growingMultiBarChart';
+import 'nvd3/nv.d3.growingPie';
+import 'nvd3/nv.d3.growingPieChart';
+import 'nvd3/nv.d3.legend';
+import 'nvd3/nv.d3.lineWithBrushChart';
+import 'nvd3/nv.d3.multiBarWithBrushChart';
 
-// TODO: Depends on Plotly
-
-ko.bindingHandlers.plotly = {
-  init: function(element, valueAccessor) {
-    const options = valueAccessor() || {};
-    if (typeof Plotly !== 'undefined') {
-      Plotly.plot(element, options.data || [], options.layout || {}, { displaylogo: false });
-    }
-  }
-};
+export default nv;

+ 483 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.growingDiscreteBar.js

@@ -0,0 +1,483 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import $ from 'jquery';
+import d3v3 from 'd3v3';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+//TODO: consider deprecating by adding necessary features to multiBar model
+nv.models.growingDiscreteBar = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const margin = { top: 0, right: 0, bottom: 0, left: 0 };
+  let width = 960,
+    height = 500,
+    id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
+    x = d3v3.scale.ordinal(),
+    y = d3v3.scale.linear(),
+    getX = function(d) {
+      return d.x;
+    },
+    getY = function(d) {
+      return d.y;
+    },
+    forceY = [0], // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
+    color = nv.utils.defaultColor(),
+    showValues = false,
+    valueFormat = d3v3.format(',.2f'),
+    xDomain,
+    yDomain,
+    xRange,
+    yRange,
+    rectClass = 'discreteBar',
+    selectBars = null;
+
+  const dispatch = d3v3.dispatch(
+    'chartClick',
+    'elementClick',
+    'elementDblClick',
+    'elementMouseover',
+    'elementMouseout'
+  );
+  //============================================================
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  let x0, y0;
+
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const availableWidth = width - margin.left - margin.right,
+        availableHeight = height - margin.top - margin.bottom,
+        container = d3v3.select(this);
+
+      //add series index to each data point for reference
+      data.forEach((series, i) => {
+        series.values.forEach(point => {
+          point.series = i;
+          point.seriesKey = series.key;
+        });
+      });
+
+      //------------------------------------------------------------
+      // Setup Scales
+
+      // remap and flatten the data for use in calculating the scales' domains
+      const seriesData =
+        xDomain && yDomain
+          ? [] // if we know xDomain and yDomain, no need to calculate
+          : data.map(d => {
+              return d.values.map((d, i) => {
+                return { x: getX(d, i), y: getY(d, i), y0: d.y0 };
+              });
+            });
+
+      x.domain(
+        xDomain ||
+          d3v3.merge(seriesData).map(d => {
+            return d.x;
+          })
+      ).rangeBands(xRange || [0, availableWidth], 0.1);
+
+      y.domain(
+        yDomain ||
+          d3v3.extent(
+            d3v3
+              .merge(seriesData)
+              .map(d => {
+                return d.y;
+              })
+              .concat(forceY)
+          )
+      );
+
+      // If showValues, pad the Y axis range to account for label height
+      if (showValues) {
+        y.range(
+          yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]
+        );
+      } else {
+        y.range(yRange || [availableHeight, 0]);
+      }
+
+      //store old scales if they exist
+      x0 = x0 || x;
+      y0 = y0 || y.copy().range([y(0), y(0)]);
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]);
+      const wrapEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-discretebar');
+      const gEnter = wrapEnter.append('g');
+      wrap.select('g');
+
+      gEnter.append('g').attr('class', 'nv-groups');
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      //------------------------------------------------------------
+
+      //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later
+      const groups = wrap
+        .select('.nv-groups')
+        .selectAll('.nv-group')
+        .data(
+          d => {
+            return d;
+          },
+          d => {
+            return d.key;
+          }
+        );
+      groups
+        .enter()
+        .append('g')
+        .style('stroke-opacity', 1e-6)
+        .style('fill-opacity', 1e-6);
+      groups
+        .exit()
+        .transition()
+        .style('stroke-opacity', 1e-6)
+        .style('fill-opacity', 1e-6)
+        .remove();
+      groups
+        .attr('class', (d, i) => {
+          return 'nv-group nv-series-' + i;
+        })
+        .classed('hover', d => {
+          return d.hover;
+        });
+      groups
+        .transition()
+        .style('stroke-opacity', 1)
+        .style('fill-opacity', 0.75);
+
+      const bars = groups
+        .selectAll('g.nv-bar')
+        .data(d => {
+          return d.values;
+        })
+        .classed('selected', false);
+
+      bars.exit().remove();
+
+      selectBars = function(selected) {
+        $(selected).each((cnt, item) => {
+          bars.each(function(d) {
+            if (d.x === item) {
+              d3v3.select(this).classed('selected', true);
+            }
+          });
+        });
+      };
+
+      const barsEnter = bars
+        .enter()
+        .append('g')
+        .attr('transform', (d, i) => {
+          return 'translate(' + (x(getX(d, i)) + x.rangeBand() * 0.05) + ', ' + y(0) + ')';
+        })
+        .on('mouseover', function(d, i) {
+          //TODO: figure out why j works above, but not here
+          d3v3.select(this).classed('hover', true);
+          dispatch.elementMouseover({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pos: [x(getX(d, i)) + (x.rangeBand() * (d.series + 0.5)) / data.length, y(getY(d, i))], // TODO: Figure out why the value appears to be shifted
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+        })
+        .on('mouseout', function(d, i) {
+          d3v3.select(this).classed('hover', false);
+          dispatch.elementMouseout({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+        })
+        .on('click', (d, i) => {
+          dispatch.elementClick({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pos: [x(getX(d, i)) + (x.rangeBand() * (d.series + 0.5)) / data.length, y(getY(d, i))], // TODO: Figure out why the value appears to be shifted
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+          d3v3.event.stopPropagation();
+        })
+        .on('dblclick', (d, i) => {
+          dispatch.elementDblClick({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pos: [x(getX(d, i)) + (x.rangeBand() * (d.series + 0.5)) / data.length, y(getY(d, i))], // TODO: Figure out why the value appears to be shifted
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+          d3v3.event.stopPropagation();
+        });
+
+      barsEnter
+        .append('rect')
+        .attr('height', 0)
+        .attr('x', (d, i, j) => {
+          return (j * x.rangeBand()) / data.length;
+        })
+        .attr('width', x.rangeBand() / data.length);
+
+      if (showValues) {
+        barsEnter.append('text').attr('text-anchor', 'middle');
+
+        bars
+          .select('text')
+          .text((d, i) => {
+            return valueFormat(getY(d, i));
+          })
+          .transition()
+          .attr('x', (d, i, j) => {
+            return (j * x.rangeBand()) / data.length + (x.rangeBand() * 0.9) / data.length / 2;
+          })
+          .attr('y', (d, i) => {
+            return getY(d, i) < 0 ? y(getY(d, i)) - y(0) + 12 : -4;
+          });
+      } else {
+        bars.selectAll('text').remove();
+      }
+
+      bars
+        .attr('class', (d, i) => {
+          return getY(d, i) < 0 ? 'nv-bar negative' : 'nv-bar positive';
+        })
+        .style('fill', (d, i) => {
+          return d.color || color(d, i);
+        })
+        .style('stroke', (d, i) => {
+          return d.color || color(d, i);
+        })
+        .select('rect')
+        .attr('class', rectClass)
+        .transition()
+        .attr('x', d => {
+          return (d.series * x.rangeBand()) / data.length;
+        })
+        .attr('width', (x.rangeBand() / data.length) * 0.9);
+      bars
+        .transition()
+        .attr('transform', (d, i) => {
+          const left = x(getX(d, i)) + x.rangeBand() * 0.05,
+            top =
+              getY(d, i) < 0
+                ? y(0)
+                : y(0) - y(getY(d, i)) < 1
+                ? y(0) - 1 //make 1 px positive bars show up above y=0
+                : y(getY(d, i));
+
+          return 'translate(' + left + ', ' + top + ')';
+        })
+        .select('rect')
+        .attr('height', (d, i) => {
+          return Math.max(Math.abs(y(getY(d, i)) - y((yDomain && yDomain[0]) || 0)) || 1);
+        });
+
+      //store old scales for use in transitions on update
+      x0 = x.copy();
+      y0 = y.copy();
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  chart.dispatch = dispatch;
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.x = function(val) {
+    if (!arguments.length) {
+      return getX;
+    }
+    getX = val;
+    return chart;
+  };
+
+  chart.y = function(val) {
+    if (!arguments.length) {
+      return getY;
+    }
+    getY = val;
+    return chart;
+  };
+
+  chart.margin = function(val) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof val.top != 'undefined' ? val.top : margin.top;
+    margin.right = typeof val.right != 'undefined' ? val.right : margin.right;
+    margin.bottom = typeof val.bottom != 'undefined' ? val.bottom : margin.bottom;
+    margin.left = typeof val.left != 'undefined' ? val.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(val) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = val;
+    return chart;
+  };
+
+  chart.height = function(val) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = val;
+    return chart;
+  };
+
+  chart.xScale = function(val) {
+    if (!arguments.length) {
+      return x;
+    }
+    x = val;
+    return chart;
+  };
+
+  chart.yScale = function(val) {
+    if (!arguments.length) {
+      return y;
+    }
+    y = val;
+    return chart;
+  };
+
+  chart.xDomain = function(val) {
+    if (!arguments.length) {
+      return xDomain;
+    }
+    xDomain = val;
+    return chart;
+  };
+
+  chart.yDomain = function(val) {
+    if (!arguments.length) {
+      return yDomain;
+    }
+    yDomain = val;
+    return chart;
+  };
+
+  chart.xRange = function(val) {
+    if (!arguments.length) {
+      return xRange;
+    }
+    xRange = val;
+    return chart;
+  };
+
+  chart.yRange = function(val) {
+    if (!arguments.length) {
+      return yRange;
+    }
+    yRange = val;
+    return chart;
+  };
+
+  chart.forceY = function(val) {
+    if (!arguments.length) {
+      return forceY;
+    }
+    forceY = val;
+    return chart;
+  };
+
+  chart.color = function(val) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(val);
+    return chart;
+  };
+
+  chart.id = function(val) {
+    if (!arguments.length) {
+      return id;
+    }
+    id = val;
+    return chart;
+  };
+
+  chart.showValues = function(val) {
+    if (!arguments.length) {
+      return showValues;
+    }
+    showValues = val;
+    return chart;
+  };
+
+  chart.valueFormat = function(val) {
+    if (!arguments.length) {
+      return valueFormat;
+    }
+    valueFormat = val;
+    return chart;
+  };
+
+  chart.rectClass = function(val) {
+    if (!arguments.length) {
+      return rectClass;
+    }
+    rectClass = val;
+    return chart;
+  };
+
+  chart.selectBars = function(args) {
+    if (!arguments.length) {
+      return selectBars;
+    }
+    selectBars(args);
+    return chart;
+  };
+  //============================================================
+
+  return chart;
+};

+ 439 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.growingDiscreteBarChart.js

@@ -0,0 +1,439 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import $ from 'jquery';
+import d3v3 from 'd3v3';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.growingDiscreteBarChart = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const discretebar = nv.models.growingDiscreteBar(),
+    xAxis = nv.models.axis(),
+    yAxis = nv.models.axis();
+  const margin = { top: 15, right: 10, bottom: 50, left: 60 };
+  let width = null,
+    height = null,
+    color = nv.utils.getColor(),
+    showXAxis = true,
+    showYAxis = true,
+    rightAlignYAxis = false,
+    staggerLabels = false,
+    tooltips = true,
+    tooltip = function(key, x, y) {
+      return '<h3>' + key + '</h3>' + '<p>' + y + ' on ' + x + '</p>';
+    },
+    x,
+    y,
+    noData = 'No Data Available.',
+    transitionDuration = 250,
+    selectBars = null;
+  xAxis
+    .orient('bottom')
+    .highlightZero(false)
+    .showMaxMin(false)
+    .tickFormat(d => {
+      return d;
+    });
+
+  const dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'beforeUpdate');
+  yAxis.orient(rightAlignYAxis ? 'right' : 'left').tickFormat(d3v3.format(',.1f'));
+
+  //============================================================
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  const showTooltip = function(e, offsetElement) {
+    const left = $.browser.msie && $.browser.version.indexOf('9.') > -1 ? e.e.clientX : e.e.layerX,
+      top = e.pos[1] + (offsetElement.offsetTop || 0),
+      x = xAxis.tickFormat()(discretebar.x()(e.point, e.pointIndex)),
+      y = yAxis.tickFormat()(discretebar.y()(e.point, e.pointIndex)),
+      content = tooltip(e.point.seriesKey, x, y, e, chart);
+
+    nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+  };
+
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const container = d3v3.select(this),
+        that = this;
+
+      const availableWidth =
+          (width || parseInt(container.style('width')) || 960) - margin.left - margin.right,
+        availableHeight =
+          (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
+
+      chart.update = function() {
+        dispatch.beforeUpdate();
+        container
+          .transition()
+          .duration(transitionDuration)
+          .call(chart);
+      };
+      chart.container = this;
+
+      //------------------------------------------------------------
+      // Display No Data message if there's nothing to show.
+
+      if (
+        !data ||
+        !data.length ||
+        !data.filter(d => {
+          return d.values.length;
+        }).length
+      ) {
+        const noDataText = container.selectAll('.nv-noData').data([noData]);
+
+        noDataText
+          .enter()
+          .append('text')
+          .attr('class', 'nvd3 nv-noData')
+          .attr('dy', '-.7em')
+          .style('text-anchor', 'middle');
+
+        noDataText
+          .attr('x', margin.left + availableWidth / 2)
+          .attr('y', margin.top + availableHeight / 2)
+          .text(d => {
+            return d;
+          });
+
+        container.selectAll('.nv-discreteBarWithAxes').style('visibility', 'hidden');
+        container.selectAll('.nv-noData').style('visibility', 'visible');
+
+        return chart;
+      } else {
+        container.selectAll('.nv-discreteBarWithAxes').style('visibility', 'visible');
+        container.selectAll('.nv-noData').style('visibility', 'hidden');
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Scales
+
+      x = discretebar.xScale();
+      y = discretebar.yScale().clamp(true);
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([data]);
+      const gEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes')
+        .append('g');
+      const defsEnter = gEnter.append('defs');
+      const g = wrap.select('g');
+
+      gEnter.append('g').attr('class', 'nv-x nv-axis');
+      gEnter
+        .append('g')
+        .attr('class', 'nv-y nv-axis')
+        .append('g')
+        .attr('class', 'nv-zeroLine')
+        .append('line');
+
+      gEnter.append('g').attr('class', 'nv-barsWrap');
+
+      g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      if (rightAlignYAxis) {
+        g.select('.nv-y.nv-axis').attr('transform', 'translate(' + availableWidth + ',0)');
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Main Chart Component(s)
+
+      discretebar.width(availableWidth).height(availableHeight);
+
+      selectBars = discretebar.selectBars;
+
+      const barsWrap = g.select('.nv-barsWrap').datum(
+        data.filter(d => {
+          return !d.disabled;
+        })
+      );
+
+      barsWrap.transition().call(discretebar);
+
+      //------------------------------------------------------------
+
+      defsEnter
+        .append('clipPath')
+        .attr('id', 'nv-x-label-clip-' + discretebar.id())
+        .append('rect');
+
+      g.select('#nv-x-label-clip-' + discretebar.id() + ' rect')
+        .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1))
+        .attr('height', 16)
+        .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2));
+
+      //------------------------------------------------------------
+      // Setup Axes
+
+      if (showXAxis) {
+        xAxis
+          .scale(x)
+          .ticks(availableWidth / 100)
+          .tickSize(-availableHeight, 0);
+
+        g.select('.nv-x.nv-axis').attr(
+          'transform',
+          'translate(0,' +
+            (y.range()[0] + (discretebar.showValues() && y.domain()[0] < 0 ? 16 : 0)) +
+            ')'
+        );
+        //d3v3.transition(g.select('.nv-x.nv-axis'))
+        g.select('.nv-x.nv-axis')
+          .transition()
+          .call(xAxis);
+
+        const xTicks = g.select('.nv-x.nv-axis').selectAll('g');
+
+        if (staggerLabels) {
+          const rangeBand = x.rangeBand();
+          xTicks.selectAll('text').attr('transform', function(d, i, j) {
+            const self = d3v3.select(this);
+            let textLength = self.node().getComputedTextLength(),
+              text = self.text();
+            while (textLength > rangeBand * 2 && text.length > 0) {
+              text = text.slice(0, -1);
+              self.text(text + '...');
+              textLength = self.node().getComputedTextLength();
+              if (self.text() === '...') {
+                self.text(' ');
+                textLength = 0;
+              }
+            }
+            return 'translate(0,' + (j % 2 === 0 ? '5' : '17') + ')';
+          });
+        }
+      }
+
+      if (showYAxis) {
+        yAxis
+          .scale(y)
+          .ticks(availableHeight / 36)
+          .tickSize(-availableWidth, 0);
+
+        g.select('.nv-y.nv-axis')
+          .transition()
+          .call(yAxis);
+      }
+
+      // Zero line
+      g.select('.nv-zeroLine line')
+        .attr('x1', 0)
+        .attr('x2', availableWidth)
+        .attr('y1', y(0))
+        .attr('y2', y(0));
+
+      //------------------------------------------------------------
+
+      //============================================================
+      // Event Handling/Dispatching (in chart's scope)
+      //------------------------------------------------------------
+
+      dispatch.on('tooltipShow', e => {
+        if (tooltips) {
+          showTooltip(e, that.parentNode);
+        }
+      });
+
+      //============================================================
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Event Handling/Dispatching (out of chart's scope)
+  //------------------------------------------------------------
+
+  discretebar.dispatch.on('elementMouseover.tooltip', e => {
+    e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+    dispatch.tooltipShow(e);
+  });
+
+  discretebar.dispatch.on('elementMouseout.tooltip', e => {
+    dispatch.tooltipHide(e);
+  });
+
+  dispatch.on('tooltipHide', () => {
+    if (tooltips) {
+      nv.tooltip.cleanup();
+    }
+  });
+
+  //============================================================
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  // expose chart's sub-components
+  chart.dispatch = dispatch;
+  chart.discretebar = discretebar;
+  chart.xAxis = xAxis;
+  chart.yAxis = yAxis;
+
+  d3v3.rebind(
+    chart,
+    discretebar,
+    'x',
+    'y',
+    'xDomain',
+    'yDomain',
+    'xRange',
+    'yRange',
+    'forceX',
+    'forceY',
+    'id',
+    'showValues',
+    'valueFormat'
+  );
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    discretebar.color(color);
+    return chart;
+  };
+
+  chart.showXAxis = function(_) {
+    if (!arguments.length) {
+      return showXAxis;
+    }
+    showXAxis = _;
+    return chart;
+  };
+
+  chart.showYAxis = function(_) {
+    if (!arguments.length) {
+      return showYAxis;
+    }
+    showYAxis = _;
+    return chart;
+  };
+
+  chart.rightAlignYAxis = function(_) {
+    if (!arguments.length) {
+      return rightAlignYAxis;
+    }
+    rightAlignYAxis = _;
+    yAxis.orient(_ ? 'right' : 'left');
+    return chart;
+  };
+
+  chart.staggerLabels = function(_) {
+    if (!arguments.length) {
+      return staggerLabels;
+    }
+    staggerLabels = _;
+    return chart;
+  };
+
+  chart.tooltips = function(_) {
+    if (!arguments.length) {
+      return tooltips;
+    }
+    tooltips = _;
+    return chart;
+  };
+
+  chart.tooltipContent = function(_) {
+    if (!arguments.length) {
+      return tooltip;
+    }
+    tooltip = _;
+    return chart;
+  };
+
+  chart.noData = function(_) {
+    if (!arguments.length) {
+      return noData;
+    }
+    noData = _;
+    return chart;
+  };
+
+  chart.transitionDuration = function(_) {
+    if (!arguments.length) {
+      return transitionDuration;
+    }
+    transitionDuration = _;
+    return chart;
+  };
+
+  chart.selectBars = function(args) {
+    if (!arguments.length) {
+      return selectBars;
+    }
+    if (selectBars) {
+      selectBars(args);
+    }
+    return chart;
+  };
+
+  //============================================================
+
+  return chart;
+};

+ 687 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.growingMultiBar.js

@@ -0,0 +1,687 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import $ from 'jquery';
+import d3v3 from 'd3v3';
+import ko from 'knockout';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.growingMultiBar = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const margin = { top: 0, right: 0, bottom: 0, left: 0 };
+  let width = 960,
+    height = 500,
+    x = d3v3.scale.ordinal(),
+    y = d3v3.scale.linear(),
+    id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
+    getX = function(d) {
+      return d.x;
+    },
+    getY = function(d) {
+      return d.y;
+    },
+    forceY = [0], // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
+    clipEdge = true,
+    stacked = false,
+    stackOffset = 'zero', // options include 'silhouette', 'wiggle', 'expand', 'zero', or a custom function
+    color = nv.utils.defaultColor(),
+    hideable = false,
+    barColor = null, // adding the ability to set the color for each rather than the whole group
+    disabled, // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled
+    delay = 0,
+    xDomain,
+    yDomain,
+    xRange,
+    yRange,
+    groupSpacing = 0.1,
+    selectBars = null;
+  const dispatch = d3v3.dispatch(
+    'chartClick',
+    'elementClick',
+    'elementDblClick',
+    'elementMouseover',
+    'elementMouseout'
+  );
+  //============================================================
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  let x0, y0; //used to store previous scales
+
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const availableWidth = width - margin.left - margin.right,
+        availableHeight = height - margin.top - margin.bottom,
+        container = d3v3.select(this);
+
+      if (hideable && data.length) {
+        hideable = [
+          {
+            values: data[0].values.map(d => {
+              return {
+                x: d.x,
+                y: 0,
+                series: d.series,
+                size: 0.01
+              };
+            })
+          }
+        ];
+      }
+
+      if (stacked) {
+        data = d3v3.layout
+          .stack()
+          .offset(stackOffset)
+          .values(d => {
+            return d.values;
+          })
+          .y(getY)(!data.length && hideable ? hideable : data);
+      }
+
+      //add series index to each data point for reference
+      data.forEach((series, i) => {
+        series.values.forEach(point => {
+          point.series = i;
+          point.seriesKey = series.key;
+        });
+      });
+
+      //------------------------------------------------------------
+      // HACK for negative value stacking
+      if (stacked) {
+        data[0].values.map((d, i) => {
+          let posBase = 0,
+            negBase = 0;
+          data.map(d => {
+            const f = d.values[i];
+            if (typeof f != 'undefined') {
+              f.size = Math.abs(f.y);
+              if (f.y < 0) {
+                f.y1 = negBase;
+                negBase = negBase - f.size;
+              } else {
+                f.y1 = f.size + posBase;
+                posBase = posBase + f.size;
+              }
+            }
+          });
+        });
+      }
+
+      //------------------------------------------------------------
+      // Setup Scales
+
+      // remap and flatten the data for use in calculating the scales' domains
+      const seriesData =
+        xDomain && yDomain
+          ? [] // if we know xDomain and yDomain, no need to calculate
+          : data.map(d => {
+              return d.values.map((d, i) => {
+                return { x: getX(d, i), y: getY(d, i), y0: d.y0, y1: d.y1 };
+              });
+            });
+
+      x.domain(
+        xDomain ||
+          d3v3.merge(seriesData).map(d => {
+            return d.x;
+          })
+      ).rangeBands(xRange || [0, availableWidth], groupSpacing);
+
+      //y   .domain(yDomain || d3v3.extent(d3v3.merge(seriesData).map(function(d) { return d.y + (stacked ? d.y1 : 0) }).concat(forceY)))
+      y.domain(
+        yDomain ||
+          d3v3.extent(
+            d3v3
+              .merge(seriesData)
+              .map(d => {
+                return stacked ? (d.y > 0 ? d.y1 : d.y1 + d.y) : d.y;
+              })
+              .concat(forceY)
+          )
+      ).range(yRange || [availableHeight, 0]);
+
+      // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
+      if (x.domain()[0] === x.domain()[1]) {
+        x.domain()[0]
+          ? x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
+          : x.domain([-1, 1]);
+      }
+
+      if (y.domain()[0] === y.domain()[1]) {
+        y.domain()[0]
+          ? y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
+          : y.domain([-1, 1]);
+      }
+
+      x0 = x0 || x;
+      y0 = y0 || y;
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-wrap.nv-multibar').data([data]);
+      const wrapEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-multibar');
+      const defsEnter = wrapEnter.append('defs');
+      const gEnter = wrapEnter.append('g');
+      const g = wrap.select('g');
+
+      gEnter.append('g').attr('class', 'nv-groups');
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      //------------------------------------------------------------
+
+      defsEnter
+        .append('clipPath')
+        .attr('id', 'nv-edge-clip-' + id)
+        .append('rect');
+      wrap
+        .select('#nv-edge-clip-' + id + ' rect')
+        .attr('width', availableWidth)
+        .attr(
+          'height',
+          nv.utils.NaNtoZero(availableHeight) >= 0 ? nv.utils.NaNtoZero(availableHeight) : 0
+        );
+
+      g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
+
+      const groups = wrap
+        .select('.nv-groups')
+        .selectAll('.nv-group')
+        .data(
+          d => {
+            return d;
+          },
+          (d, i) => {
+            return i;
+          }
+        );
+      groups
+        .enter()
+        .append('g')
+        .style('stroke-opacity', 1e-6)
+        .style('fill-opacity', 1e-6);
+      groups
+        .exit()
+        .transition()
+        .selectAll('rect.nv-bar')
+        .delay((d, i) => {
+          return (i * delay) / data[0].values.length;
+        })
+        .attr('y', d => {
+          return stacked ? y0(d.y0) : y0(0);
+        })
+        .attr('height', 0)
+        .remove();
+      groups
+        .attr('class', (d, i) => {
+          return 'nv-group nv-series-' + i;
+        })
+        .classed('hover', d => {
+          return d.hover;
+        })
+        .style('fill', (d, i) => {
+          return color(d, i);
+        })
+        .style('stroke', (d, i) => {
+          return color(d, i);
+        });
+      groups
+        .transition()
+        .style('stroke-opacity', 1)
+        .style('fill-opacity', 0.75);
+
+      const bars = groups
+        .selectAll('rect.nv-bar')
+        .data(d => {
+          return hideable && !data.length ? hideable.values : d.values;
+        })
+        .classed('selected', false);
+
+      bars.exit().remove();
+
+      selectBars = function(selected) {
+        if (selected.rangeValues) {
+          $(selected.rangeValues).each((cnt, item) => {
+            bars.each(function(d) {
+              if (parseInt(d.x) >= parseInt(item.from) && parseInt(d.x_end) <= parseInt(item.to)) {
+                d3v3.select(this).classed('selected', true);
+              }
+            });
+          });
+        } else {
+          let _pivotField = null;
+          if (!Array.isArray(selected)) {
+            _pivotField = selected.field;
+            selected = selected.selected;
+          }
+
+          $(selected).each((cnt, item) => {
+            bars.each(function(d) {
+              if (_pivotField != null) {
+                if (
+                  (Array.isArray(_pivotField)
+                    ? ko.toJSON(d.obj.fq_fields) === ko.toJSON(_pivotField)
+                    : d.obj.fq_fields === _pivotField) &&
+                  (item.values
+                    ? ko.toJSON(d.obj.fq_values) === ko.toJSON(item.values)
+                    : d.obj.fq_values === item)
+                ) {
+                  d3v3.select(this).classed('selected', true);
+                }
+              } else if (d.x instanceof Date) {
+                if (
+                  moment(d.x)
+                    .utc()
+                    .format('YYYY-MM-DD[T]HH:mm:ss[Z]') === item
+                ) {
+                  d3v3.select(this).classed('selected', true);
+                }
+              } else if (d.x === item) {
+                d3v3.select(this).classed('selected', true);
+              }
+            });
+          });
+        }
+      };
+
+      const barsEnter = bars
+        .enter()
+        .append('rect')
+        .attr('class', (d, i) => {
+          return getY(d, i) < 0 ? 'nv-bar negative' : 'nv-bar positive';
+        })
+        .attr('x', (d, i, j) => {
+          return stacked ? 0 : (j * x.rangeBand()) / data.length;
+        })
+        .attr('y', d => {
+          return y0(stacked ? d.y0 : 0);
+        })
+        .attr('height', 0)
+        .attr('width', x.rangeBand() / (stacked ? 1 : data.length))
+        .attr('transform', (d, i) => {
+          return 'translate(' + x(getX(d, i)) + ',0)';
+        });
+      bars
+        .style('fill', (d, i, j) => {
+          return color(d, j, i);
+        })
+        .style('stroke', (d, i, j) => {
+          return color(d, j, i);
+        });
+      barsEnter
+        .on('mouseover', function(d, i) {
+          d3v3.select(this).classed('hover', true);
+          dispatch.elementMouseover({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pos: [
+              x(getX(d, i)) +
+                (x.rangeBand() * (stacked ? data.length / 2 : d.series + 0.5)) / data.length,
+              y(getY(d, i) + (stacked ? d.y0 : 0))
+            ], // TODO: Figure out why the value appears to be shifted
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+        })
+        .on('mouseout', function(d, i) {
+          d3v3.select(this).classed('hover', false);
+          dispatch.elementMouseout({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+        })
+        .on('click', (d, i) => {
+          dispatch.elementClick({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pos: [
+              x(getX(d, i)) +
+                (x.rangeBand() * (stacked ? data.length / 2 : d.series + 0.5)) / data.length,
+              y(getY(d, i) + (stacked ? d.y0 : 0))
+            ], // TODO: Figure out why the value appears to be shifted
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+          d3v3.event.stopPropagation();
+        })
+        .on('dblclick', (d, i) => {
+          dispatch.elementDblClick({
+            value: getY(d, i),
+            point: d,
+            series: data[d.series],
+            pos: [
+              x(getX(d, i)) +
+                (x.rangeBand() * (stacked ? data.length / 2 : d.series + 0.5)) / data.length,
+              y(getY(d, i) + (stacked ? d.y0 : 0))
+            ], // TODO: Figure out why the value appears to be shifted
+            pointIndex: i,
+            seriesIndex: d.series,
+            e: d3v3.event
+          });
+          d3v3.event.stopPropagation();
+        });
+      bars
+        .attr('class', (d, i) => {
+          return getY(d, i) < 0 ? 'nv-bar negative' : 'nv-bar positive';
+        })
+        .transition()
+        .attr('transform', (d, i) => {
+          return 'translate(' + x(getX(d, i)) + ',0)';
+        });
+
+      if (barColor) {
+        if (!disabled) {
+          disabled = data.map(() => {
+            return true;
+          });
+        }
+        bars
+          .style('fill', (d, i, j) => {
+            return d3v3
+              .rgb(barColor(d, i))
+              .darker(
+                disabled
+                  .map((d, i) => {
+                    return i;
+                  })
+                  .filter((d, i) => {
+                    return !disabled[i];
+                  })[j]
+              )
+              .toString();
+          })
+          .style('stroke', (d, i, j) => {
+            return d3v3
+              .rgb(barColor(d, i))
+              .darker(
+                disabled
+                  .map((d, i) => {
+                    return i;
+                  })
+                  .filter((d, i) => {
+                    return !disabled[i];
+                  })[j]
+              )
+              .toString();
+          });
+      }
+
+      if (stacked) {
+        bars
+          .transition()
+          .delay((d, i) => {
+            return (i * delay) / data[0].values.length;
+          })
+          .attr('y', d => {
+            return y(stacked ? d.y1 : 0);
+          })
+          .attr('height', d => {
+            return Math.max(Math.abs(y(d.y + (stacked ? d.y0 : 0)) - y(stacked ? d.y0 : 0)), 1);
+          })
+          .attr('x', d => {
+            return stacked ? 0 : (d.series * x.rangeBand()) / data.length;
+          })
+          .attr('width', x.rangeBand() / (stacked ? 1 : data.length));
+      } else {
+        bars
+          .transition()
+          .delay((d, i) => {
+            return (i * delay) / data[0].values.length;
+          })
+          .attr('x', d => {
+            return (d.series * x.rangeBand()) / data.length;
+          })
+          .attr('width', x.rangeBand() / data.length)
+          .attr('y', (d, i) => {
+            return getY(d, i) < 0 ? y(0) : y(0) - y(getY(d, i)) < 1 ? y(0) - 1 : y(getY(d, i)) || 0;
+          })
+          .attr('height', (d, i) => {
+            return Math.max(Math.abs(y(getY(d, i)) - y(0)), 1) || 0;
+          });
+      }
+
+      //store old scales for use in transitions on update
+      x0 = x.copy();
+      y0 = y.copy();
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  chart.dispatch = dispatch;
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.x = function(_) {
+    if (!arguments.length) {
+      return getX;
+    }
+    getX = _;
+    return chart;
+  };
+
+  chart.y = function(_) {
+    if (!arguments.length) {
+      return getY;
+    }
+    getY = _;
+    return chart;
+  };
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.xScale = function(_) {
+    if (!arguments.length) {
+      return x;
+    }
+    x = _;
+    return chart;
+  };
+
+  chart.yScale = function(_) {
+    if (!arguments.length) {
+      return y;
+    }
+    y = _;
+    return chart;
+  };
+
+  chart.xDomain = function(_) {
+    if (!arguments.length) {
+      return xDomain;
+    }
+    xDomain = _;
+    return chart;
+  };
+
+  chart.yDomain = function(_) {
+    if (!arguments.length) {
+      return yDomain;
+    }
+    yDomain = _;
+    return chart;
+  };
+
+  chart.xRange = function(_) {
+    if (!arguments.length) {
+      return xRange;
+    }
+    xRange = _;
+    return chart;
+  };
+
+  chart.yRange = function(_) {
+    if (!arguments.length) {
+      return yRange;
+    }
+    yRange = _;
+    return chart;
+  };
+
+  chart.forceY = function(_) {
+    if (!arguments.length) {
+      return forceY;
+    }
+    forceY = _;
+    return chart;
+  };
+
+  chart.stacked = function(_) {
+    if (!arguments.length) {
+      return stacked;
+    }
+    stacked = _;
+    return chart;
+  };
+
+  chart.stackOffset = function(_) {
+    if (!arguments.length) {
+      return stackOffset;
+    }
+    stackOffset = _;
+    return chart;
+  };
+
+  chart.clipEdge = function(_) {
+    if (!arguments.length) {
+      return clipEdge;
+    }
+    clipEdge = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    return chart;
+  };
+
+  chart.barColor = function(_) {
+    if (!arguments.length) {
+      return barColor;
+    }
+    barColor = nv.utils.getColor(_);
+    return chart;
+  };
+
+  chart.disabled = function(_) {
+    if (!arguments.length) {
+      return disabled;
+    }
+    disabled = _;
+    return chart;
+  };
+
+  chart.id = function(_) {
+    if (!arguments.length) {
+      return id;
+    }
+    id = _;
+    return chart;
+  };
+
+  chart.hideable = function(_) {
+    if (!arguments.length) {
+      return hideable;
+    }
+    hideable = _;
+    return chart;
+  };
+
+  chart.delay = function(_) {
+    if (!arguments.length) {
+      return delay;
+    }
+    delay = _;
+    return chart;
+  };
+
+  chart.groupSpacing = function(_) {
+    if (!arguments.length) {
+      return groupSpacing;
+    }
+    groupSpacing = _;
+    return chart;
+  };
+
+  chart.selectBars = function(args) {
+    if (!arguments.length) {
+      return selectBars;
+    }
+    selectBars(args);
+    return chart;
+  };
+
+  //============================================================
+
+  return chart;
+};

+ 651 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.growingMultiBarChart.js

@@ -0,0 +1,651 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import d3v3 from 'd3v3';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.growingMultiBarChart = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const multibar = nv.models.growingMultiBar(),
+    xAxis = nv.models.axis(),
+    yAxis = nv.models.axis(),
+    legend = nv.models.legend(),
+    controls = nv.models.legend();
+  const margin = { top: 30, right: 20, bottom: 50, left: 60 };
+  let width = null,
+    height = null,
+    color = nv.utils.defaultColor(),
+    showControls = true,
+    showLegend = true,
+    showXAxis = true,
+    showYAxis = true,
+    rightAlignYAxis = false,
+    reduceXTicks = true, // if false a tick will show for every data point
+    staggerLabels = false,
+    rotateLabels = 0,
+    tooltips = true,
+    tooltip = function(key, x, y) {
+      return '<h3>' + key + '</h3>' + '<p>' + y + ' on ' + x + '</p>';
+    },
+    x, //can be accessed via chart.xScale()
+    y, //can be accessed via chart.yScale()
+    state = { stacked: false },
+    defaultState = null,
+    noData = 'No Data Available.',
+    transitionDuration = 250,
+    selectBars = null,
+    onStateChange = null;
+  const controlWidth = () => (showControls ? 180 : 0);
+  const dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState');
+  multibar.stacked(false);
+  xAxis
+    .orient('bottom')
+    .tickPadding(7)
+    .highlightZero(true)
+    .showMaxMin(false)
+    .tickFormat(d => {
+      return d;
+    });
+  yAxis.orient(rightAlignYAxis ? 'right' : 'left').tickFormat(d3v3.format(',.1f'));
+
+  controls.updateState(false);
+  //============================================================
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  const showTooltip = function(e, offsetElement) {
+    const left = e.pos[0] + (offsetElement.offsetLeft || 0),
+      top = e.pos[1] + (offsetElement.offsetTop || 0),
+      x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
+      y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex)),
+      content = tooltip(e.point.seriesKey, x, y, e, chart);
+
+    nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+  };
+
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const container = d3v3.select(this),
+        that = this;
+
+      const availableWidth =
+        (width || parseInt(container.style('width')) || 960) - margin.left - margin.right;
+      let availableHeight =
+        (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
+
+      chart.update = function() {
+        container
+          .transition()
+          .duration(transitionDuration)
+          .call(chart);
+      };
+      chart.container = this;
+
+      //set state.disabled
+      state.disabled = data.map(d => {
+        return !!d.disabled;
+      });
+
+      if (!defaultState) {
+        let key;
+        defaultState = {};
+        for (key in state) {
+          if (state[key] instanceof Array) {
+            defaultState[key] = state[key].slice(0);
+          } else {
+            defaultState[key] = state[key];
+          }
+        }
+      }
+      //------------------------------------------------------------
+      // Display noData message if there's nothing to show.
+
+      if (
+        !data ||
+        !data.length ||
+        !data.filter(d => {
+          return d.values.length;
+        }).length
+      ) {
+        const noDataText = container.selectAll('.nv-noData').data([noData]);
+
+        noDataText
+          .enter()
+          .append('text')
+          .attr('class', 'nvd3 nv-noData')
+          .attr('dy', '-.7em')
+          .style('text-anchor', 'middle');
+
+        noDataText
+          .attr('x', margin.left + availableWidth / 2)
+          .attr('y', margin.top + availableHeight / 2)
+          .text(d => {
+            return d;
+          });
+
+        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'hidden');
+        container.selectAll('.nv-noData').style('visibility', 'visible');
+
+        return chart;
+      } else {
+        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'visible');
+        container.selectAll('.nv-noData').style('visibility', 'hidden');
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Scales
+
+      x = multibar.xScale();
+      y = multibar.yScale();
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]);
+      const gEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend')
+        .append('g');
+      const g = wrap.select('g');
+
+      gEnter.append('g').attr('class', 'nv-x nv-axis');
+      gEnter.append('g').attr('class', 'nv-y nv-axis');
+      gEnter.append('g').attr('class', 'nv-barsWrap');
+      gEnter.append('g').attr('class', 'nv-legendWrap');
+      gEnter.append('g').attr('class', 'nv-controlsWrap');
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Legend
+
+      if (showLegend) {
+        legend.width(availableWidth - controlWidth());
+
+        if (multibar.barColor()) {
+          data.forEach((series, i) => {
+            series.color = d3v3
+              .rgb('#ccc')
+              .darker(i * 1.5)
+              .toString();
+          });
+        }
+
+        g.select('.nv-legendWrap')
+          .datum(data)
+          .call(legend);
+
+        if (legend.height() > 50) {
+          g.select('.nv-legendWrap').style('visibility', 'hidden');
+        } else {
+          g.select('.nv-legendWrap').style('visibility', 'visible');
+          if (margin.top !== legend.height()) {
+            margin.top = legend.height();
+            availableHeight =
+              (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
+          }
+        }
+
+        g.select('.nv-legendWrap').attr(
+          'transform',
+          'translate(' + controlWidth() + ',' + -margin.top + ')'
+        );
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Controls
+      const controlsData = [
+        { key: 'Grouped', disabled: multibar.stacked() },
+        { key: 'Stacked', disabled: !multibar.stacked() }
+      ];
+
+      if (showControls) {
+        controls.width(controlWidth()).color(['#444', '#444', '#444']);
+        g.select('.nv-controlsWrap')
+          .datum(controlsData)
+          .attr('transform', 'translate(0,' + -margin.top + ')')
+          .call(controls);
+      }
+
+      //------------------------------------------------------------
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      if (rightAlignYAxis) {
+        g.select('.nv-y.nv-axis').attr('transform', 'translate(' + availableWidth + ',0)');
+      }
+
+      //------------------------------------------------------------
+      // Main Chart Component(s)
+
+      multibar
+        .disabled(
+          data.map(series => {
+            return series.disabled;
+          })
+        )
+        .width(availableWidth)
+        .height(availableHeight)
+        .color(
+          data
+            .map((d, i) => {
+              return d.color || color(d, i);
+            })
+            .filter((d, i) => {
+              return !data[i].disabled;
+            })
+        );
+
+      selectBars = multibar.selectBars;
+
+      const barsWrap = g.select('.nv-barsWrap').datum(
+        data.filter(d => {
+          return !d.disabled;
+        })
+      );
+
+      barsWrap.transition().call(multibar);
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Axes
+
+      if (showXAxis) {
+        xAxis
+          .scale(x)
+          .ticks(availableWidth / 100)
+          .tickSize(-availableHeight, 0);
+
+        g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')');
+        g.select('.nv-x.nv-axis')
+          .transition()
+          .call(xAxis);
+
+        const xTicks = g.select('.nv-x.nv-axis > g').selectAll('g');
+
+        xTicks.selectAll('line, text').style('opacity', 1);
+
+        if (staggerLabels) {
+          const getTranslate = function(x, y) {
+            return 'translate(' + x + ',' + y + ')';
+          };
+
+          const staggerUp = 5,
+            staggerDown = 17; //pixels to stagger by
+          // Issue #140
+          xTicks.selectAll('text').attr('transform', (d, i, j) => {
+            return getTranslate(0, j % 2 === 0 ? staggerUp : staggerDown);
+          });
+
+          const totalInBetweenTicks = d3v3.selectAll('.nv-x.nv-axis .nv-wrap g g text')[0].length;
+          g.selectAll('.nv-x.nv-axis .nv-axisMaxMin text').attr('transform', (d, i) => {
+            return getTranslate(
+              0,
+              i === 0 || totalInBetweenTicks % 2 !== 0 ? staggerDown : staggerUp
+            );
+          });
+        }
+
+        if (reduceXTicks) {
+          xTicks
+            .filter((d, i) => {
+              return i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0;
+            })
+            .selectAll('text, line')
+            .style('opacity', 0);
+        }
+
+        if (rotateLabels) {
+          xTicks
+            .selectAll('.tick text')
+            .attr('transform', 'rotate(' + rotateLabels + ' 0,0)')
+            .style('text-anchor', rotateLabels > 0 ? 'start' : 'end');
+        }
+
+        g.select('.nv-x.nv-axis')
+          .selectAll('g.nv-axisMaxMin text')
+          .style('opacity', 1);
+      }
+
+      if (showYAxis) {
+        yAxis
+          .scale(y)
+          .ticks(availableHeight / 36)
+          .tickSize(-availableWidth, 0);
+
+        g.select('.nv-y.nv-axis')
+          .transition()
+          .call(yAxis);
+      }
+
+      //------------------------------------------------------------
+
+      //============================================================
+      // Event Handling/Dispatching (in chart's scope)
+      //------------------------------------------------------------
+
+      legend.dispatch.on('stateChange', newState => {
+        state = newState;
+        dispatch.stateChange(state);
+        chart.update();
+      });
+
+      controls.dispatch.on('legendClick', d => {
+        if (!d.disabled) {
+          return;
+        }
+        controlsData.forEach(controlData => {
+          controlData.disabled = true;
+        });
+        d.disabled = false;
+
+        switch (d.key) {
+          case 'Grouped':
+            multibar.stacked(false);
+            break;
+          case 'Stacked':
+            multibar.stacked(true);
+            break;
+        }
+
+        state.stacked = multibar.stacked();
+        dispatch.stateChange(state);
+        if (onStateChange != null) {
+          onStateChange(state);
+        }
+
+        chart.update();
+      });
+
+      dispatch.on('tooltipShow', e => {
+        if (tooltips) {
+          showTooltip(e, that.parentNode);
+        }
+      });
+
+      // Update chart from a state object passed to event handler
+      dispatch.on('changeState', e => {
+        if (typeof e.disabled !== 'undefined') {
+          data.forEach((series, i) => {
+            series.disabled = e.disabled[i];
+          });
+
+          state.disabled = e.disabled;
+        }
+
+        if (typeof e.stacked !== 'undefined') {
+          multibar.stacked(e.stacked);
+          state.stacked = e.stacked;
+        }
+
+        chart.update();
+      });
+
+      //============================================================
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Event Handling/Dispatching (out of chart's scope)
+  //------------------------------------------------------------
+
+  multibar.dispatch.on('elementMouseover.tooltip', e => {
+    e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+    dispatch.tooltipShow(e);
+  });
+
+  multibar.dispatch.on('elementMouseout.tooltip', e => {
+    dispatch.tooltipHide(e);
+  });
+  dispatch.on('tooltipHide', () => {
+    if (tooltips) {
+      nv.tooltip.cleanup();
+    }
+  });
+
+  //============================================================
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  // expose chart's sub-components
+  chart.dispatch = dispatch;
+  chart.multibar = multibar;
+  chart.legend = legend;
+  chart.xAxis = xAxis;
+  chart.yAxis = yAxis;
+
+  d3v3.rebind(
+    chart,
+    multibar,
+    'x',
+    'y',
+    'xDomain',
+    'yDomain',
+    'xRange',
+    'yRange',
+    'forceX',
+    'forceY',
+    'clipEdge',
+    'id',
+    'stacked',
+    'stackOffset',
+    'delay',
+    'barColor',
+    'groupSpacing'
+  );
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    legend.color(color);
+    return chart;
+  };
+
+  chart.showControls = function(_) {
+    if (!arguments.length) {
+      return showControls;
+    }
+    showControls = _;
+    return chart;
+  };
+
+  chart.showLegend = function(_) {
+    if (!arguments.length) {
+      return showLegend;
+    }
+    showLegend = _;
+    return chart;
+  };
+
+  chart.showXAxis = function(_) {
+    if (!arguments.length) {
+      return showXAxis;
+    }
+    showXAxis = _;
+    return chart;
+  };
+
+  chart.showYAxis = function(_) {
+    if (!arguments.length) {
+      return showYAxis;
+    }
+    showYAxis = _;
+    return chart;
+  };
+
+  chart.rightAlignYAxis = function(_) {
+    if (!arguments.length) {
+      return rightAlignYAxis;
+    }
+    rightAlignYAxis = _;
+    yAxis.orient(_ ? 'right' : 'left');
+    return chart;
+  };
+
+  chart.reduceXTicks = function(_) {
+    if (!arguments.length) {
+      return reduceXTicks;
+    }
+    reduceXTicks = _;
+    return chart;
+  };
+
+  chart.rotateLabels = function(_) {
+    if (!arguments.length) {
+      return rotateLabels;
+    }
+    rotateLabels = _;
+    return chart;
+  };
+
+  chart.staggerLabels = function(_) {
+    if (!arguments.length) {
+      return staggerLabels;
+    }
+    staggerLabels = _;
+    return chart;
+  };
+
+  chart.tooltip = function(_) {
+    if (!arguments.length) {
+      return tooltip;
+    }
+    tooltip = _;
+    return chart;
+  };
+
+  chart.tooltips = function(_) {
+    if (!arguments.length) {
+      return tooltips;
+    }
+    tooltips = _;
+    return chart;
+  };
+
+  chart.tooltipContent = function(_) {
+    if (!arguments.length) {
+      return tooltip;
+    }
+    tooltip = _;
+    return chart;
+  };
+
+  chart.state = function(_) {
+    if (!arguments.length) {
+      return state;
+    }
+    state = _;
+    return chart;
+  };
+
+  chart.defaultState = function(_) {
+    if (!arguments.length) {
+      return defaultState;
+    }
+    defaultState = _;
+    return chart;
+  };
+
+  chart.noData = function(_) {
+    if (!arguments.length) {
+      return noData;
+    }
+    noData = _;
+    return chart;
+  };
+
+  chart.transitionDuration = function(_) {
+    if (!arguments.length) {
+      return transitionDuration;
+    }
+    transitionDuration = _;
+    return chart;
+  };
+
+  chart.selectBars = function(args) {
+    if (!arguments.length) {
+      return selectBars;
+    }
+    if (selectBars) {
+      selectBars(args);
+    }
+    return chart;
+  };
+
+  chart.onStateChange = function(_) {
+    if (!arguments.length) {
+      return onStateChange;
+    }
+    onStateChange = _;
+    return chart;
+  };
+
+  //============================================================
+
+  return chart;
+};

+ 589 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.growingPie.js

@@ -0,0 +1,589 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import $ from 'jquery';
+import d3v3 from 'd3v3';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.growingPie = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const margin = { top: 0, right: 0, bottom: 0, left: 0 };
+  let width = 500,
+    height = 500,
+    getX = function(d) {
+      return d.x;
+    },
+    getY = function(d) {
+      return d.y;
+    },
+    getDescription = function(d) {
+      return d.description;
+    },
+    id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
+    color = nv.utils.defaultColor(),
+    valueFormat = d3v3.format(',.2f'),
+    showLabels = true,
+    pieLabelsOutside = true,
+    donutLabelsOutside = false,
+    labelType = 'key',
+    labelThreshold = 0.02, //if slice percentage is under this, don't show label
+    donut = false,
+    labelSunbeamLayout = false,
+    startAngle = false,
+    endAngle = false,
+    donutRatio = 0.5,
+    selectSlices = null;
+
+  const dispatch = d3v3.dispatch(
+    'chartClick',
+    'elementClick',
+    'elementDblClick',
+    'elementMouseover',
+    'elementMouseout'
+  );
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      let availableWidth = width - margin.left - margin.right,
+        availableHeight = height - margin.top - margin.bottom,
+        radius = Math.min(availableWidth, availableHeight) / 2,
+        arcRadius = radius - radius / 5;
+      const container = d3v3.select(this);
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      //let wrap = container.selectAll('.nv-wrap.nv-pie').data([data]);
+      const wrap = container.selectAll('.nv-wrap.nv-pie').data(data);
+      const wrapEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-pie nv-chart-' + id);
+      const gEnter = wrapEnter.append('g');
+      const g = wrap.select('g');
+
+      gEnter.append('g').attr('class', 'nv-pie');
+      gEnter.append('g').attr('class', 'nv-pieLabels');
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+      g.select('.nv-pie').attr(
+        'transform',
+        'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'
+      );
+      g.select('.nv-pieLabels').attr(
+        'transform',
+        'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'
+      );
+
+      //------------------------------------------------------------
+
+      container.on('click', (d, i) => {
+        dispatch.chartClick({
+          data: d,
+          index: i,
+          pos: d3v3.event,
+          id: id
+        });
+      });
+
+      function updateVariables() {
+        availableWidth = width - margin.left - margin.right;
+        availableHeight = height - margin.top - margin.bottom;
+        radius = Math.min(availableWidth, availableHeight) / 2;
+        arcRadius = radius - radius / 5;
+      }
+
+      const arcNormal = function() {
+        updateVariables();
+        return d3v3.svg.arc().outerRadius(arcRadius);
+      };
+
+      const arcOver = function() {
+        updateVariables();
+        return d3v3.svg.arc().outerRadius(arcRadius + 10);
+      };
+
+      if (startAngle) {
+        arcNormal().startAngle(startAngle);
+      }
+      if (endAngle) {
+        arcNormal().endAngle(endAngle);
+      }
+      if (donut) {
+        arcNormal().innerRadius(radius * donutRatio);
+      }
+
+      // Setup the Pie chart and choose the data element
+      const pie = d3v3.layout
+        .pie()
+        .sort(null)
+        .value(d => {
+          return d.disabled ? 0 : getY(d);
+        });
+
+      const slices = wrap
+        .select('.nv-pie')
+        .selectAll('.nv-slice')
+        .data(pie)
+        .classed('selected', false);
+
+      const pieLabels = wrap
+        .select('.nv-pieLabels')
+        .selectAll('.nv-label')
+        .data(pie);
+
+      slices.exit().remove();
+      pieLabels.exit().remove();
+
+      selectSlices = function(selected) {
+        $(selected).each((cnt, item) => {
+          slices.each(function(d) {
+            if (
+              (typeof d.data.obj.from != 'undefined' && d.data.obj.from === item) ||
+              d.data.obj.value === item
+            ) {
+              d3v3.select(this).classed('selected', true);
+              d3v3
+                .select(this)
+                .select('path')
+                .transition()
+                .duration(100)
+                .attr('d', arcOver());
+            }
+          });
+        });
+      };
+
+      const ae = slices
+        .enter()
+        .append('g')
+        .attr('class', 'nv-slice')
+        .on('mouseover', function(d, i) {
+          d3v3
+            .select(this)
+            .select('path')
+            .transition()
+            .duration(100)
+            .attr('d', arcOver());
+          d3v3.select(this).classed('hover', true);
+          dispatch.elementMouseover({
+            label: getX(d.data),
+            value: getY(d.data),
+            point: d.data,
+            pointIndex: i,
+            pos: [d3v3.event.pageX, d3v3.event.pageY],
+            id: id
+          });
+        })
+        .on('mouseout', function(d, i) {
+          if (!d3v3.select(this).classed('selected')) {
+            d3v3
+              .select(this)
+              .select('path')
+              .transition()
+              .duration(100)
+              .attr('d', arcNormal());
+          }
+          d3v3.select(this).classed('hover', false);
+          dispatch.elementMouseout({
+            label: getX(d.data),
+            value: getY(d.data),
+            point: d.data,
+            index: i,
+            id: id
+          });
+        })
+        .on('click', function(d, i) {
+          d3v3
+            .select(this)
+            .select('path')
+            .transition()
+            .duration(100)
+            .attr('d', arcOver());
+          dispatch.elementClick({
+            label: getX(d.data),
+            value: getY(d.data),
+            point: d.data,
+            index: i,
+            pos: d3v3.event,
+            id: id
+          });
+          d3v3.event.stopPropagation();
+        })
+        .on('dblclick', function(d, i) {
+          d3v3
+            .select(this)
+            .select('path')
+            .transition()
+            .duration(100)
+            .attr('d', arcNormal());
+          dispatch.elementDblClick({
+            label: getX(d.data),
+            value: getY(d.data),
+            point: d.data,
+            index: i,
+            pos: d3v3.event,
+            id: id
+          });
+          d3v3.event.stopPropagation();
+        });
+
+      slices
+        .attr('fill', (d, i) => {
+          return d.data.color || color(d, i);
+        })
+        .attr('stroke', (d, i) => {
+          return d.data.color || color(d, i);
+        });
+
+      ae.append('path').each(function(d) {
+        this._current = d;
+      });
+
+      slices
+        .select('path')
+        .transition()
+        .attr('d', arcNormal())
+        .attrTween('d', arcTween);
+
+      if (showLabels) {
+        // This does the normal label
+        let labelsArc = d3v3.svg.arc().innerRadius(0);
+
+        if (pieLabelsOutside) {
+          labelsArc = arcNormal();
+        }
+
+        if (donutLabelsOutside) {
+          labelsArc = d3v3.svg.arc().outerRadius(d3v3.svg.arc().outerRadius());
+        }
+
+        pieLabels
+          .enter()
+          .append('g')
+          .classed('nv-label', true)
+          .each(function(d) {
+            if (d.value > 0) {
+              const group = d3v3.select(this);
+
+              group.attr('transform', d => {
+                if (labelSunbeamLayout) {
+                  d.outerRadius = arcRadius + 10; // Set Outer Coordinate
+                  d.innerRadius = arcRadius + 15; // Set Inner Coordinate
+                  let rotateAngle = ((d.startAngle + d.endAngle) / 2) * (180 / Math.PI);
+                  if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
+                    rotateAngle -= 90;
+                  } else {
+                    rotateAngle += 90;
+                  }
+                  return 'translate(' + labelsArc.centroid(d) + ') rotate(' + rotateAngle + ')';
+                } else {
+                  d.outerRadius = radius + 10; // Set Outer Coordinate
+                  d.innerRadius = radius + 15; // Set Inner Coordinate
+                  return 'translate(' + labelsArc.centroid(d) + ')';
+                }
+              });
+
+              group
+                .append('rect')
+                .style('stroke', '#fff')
+                .style('fill', '#fff')
+                .attr('rx', 3)
+                .attr('ry', 3);
+
+              group
+                .append('text')
+                .style(
+                  'text-anchor',
+                  labelSunbeamLayout
+                    ? (d.startAngle + d.endAngle) / 2 < Math.PI
+                      ? 'start'
+                      : 'end'
+                    : 'middle'
+                ) //center the text on it's origin or begin/end if orthogonal aligned
+                .style('fill', '#000');
+            }
+          });
+
+        const labelLocationHash = {};
+        const avgHeight = 14;
+        const avgWidth = 140;
+        const createHashKey = function(coordinates) {
+          return (
+            Math.floor(coordinates[0] / avgWidth) * avgWidth +
+            ',' +
+            Math.floor(coordinates[1] / avgHeight) * avgHeight
+          );
+        };
+        pieLabels.transition().attr('transform', d => {
+          if (d.value > 0) {
+            if (labelSunbeamLayout) {
+              d.outerRadius = arcRadius + 10; // Set Outer Coordinate
+              d.innerRadius = arcRadius + 15; // Set Inner Coordinate
+              let rotateAngle = ((d.startAngle + d.endAngle) / 2) * (180 / Math.PI);
+              if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
+                rotateAngle -= 90;
+              } else {
+                rotateAngle += 90;
+              }
+              return 'translate(' + labelsArc.centroid(d) + ') rotate(' + rotateAngle + ')';
+            } else {
+              d.outerRadius = radius + 10; // Set Outer Coordinate
+              d.innerRadius = radius + 15; // Set Inner Coordinate
+
+              /*
+                Overlapping pie labels are not good. What this attempts to do is, prevent overlapping.
+                Each label location is hashed, and if a hash collision occurs, we assume an overlap.
+                Adjust the label's y-position to remove the overlap.
+                */
+              const center = labelsArc.centroid(d);
+              const hashKey = createHashKey(center);
+              if (labelLocationHash[hashKey]) {
+                center[1] -= avgHeight;
+              }
+              labelLocationHash[createHashKey(center)] = true;
+              return 'translate(' + center + ')';
+            }
+          }
+        });
+        pieLabels
+          .select('.nv-label text')
+          .style('text-anchor', d => {
+            if (d.value > 0) {
+              if (labelSunbeamLayout) {
+                return (d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end'; //center the text on it's origin or begin/end if orthogonal aligned
+              } else {
+                return 'middle';
+              }
+            }
+          })
+          .text(d => {
+            if (d.value > 0) {
+              const percent = (d.endAngle - d.startAngle) / (2 * Math.PI);
+              const labelTypes = {
+                key: getX(d.data),
+                value: getY(d.data),
+                percent: d3v3.format('%')(percent)
+              };
+              return d.value && percent > labelThreshold ? labelTypes[labelType] : '';
+            } else {
+              return '';
+            }
+          });
+      }
+
+      function arcTween(a) {
+        a.endAngle = isNaN(a.endAngle) ? 0 : a.endAngle;
+        a.startAngle = isNaN(a.startAngle) ? 0 : a.startAngle;
+        if (!donut) {
+          a.innerRadius = 0;
+        }
+        const i = d3v3.interpolate(this._current, a);
+        this._current = i(0);
+        return function(t) {
+          return arcNormal()(i(t));
+        };
+      }
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  chart.dispatch = dispatch;
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.values = function() {
+    nv.log('pie.values() is no longer supported.');
+    return chart;
+  };
+
+  chart.x = function(_) {
+    if (!arguments.length) {
+      return getX;
+    }
+    getX = _;
+    return chart;
+  };
+
+  chart.y = function(_) {
+    if (!arguments.length) {
+      return getY;
+    }
+    getY = d3v3.functor(_);
+    return chart;
+  };
+
+  chart.description = function(_) {
+    if (!arguments.length) {
+      return getDescription;
+    }
+    getDescription = _;
+    return chart;
+  };
+
+  chart.showLabels = function(_) {
+    if (!arguments.length) {
+      return showLabels;
+    }
+    showLabels = _;
+    return chart;
+  };
+
+  chart.labelSunbeamLayout = function(_) {
+    if (!arguments.length) {
+      return labelSunbeamLayout;
+    }
+    labelSunbeamLayout = _;
+    return chart;
+  };
+
+  chart.donutLabelsOutside = function(_) {
+    if (!arguments.length) {
+      return donutLabelsOutside;
+    }
+    donutLabelsOutside = _;
+    return chart;
+  };
+
+  chart.pieLabelsOutside = function(_) {
+    if (!arguments.length) {
+      return pieLabelsOutside;
+    }
+    pieLabelsOutside = _;
+    return chart;
+  };
+
+  chart.labelType = function(_) {
+    if (!arguments.length) {
+      return labelType;
+    }
+    labelType = _;
+    labelType = labelType || 'key';
+    return chart;
+  };
+
+  chart.donut = function(_) {
+    if (!arguments.length) {
+      return donut;
+    }
+    donut = _;
+    return chart;
+  };
+
+  chart.donutRatio = function(_) {
+    if (!arguments.length) {
+      return donutRatio;
+    }
+    donutRatio = _;
+    return chart;
+  };
+
+  chart.startAngle = function(_) {
+    if (!arguments.length) {
+      return startAngle;
+    }
+    startAngle = _;
+    return chart;
+  };
+
+  chart.endAngle = function(_) {
+    if (!arguments.length) {
+      return endAngle;
+    }
+    endAngle = _;
+    return chart;
+  };
+
+  chart.id = function(_) {
+    if (!arguments.length) {
+      return id;
+    }
+    id = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    return chart;
+  };
+
+  chart.valueFormat = function(_) {
+    if (!arguments.length) {
+      return valueFormat;
+    }
+    valueFormat = _;
+    return chart;
+  };
+
+  chart.labelThreshold = function(_) {
+    if (!arguments.length) {
+      return labelThreshold;
+    }
+    labelThreshold = _;
+    return chart;
+  };
+
+  chart.selectSlices = function(args) {
+    if (!arguments.length) {
+      return selectSlices;
+    }
+    selectSlices(args);
+    return chart;
+  };
+  //============================================================
+
+  return chart;
+};

+ 141 - 106
desktop/core/src/desktop/static/desktop/js/nv.d3.growingPieChart.js → desktop/core/src/desktop/js/nvd3/nv.d3.growingPieChart.js

@@ -14,97 +14,100 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import d3v3 from 'd3v3';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
 nv.models.growingPieChart = function() {
-  "use strict";
+  'use strict';
   //============================================================
   // Public Variables with Default Settings
   //------------------------------------------------------------
 
-  var pie = nv.models.growingPie()
-    , legend = nv.models.legend()
-    ;
-
-  var margin = {top: 30, right: 20, bottom: 20, left: 20}
-    , width = null
-    , height = null
-    , showLegend = true
-    , color = nv.utils.defaultColor()
-    , tooltips = true
-    , tooltip = function(key, y, e, graph) {
-        return '<h3>' + key + '</h3>' +
-               '<p>' +  y + '</p>'
-      }
-    , state = {}
-    , defaultState = null
-    , noData = "No Data Available."
-    , selectSlices = null
-    , dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState')
-    ;
-
+  const pie = nv.models.growingPie(),
+    legend = nv.models.legend(),
+    margin = { top: 30, right: 20, bottom: 20, left: 20 };
+
+  let width = null,
+    height = null,
+    showLegend = true,
+    color = nv.utils.defaultColor(),
+    tooltips = true,
+    tooltip = function(key, y) {
+      return '<h3>' + key + '</h3>' + '<p>' + y + '</p>';
+    },
+    state = {},
+    defaultState = null,
+    noData = 'No Data Available.',
+    selectSlices = null;
+  const dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState');
   //============================================================
 
-
   //============================================================
   // Private Variables
   //------------------------------------------------------------
 
-  var showTooltip = function(e, offsetElement) {
-    var tooltipLabel = pie.description()(e.point) || pie.x()(e.point)
-    var left = e.pos[0] + ( (offsetElement && offsetElement.offsetLeft) || 0 ),
-        top = e.pos[1] + ( (offsetElement && offsetElement.offsetTop) || 0),
-        y = pie.valueFormat()(pie.y()(e.point)),
-        content = tooltip(tooltipLabel, y, e, chart);
+  const showTooltip = function(e, offsetElement) {
+    const tooltipLabel = pie.description()(e.point) || pie.x()(e.point);
+    const left = e.pos[0] + ((offsetElement && offsetElement.offsetLeft) || 0),
+      top = e.pos[1] + ((offsetElement && offsetElement.offsetTop) || 0),
+      y = pie.valueFormat()(pie.y()(e.point)),
+      content = tooltip(tooltipLabel, y, e, chart);
 
     nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
   };
 
   //============================================================
 
-
   function chart(selection) {
     selection.each(function(data) {
+      const container = d3v3.select(this);
 
-      var container = d3v3.select(this),
-          that = this;
+      const availableWidth =
+        (width || parseInt(container.style('width')) || 960) - margin.left - margin.right;
+      let availableHeight =
+        (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
 
-      var availableWidth = (width || parseInt(container.style('width')) || 960)
-                             - margin.left - margin.right,
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-
-      chart.update = function() { container.transition().call(chart); };
+      chart.update = function() {
+        container.transition().call(chart);
+      };
       chart.container = this;
 
       //set state.disabled
-      state.disabled = data.map(function(d) { return !!d.disabled });
+      state.disabled = data.map(d => {
+        return !!d.disabled;
+      });
 
       if (!defaultState) {
-        var key;
+        let key;
         defaultState = {};
         for (key in state) {
-          if (state[key] instanceof Array)
+          if (state[key] instanceof Array) {
             defaultState[key] = state[key].slice(0);
-          else
+          } else {
             defaultState[key] = state[key];
+          }
         }
       }
 
       //------------------------------------------------------------
       // Display No Data message if there's nothing to show.
 
-      var _allDataIsZero = true;
-      if (data){
-        data.forEach(function(obj){
-          if (obj.value > 0){
+      let _allDataIsZero = true;
+      if (data) {
+        data.forEach(obj => {
+          if (obj.value > 0) {
             _allDataIsZero = false;
           }
         });
       }
 
       if (!data || !data.length || _allDataIsZero) {
-        var noDataText = container.selectAll('.nv-noData').data([noData]);
+        const noDataText = container.selectAll('.nv-noData').data([noData]);
 
-        noDataText.enter().append('text')
+        noDataText
+          .enter()
+          .append('text')
           .attr('class', 'nvd3 nv-noData')
           .attr('dy', '-.7em')
           .style('text-anchor', 'middle');
@@ -112,7 +115,9 @@ nv.models.growingPieChart = function() {
         noDataText
           .attr('x', margin.left + availableWidth / 2)
           .attr('y', margin.top + availableHeight / 2)
-          .text(function(d) { return d });
+          .text(d => {
+            return d;
+          });
 
         container.selectAll('.nv-pieChart').style('visibility', 'hidden');
         container.selectAll('.nv-noData').style('visibility', 'visible');
@@ -125,63 +130,57 @@ nv.models.growingPieChart = function() {
 
       //------------------------------------------------------------
 
-
       //------------------------------------------------------------
       // Setup containers and skeleton of chart
 
-      var wrap = container.selectAll('g.nv-wrap.nv-pieChart').data([data]);
-      var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-pieChart').append('g');
-      var g = wrap.select('g');
+      const wrap = container.selectAll('g.nv-wrap.nv-pieChart').data([data]);
+      const gEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-pieChart')
+        .append('g');
+      const g = wrap.select('g');
 
       gEnter.append('g').attr('class', 'nv-pieWrap');
       gEnter.append('g').attr('class', 'nv-legendWrap');
 
       //------------------------------------------------------------
 
-
       //------------------------------------------------------------
       // Legend
 
       if (showLegend) {
-        legend
-          .width( availableWidth )
-          .key(pie.x());
+        legend.width(availableWidth).key(pie.x());
 
-        wrap.select('.nv-legendWrap')
-            .datum(data)
-            .call(legend);
+        wrap
+          .select('.nv-legendWrap')
+          .datum(data)
+          .call(legend);
 
         if (legend.height() > 50) {
           wrap.select('.nv-legendWrap').style('visibility', 'hidden');
-        }
-        else {
+        } else {
           wrap.select('.nv-legendWrap').style('visibility', 'visible');
-          if (margin.top != legend.height()) {
+          if (margin.top !== legend.height()) {
             margin.top = legend.height();
-            availableHeight = (height || parseInt(container.style('height')) || 400)
-              - margin.top - margin.bottom;
+            availableHeight =
+              (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
           }
         }
 
-        wrap.select('.nv-legendWrap')
-            .attr('transform', 'translate(0,' + (-margin.top) +')');
+        wrap.select('.nv-legendWrap').attr('transform', 'translate(0,' + -margin.top + ')');
       }
 
       //------------------------------------------------------------
 
-
       wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 
-
       //------------------------------------------------------------
       // Main Chart Component(s)
 
-      pie
-        .width(availableWidth)
-        .height(availableHeight);
+      pie.width(availableWidth).height(availableHeight);
 
-      var pieWrap = g.select('.nv-pieWrap')
-          .datum([data]);
+      const pieWrap = g.select('.nv-pieWrap').datum([data]);
 
       selectSlices = pie.selectSlices;
 
@@ -189,26 +188,24 @@ nv.models.growingPieChart = function() {
 
       //------------------------------------------------------------
 
-
       //============================================================
       // Event Handling/Dispatching (in chart's scope)
       //------------------------------------------------------------
 
-      legend.dispatch.on('stateChange', function(newState) {
+      legend.dispatch.on('stateChange', newState => {
         state = newState;
         dispatch.stateChange(state);
         chart.update();
       });
 
-      pie.dispatch.on('elementMouseout.tooltip', function(e) {
+      pie.dispatch.on('elementMouseout.tooltip', e => {
         dispatch.tooltipHide(e);
       });
 
       // Update chart from a state object passed to event handler
-      dispatch.on('changeState', function(e) {
-
+      dispatch.on('changeState', e => {
         if (typeof e.disabled !== 'undefined') {
-          data.forEach(function(series,i) {
+          data.forEach((series, i) => {
             series.disabled = e.disabled[i];
           });
 
@@ -219,8 +216,6 @@ nv.models.growingPieChart = function() {
       });
 
       //============================================================
-
-
     });
 
     return chart;
@@ -230,22 +225,25 @@ nv.models.growingPieChart = function() {
   // Event Handling/Dispatching (out of chart's scope)
   //------------------------------------------------------------
 
-  pie.dispatch.on('elementMouseover.tooltip', function(e) {
-    e.pos = [e.pos[0] +  margin.left, e.pos[1] + margin.top];
+  pie.dispatch.on('elementMouseover.tooltip', e => {
+    e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
     dispatch.tooltipShow(e);
   });
 
-  dispatch.on('tooltipShow', function(e) {
-    if (tooltips) showTooltip(e);
+  dispatch.on('tooltipShow', e => {
+    if (tooltips) {
+      showTooltip(e);
+    }
   });
 
-  dispatch.on('tooltipHide', function() {
-    if (tooltips) nv.tooltip.cleanup();
+  dispatch.on('tooltipHide', () => {
+    if (tooltips) {
+      nv.tooltip.cleanup();
+    }
   });
 
   //============================================================
 
-
   //============================================================
   // Expose Public Variables
   //------------------------------------------------------------
@@ -255,32 +253,56 @@ nv.models.growingPieChart = function() {
   chart.dispatch = dispatch;
   chart.pie = pie;
 
-  d3v3.rebind(chart, pie, 'valueFormat', 'values', 'x', 'y', 'description', 'id', 'showLabels', 'donutLabelsOutside', 'pieLabelsOutside', 'labelType', 'donut', 'donutRatio', 'labelThreshold');
+  d3v3.rebind(
+    chart,
+    pie,
+    'valueFormat',
+    'values',
+    'x',
+    'y',
+    'description',
+    'id',
+    'showLabels',
+    'donutLabelsOutside',
+    'pieLabelsOutside',
+    'labelType',
+    'donut',
+    'donutRatio',
+    'labelThreshold'
+  );
   chart.options = nv.utils.optionsFunc.bind(chart);
 
   chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
     margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
     return chart;
   };
 
   chart.width = function(_) {
-    if (!arguments.length) return width;
+    if (!arguments.length) {
+      return width;
+    }
     width = _;
     return chart;
   };
 
   chart.height = function(_) {
-    if (!arguments.length) return height;
+    if (!arguments.length) {
+      return height;
+    }
     height = _;
     return chart;
   };
 
   chart.color = function(_) {
-    if (!arguments.length) return color;
+    if (!arguments.length) {
+      return color;
+    }
     color = nv.utils.getColor(_);
     legend.color(color);
     pie.color(color);
@@ -288,49 +310,62 @@ nv.models.growingPieChart = function() {
   };
 
   chart.showLegend = function(_) {
-    if (!arguments.length) return showLegend;
+    if (!arguments.length) {
+      return showLegend;
+    }
     showLegend = _;
     return chart;
   };
 
   chart.tooltips = function(_) {
-    if (!arguments.length) return tooltips;
+    if (!arguments.length) {
+      return tooltips;
+    }
     tooltips = _;
     return chart;
   };
 
   chart.tooltipContent = function(_) {
-    if (!arguments.length) return tooltip;
+    if (!arguments.length) {
+      return tooltip;
+    }
     tooltip = _;
     return chart;
   };
 
   chart.state = function(_) {
-    if (!arguments.length) return state;
+    if (!arguments.length) {
+      return state;
+    }
     state = _;
     return chart;
   };
 
   chart.defaultState = function(_) {
-    if (!arguments.length) return defaultState;
+    if (!arguments.length) {
+      return defaultState;
+    }
     defaultState = _;
     return chart;
   };
 
   chart.noData = function(_) {
-    if (!arguments.length) return noData;
+    if (!arguments.length) {
+      return noData;
+    }
     noData = _;
     return chart;
   };
 
   chart.selectSlices = function(args) {
-    if (!arguments.length) return selectSlices;
+    if (!arguments.length) {
+      return selectSlices;
+    }
     selectSlices(args);
     return chart;
   };
 
   //============================================================
 
-
   return chart;
-}
+};

+ 380 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.legend.js

@@ -0,0 +1,380 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import d3v3 from 'd3v3';
+
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.legend = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const margin = { top: 5, right: 0, bottom: 5, left: 0 };
+  let width = 400,
+    height = 20,
+    getKey = function(d) {
+      return d.key;
+    },
+    color = nv.utils.defaultColor(),
+    align = true,
+    rightAlign = true,
+    updateState = true, //If true, legend will update data.disabled and trigger a 'stateChange' dispatch.
+    radioButtonMode = false; //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time)
+
+  const dispatch = d3v3.dispatch(
+    'legendClick',
+    'legendDblclick',
+    'legendMouseover',
+    'legendMouseout',
+    'stateChange'
+  );
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const availableWidth = width - margin.left - margin.right,
+        container = d3v3.select(this);
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-legend').data([data]);
+      wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-legend')
+        .append('g');
+      const g = wrap.select('g');
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      //------------------------------------------------------------
+
+      const series = g.selectAll('.nv-series').data(d => {
+        return d;
+      });
+      const seriesEnter = series
+        .enter()
+        .append('g')
+        .attr('class', 'nv-series')
+        .on('mouseover', (d, i) => {
+          dispatch.legendMouseover(d, i); //TODO: Make consistent with other event objects
+        })
+        .on('mouseout', (d, i) => {
+          dispatch.legendMouseout(d, i);
+        })
+        .on('click', (d, i) => {
+          dispatch.legendClick(d, i);
+          if (updateState) {
+            if (radioButtonMode) {
+              //Radio button mode: set every series to disabled,
+              //  and enable the clicked series.
+              data.forEach(series => {
+                series.disabled = true;
+              });
+              d.disabled = false;
+            } else {
+              d.disabled = !d.disabled;
+              if (
+                data.every(series => {
+                  return series.disabled;
+                })
+              ) {
+                //the default behavior of NVD3 legends is, if every single series
+                // is disabled, turn all series' back on.
+                data.forEach(series => {
+                  series.disabled = false;
+                });
+              }
+            }
+            dispatch.stateChange({
+              disabled: data.map(d => {
+                return !!d.disabled;
+              })
+            });
+          }
+        })
+        .on('dblclick', (d, i) => {
+          dispatch.legendDblclick(d, i);
+          if (updateState) {
+            //the default behavior of NVD3 legends, when double clicking one,
+            // is to set all other series' to false, and make the double clicked series enabled.
+            data.forEach(series => {
+              series.disabled = true;
+            });
+            d.disabled = false;
+            dispatch.stateChange({
+              disabled: data.map(d => {
+                return !!d.disabled;
+              })
+            });
+          }
+        });
+      seriesEnter
+        .append('circle')
+        .style('stroke-width', 2)
+        .attr('class', 'nv-legend-symbol')
+        .attr('r', 5)
+        .style('display', d => {
+          return d.checkbox ? 'none' : 'inline';
+        });
+
+      seriesEnter
+        .append('rect')
+        .style('stroke-width', 2)
+        .attr('class', 'nv-legend-symbol')
+        .attr('width', 10)
+        .attr('height', 10)
+        .attr('transform', 'translate(-5,-5)')
+        .style('display', d => {
+          return d.checkbox ? 'inline' : 'none';
+        });
+
+      seriesEnter
+        .append('text')
+        .attr('text-anchor', 'start')
+        .attr('class', 'nv-legend-text')
+        .attr('dy', '.32em')
+        .attr('dx', '8');
+      series.classed('disabled', d => {
+        return d.disabled;
+      });
+      series.exit().remove();
+      series
+        .select('circle')
+        .style('fill', (d, i) => {
+          return d.color || color(d, i);
+        })
+        .style('stroke', (d, i) => {
+          return d.color || color(d, i);
+        });
+      series
+        .select('rect')
+        .style('fill', (d, i) => {
+          return d.color || color(d, i);
+        })
+        .style('stroke', (d, i) => {
+          return d.color || color(d, i);
+        });
+      series.select('text').text(getKey);
+
+      //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option)
+
+      // NEW ALIGNING CODE, TODO: clean up
+      if (align) {
+        const seriesWidths = [];
+        series.each(function() {
+          const legendText = d3v3.select(this).select('text');
+          let nodeTextLength;
+          try {
+            nodeTextLength = legendText.getComputedTextLength();
+            // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead
+            if (nodeTextLength <= 0) {
+              throw Error();
+            }
+          } catch (e) {
+            nodeTextLength = nv.utils.calcApproxTextWidth(legendText);
+          }
+
+          seriesWidths.push(nodeTextLength + 28); // 28 is ~ the width of the circle plus some padding
+        });
+
+        let seriesPerRow = 0;
+        let legendWidth = 0;
+        let columnWidths = [];
+
+        while (legendWidth < availableWidth && seriesPerRow < seriesWidths.length) {
+          columnWidths[seriesPerRow] = seriesWidths[seriesPerRow];
+          legendWidth += seriesWidths[seriesPerRow++];
+        }
+        if (seriesPerRow === 0) {
+          seriesPerRow = 1;
+        } //minimum of one series per row
+
+        while (legendWidth > availableWidth && seriesPerRow > 1) {
+          columnWidths = [];
+          seriesPerRow--;
+
+          for (let k = 0; k < seriesWidths.length; k++) {
+            if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0)) {
+              columnWidths[k % seriesPerRow] = seriesWidths[k];
+            }
+          }
+
+          legendWidth = columnWidths.reduce((prev, cur) => {
+            return prev + cur;
+          });
+        }
+
+        const xPositions = [];
+        for (let i = 0, curX = 0; i < seriesPerRow; i++) {
+          xPositions[i] = curX;
+          curX += columnWidths[i];
+        }
+
+        series.attr('transform', (d, i) => {
+          return (
+            'translate(' +
+            xPositions[i % seriesPerRow] +
+            ',' +
+            (5 + Math.floor(i / seriesPerRow) * 20) +
+            ')'
+          );
+        });
+
+        //position legend as far right as possible within the total width
+        if (rightAlign) {
+          g.attr(
+            'transform',
+            'translate(' +
+              nv.utils.NaNtoZero(width - margin.right - legendWidth) +
+              ',' +
+              margin.top +
+              ')'
+          );
+        } else {
+          g.attr('transform', 'translate(0' + ',' + margin.top + ')');
+        }
+
+        height = margin.top + margin.bottom + Math.ceil(seriesWidths.length / seriesPerRow) * 20;
+      } else {
+        let ypos = 5,
+          newxpos = 5,
+          maxwidth = 0,
+          xpos;
+        series.attr('transform', function() {
+          const length =
+            d3v3
+              .select(this)
+              .select('text')
+              .node()
+              .getComputedTextLength() + 28;
+          xpos = newxpos;
+
+          if (width < margin.left + margin.right + xpos + length) {
+            newxpos = xpos = 5;
+            ypos += 20;
+          }
+
+          newxpos += length;
+          if (newxpos > maxwidth) {
+            maxwidth = newxpos;
+          }
+
+          return 'translate(' + xpos + ',' + ypos + ')';
+        });
+
+        //position legend as far right as possible within the total width
+        g.attr(
+          'transform',
+          'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')'
+        );
+
+        height = margin.top + margin.bottom + ypos + 15;
+      }
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  chart.dispatch = dispatch;
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.key = function(_) {
+    if (!arguments.length) {
+      return getKey;
+    }
+    getKey = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    return chart;
+  };
+
+  chart.align = function(_) {
+    if (!arguments.length) {
+      return align;
+    }
+    align = _;
+    return chart;
+  };
+
+  chart.rightAlign = function(_) {
+    if (!arguments.length) {
+      return rightAlign;
+    }
+    rightAlign = _;
+    return chart;
+  };
+
+  chart.updateState = function(_) {
+    if (!arguments.length) {
+      return updateState;
+    }
+    updateState = _;
+    return chart;
+  };
+
+  chart.radioButtonMode = function(_) {
+    if (!arguments.length) {
+      return radioButtonMode;
+    }
+    radioButtonMode = _;
+    return chart;
+  };
+
+  //============================================================
+
+  return chart;
+};

+ 1146 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.lineWithBrushChart.js

@@ -0,0 +1,1146 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import d3v3 from 'd3v3';
+
+import hueUtils from 'utils/hueUtils';
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.lineWithBrushChart = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const LABELS = {
+    SELECT: 'Enable selection'
+  };
+
+  const lines = nv.models.line(),
+    xAxis = nv.models.axis(),
+    yAxis = nv.models.axis(),
+    legend = nv.models.legend(),
+    controls = nv.models.legend(),
+    interactiveLayer = nv.interactiveGuideline(),
+    margin = { top: 30, right: 20, bottom: 50, left: 60 };
+  let brush = d3v3.svg.brush(),
+    color = nv.utils.defaultColor(),
+    width = null,
+    height = null,
+    showLegend = true,
+    showControls = true,
+    showXAxis = true,
+    showYAxis = true,
+    rightAlignYAxis = false,
+    useInteractiveGuideline = false,
+    tooltips = true,
+    tooltip = null,
+    displayValuesInLegend = false;
+  const tooltipSimple = function(value) {
+      return (
+        '<h3>' +
+        hueUtils.htmlEncode(value.key) +
+        '</h3>' +
+        '<p>' +
+        hueUtils.htmlEncode(value.x) +
+        '</p>'
+      );
+    },
+    tooltipMultiple = function(values) {
+      return (
+        '<h3>' +
+        hueUtils.htmlEncode(values[0] && values[0].x) +
+        '</h3>' +
+        values
+          .map(value => {
+            return (
+              '<p><span class="circle" style="background-color:' +
+              value.color +
+              '"></span><b>' +
+              hueUtils.htmlEncode(value.key) +
+              '</b> ' +
+              hueUtils.htmlEncode(value.y) +
+              '</p>'
+            );
+          })
+          .join('')
+      );
+    },
+    getX = function(d) {
+      return d.x;
+    }, // accessor to get the x value
+    getY = function(d) {
+      return d.y;
+    }, // accessor to get the y value;
+    controlWidth = function() {
+      return showControls ? (selectionHidden ? 240 : 300) : 0;
+    },
+    legendWidth = 175,
+    dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'brush');
+
+  let x,
+    y,
+    state = {},
+    defaultState = null,
+    noData = 'No Data Available.',
+    transitionDuration = 250,
+    extent,
+    selectionEnabled = false,
+    selectionHidden = false,
+    onSelectRange = null,
+    onStateChange = null,
+    onLegendChange = null,
+    onChartUpdate = null;
+  xAxis.orient('bottom').tickPadding(7);
+  yAxis.orient(rightAlignYAxis ? 'right' : 'left');
+
+  controls.updateState(false);
+
+  //============================================================
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  const showTooltip = function(e, offsetElement) {
+    let values;
+    if (!tooltip) {
+      values = (e.list || [e]).map(e => {
+        const x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
+          y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex));
+        return {
+          x: x,
+          y: y,
+          key:
+            (displayValuesInLegend &&
+              (e.point.obj.field || (e.point.obj.fq_fields && e.point.obj.fq_fields[0]))) ||
+            e.series.key,
+          color: e.series.color || color(e.series, e.point.series)
+        };
+      });
+    } else {
+      values = tooltip(
+        (e.list || [e]).map(e => {
+          const x = lines.x()(e.point, e.pointIndex),
+            y = lines.y()(e.point, e.pointIndex);
+          return {
+            x: x,
+            y: y,
+            key:
+              (displayValuesInLegend &&
+                (e.point.obj.field || (e.point.obj.fq_fields && e.point.obj.fq_fields[0]))) ||
+              e.series.key,
+            color: e.series.color || color(e.series, e.point.series)
+          };
+        })
+      );
+    }
+
+    const left = e.pos[0] + (offsetElement.offsetLeft || 0),
+      top = e.pos[1] + (offsetElement.offsetTop || 0),
+      content = displayValuesInLegend ? tooltipSimple(values[0]) : tooltipMultiple(values);
+
+    nv.tooltip.show([left, top], content, null, null, offsetElement);
+  };
+
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const container = d3v3.select(this),
+        that = this;
+
+      const availableWidth =
+          (width || parseInt(container.style('width')) || 960) - margin.left - margin.right,
+        availableChartWidth = Math.max(availableWidth - showLegend * legendWidth, 0),
+        availableHeight =
+          (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
+
+      chart.update = function() {
+        container
+          .transition()
+          .duration(transitionDuration)
+          .each('end', onChartUpdate)
+          .call(chart);
+        filteredData = data.filter(series => {
+          return !series.disabled;
+        });
+        if (selectionEnabled) {
+          enableBrush();
+        } else {
+          disableBrush();
+        }
+      };
+      chart.container = this;
+
+      //set state.disabled
+      state.disabled = data.map(d => {
+        return !!d.disabled;
+      });
+
+      if (!defaultState) {
+        let key;
+        defaultState = {};
+        for (key in state) {
+          if (state[key] instanceof Array) {
+            defaultState[key] = state[key].slice(0);
+          } else {
+            defaultState[key] = state[key];
+          }
+        }
+      }
+
+      //------------------------------------------------------------
+      // Display noData message if there's nothing to show.
+
+      if (
+        !data ||
+        !data.length ||
+        !data.filter(d => {
+          return d.values.length;
+        }).length
+      ) {
+        const noDataText = container.selectAll('.nv-noData').data([noData]);
+
+        noDataText
+          .enter()
+          .append('text')
+          .attr('class', 'nvd3 nv-noData')
+          .attr('dy', '-.7em')
+          .style('text-anchor', 'middle');
+
+        noDataText
+          .attr('x', margin.left + availableWidth / 2)
+          .attr('y', margin.top + availableHeight / 2)
+          .text(d => {
+            return d;
+          });
+
+        return chart;
+      } else {
+        container.selectAll('.nv-noData').remove();
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Scales
+
+      x = lines.xScale();
+      y = lines.yScale();
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]);
+      const gEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-lineChart')
+        .append('g');
+      const g = wrap.select('g');
+
+      gEnter.append('rect').style('opacity', 0);
+      gEnter.append('g').attr('class', 'nv-x nv-axis');
+      gEnter.append('g').attr('class', 'nv-y nv-axis');
+      gEnter.append('g').attr('class', 'nv-linesWrap');
+      // We put the legend in an another SVG to support scrolling
+      const legendDiv = d3v3.select(container.node().parentNode).select('div');
+      const legendSvg =
+        legendDiv.select('svg').size() === 0 ? legendDiv.append('svg') : legendDiv.select('svg');
+      legendSvg
+        .style('height', data.length * 20 + 6 + 'px')
+        .selectAll('g')
+        .remove();
+      const legendG = legendSvg.append('g').attr('class', 'nvd3 nv-wrap nv-legendWrap');
+      gEnter.append('g').attr('class', 'nv-interactive');
+      gEnter.append('g').attr('class', 'nv-controlsWrap');
+
+      g.select('rect')
+        .attr('width', availableChartWidth)
+        .attr('height', availableHeight > 0 ? availableHeight : 0);
+      //------------------------------------------------------------
+      // Legend
+
+      if (showLegend) {
+        legend.width(legendWidth / 2);
+        legend.height(availableHeight);
+        legend.rightAlign(false);
+        legend.margin({ top: 5, right: 0, left: 10, bottom: 0 });
+        data.forEach((series, i) => {
+          series.color = color(series, i);
+        });
+
+        try {
+          legendG
+            .datum(data)
+            .call(legend)
+            .selectAll('text')
+            .text(d => {
+              if (displayValuesInLegend) {
+                const addEllipsis = d.key && d.key.length > 12;
+                return d.key && d.key.substring(0, 12) + (addEllipsis ? '...' : '');
+              } else {
+                return d.key;
+              }
+            })
+            .append('title')
+            .text(d => {
+              return d.key;
+            });
+          if (displayValuesInLegend) {
+            legendG
+              .selectAll('g.nv-series')
+              .append('text')
+              .classed('nv-series-value', true)
+              .text(() => {
+                return '';
+              })
+              .attr('dx', 125)
+              .attr('dy', '.32em')
+              .attr('text-anchor', 'end')
+              .append('title')
+              .classed('nv-series-value', true)
+              .text(() => {
+                return '';
+              });
+          }
+        } catch (e) {}
+      }
+
+      const controlsData = [];
+      if (showControls) {
+        if (!selectionHidden) {
+          controlsData.push({ key: LABELS.SELECT, disabled: !selectionEnabled, checkbox: true });
+        }
+
+        controls.width(controlWidth()).color(['#444', '#444', '#444']);
+        g.select('.nv-controlsWrap')
+          .datum(controlsData)
+          .attr('transform', 'translate(0,' + -margin.top + ')')
+          .call(controls);
+      }
+
+      //------------------------------------------------------------
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      if (rightAlignYAxis) {
+        g.select('.nv-y.nv-axis').attr('transform', 'translate(' + availableChartWidth + ',0)');
+      }
+
+      //------------------------------------------------------------
+      // Main Chart Component(s)
+
+      //------------------------------------------------------------
+      //Set up interactive layer
+      if (useInteractiveGuideline) {
+        interactiveLayer
+          .width(availableChartWidth)
+          .height(availableHeight)
+          .margin({ left: margin.left, top: margin.top })
+          .svgContainer(container)
+          .xScale(x);
+        wrap.select('.nv-interactive').call(interactiveLayer);
+      }
+
+      let filteredData = data.filter(series => {
+        return !series.disabled;
+      });
+      lines
+        .width(availableChartWidth)
+        .height(availableHeight)
+        .color(
+          data
+            .map((d, i) => {
+              return d.color || color(d, i);
+            })
+            .filter((d, i) => {
+              return !data[i].disabled;
+            })
+        );
+
+      const linesWrap = g.select('.nv-linesWrap').datum(
+        data.filter(d => {
+          return !d.disabled;
+        })
+      );
+
+      linesWrap.transition().call(lines);
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Brush
+      let overlay;
+      if (selectionEnabled) {
+        enableBrush();
+        overlay = g.select('rect');
+        overlay.style('display', 'none');
+      } else {
+        disableBrush();
+        overlay = g.select('rect');
+        overlay
+          .style('display', 'inherit')
+          .attr('height', availableHeight)
+          .attr('width', availableWidth)
+          .on('mousemove', onMouseMove)
+          .on('mouseout', onMouseOut)
+          .on('click', onClick);
+      }
+
+      function enableBrush() {
+        if (!g) {
+          // Can happen if the state change before the charts has been created.
+          return;
+        }
+        brush
+          .x(x)
+          .on('brush', onBrush)
+          .on('brushend', onBrushEnd);
+        if (chart.brushDomain) {
+          const brushExtent = [
+            fGetNumericValue(chart.brushDomain[0]),
+            fGetNumericValue(chart.brushDomain[1])
+          ];
+          const isWholeDomain =
+            xAxis.scale()(chart.brushDomain[0]) < 10 &&
+            xAxis.scale()(chart.brushDomain[1]) >= xAxis.range()[1];
+          if (!isWholeDomain) {
+            // If brush is the whole domain, don't display brush
+            brush.extent(brushExtent);
+          } else {
+            brush.clear();
+          }
+        } else {
+          brush.clear();
+        }
+        let gBrush;
+        if (g.selectAll('.nv-brush')[0].length === 0) {
+          g.append('g').attr('class', 'nv-brushBackground');
+          g.append('g').attr('class', 'nv-x nv-brush');
+
+          const brushBG = g
+            .select('.nv-brushBackground')
+            .selectAll('g')
+            .data([chart.brushExtent || brush.extent()]);
+          const brushBGenter = brushBG.enter().append('g');
+
+          brushBGenter
+            .append('rect')
+            .attr('class', 'left')
+            .attr('x', 0)
+            .attr('y', 0)
+            .attr('height', availableHeight);
+
+          brushBGenter
+            .append('rect')
+            .attr('class', 'right')
+            .attr('x', 0)
+            .attr('y', 0)
+            .attr('height', availableHeight);
+
+          gBrush = g.select('.nv-x.nv-brush').call(brush);
+        } else {
+          g.selectAll('.nv-brush').attr('display', 'inline');
+          gBrush = g.select('.nv-x.nv-brush').call(brush);
+        }
+        gBrush
+          .selectAll('rect')
+          .attr('height', availableHeight)
+          .on('mousemove', onMouseMove)
+          .on('mouseout', onMouseOut);
+      }
+
+      function disableBrush() {
+        if (g) {
+          g.selectAll('.nv-brush').attr('display', 'none');
+        }
+      }
+
+      //------------------------------------------------------------
+      // Setup Axes
+
+      if (showXAxis) {
+        xAxis
+          .scale(x)
+          .ticks(availableChartWidth / 100)
+          .tickSize(-availableHeight, 0);
+
+        g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')');
+        g.select('.nv-x.nv-axis')
+          .transition()
+          .call(xAxis);
+      }
+
+      if (showYAxis) {
+        yAxis
+          .scale(y)
+          .ticks(availableHeight / 36)
+          .tickSize(-availableChartWidth, 0);
+
+        g.select('.nv-y.nv-axis')
+          .transition()
+          .call(yAxis);
+      }
+      //------------------------------------------------------------
+
+      //============================================================
+      // Event Handling/Dispatching (in chart's scope)
+      //------------------------------------------------------------
+
+      legend.dispatch.on('stateChange', newState => {
+        state = newState;
+        dispatch.stateChange(state);
+        if (onLegendChange) {
+          onLegendChange(state);
+        }
+        chart.update();
+      });
+
+      controls.dispatch.on('legendClick', d => {
+        if (typeof d.checkbox == 'undefined') {
+          if (!d.disabled) {
+            return;
+          }
+          controlsData.forEach(controlData => {
+            controlData.disabled = false;
+          });
+          d.disabled = false;
+        }
+
+        switch (d.key) {
+          case LABELS.SELECT:
+            selectionEnabled = !selectionEnabled;
+            break;
+        }
+        chart.update();
+      });
+
+      interactiveLayer.dispatch.on('elementMousemove', e => {
+        lines.clearHighlights();
+        let singlePoint,
+          pointIndex,
+          pointXLocation = undefined;
+        const allData = [];
+        data
+          .filter((series, i) => {
+            series.seriesIndex = i;
+            return !series.disabled;
+          })
+          .forEach((series, i) => {
+            pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+            lines.highlightPoint(i, pointIndex, true);
+            const point = series.values[pointIndex];
+            if (typeof point === 'undefined') {
+              return;
+            }
+            if (typeof singlePoint === 'undefined') {
+              singlePoint = point;
+            }
+            if (typeof pointXLocation === 'undefined') {
+              pointXLocation = chart.xScale()(chart.x()(point, pointIndex));
+            }
+            allData.push({
+              key: series.key,
+              value: chart.y()(point, pointIndex),
+              color: color(series, series.seriesIndex)
+            });
+          });
+        //Highlight the tooltip entry based on which point the mouse is closest to.
+        if (allData.length > 2) {
+          const yValue = chart.yScale().invert(e.mouseY);
+          const domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
+          const threshold = 0.03 * domainExtent;
+          const indexToHighlight = nv.nearestValueIndex(
+            allData.map(d => {
+              return d.value;
+            }),
+            yValue,
+            threshold
+          );
+          if (indexToHighlight !== null) {
+            allData[indexToHighlight].highlight = true;
+          }
+        }
+
+        const xValue = xAxis.tickFormat()(chart.x()());
+        interactiveLayer.tooltip
+          .position({ left: pointXLocation + margin.left, top: e.mouseY + margin.top })
+          .chartContainer(that.parentNode)
+          .enabled(tooltips)
+          .valueFormatter(d => {
+            return yAxis.tickFormat()(d);
+          })
+          .data({
+            value: xValue,
+            series: allData
+          })();
+
+        interactiveLayer.renderGuideLine(pointXLocation);
+      });
+
+      interactiveLayer.dispatch.on('elementMouseout', e => {
+        dispatch.tooltipHide();
+        lines.clearHighlights();
+      });
+
+      dispatch.on('tooltipShow', e => {
+        if (tooltips) {
+          showTooltip(e, that.parentNode);
+        }
+      });
+
+      dispatch.on('changeState', e => {
+        if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) {
+          data.forEach((series, i) => {
+            series.disabled = e.disabled[i];
+          });
+
+          state.disabled = e.disabled;
+        }
+
+        chart.update();
+      });
+
+      //============================================================
+
+      function onBrush() {
+        chart.brushExtent = brush.empty() ? null : brush.extent();
+        extent = brush.empty() ? x.domain() : brush.extent();
+
+        dispatch.brush({ extent: extent, brush: brush });
+      }
+
+      function fGetNumericValue(o) {
+        return o instanceof Date ? o.getTime() : o;
+      }
+
+      function onBrushEnd() {
+        const closest = function() {
+          if (!data[0].values.length) {
+            return [];
+          }
+          const xDate = x.invert(d3v3.mouse(this)[0]);
+
+          const distances = {};
+          let min = Number.MAX_VALUE;
+          let next = -Number.MAX_VALUE;
+          let diff;
+          let i, j;
+          for (j = 0; j < data.length; j++) {
+            for (i = 0; i < data[j].values.length; i++) {
+              diff = xDate - fGetNumericValue(data[j].values[i].x);
+              if (diff >= 0 && diff < min) {
+                min = diff;
+              } else if (diff < 0 && diff > next) {
+                next = diff;
+              }
+              if (!distances[diff]) {
+                distances[diff] = [];
+              }
+              distances[diff].push(data[j].values[i]);
+            }
+          }
+          if (distances[min][0].x_end) {
+            return [distances[min][0].x, distances[min][0].x_end];
+          } else if (distances[min] !== undefined && distances[next] !== undefined) {
+            const _from =
+              distances[min][0].x < distances[next][0].x
+                ? distances[min][0].x
+                : distances[next][0].x;
+            const _to =
+              distances[min][0].x < distances[next][0].x
+                ? distances[next][0].x
+                : distances[min][0].x;
+            return [_from, _to];
+          } else {
+            return [];
+          }
+        };
+
+        chart.brushExtent = extent = brush.empty() ? closest.call(this) : brush.extent();
+
+        if (onSelectRange) {
+          onSelectRange(fGetNumericValue(extent[0]), fGetNumericValue(extent[1]));
+        }
+      }
+
+      function getElByMouse() {
+        const xy = d3v3.mouse(this);
+        const px = x.invert(xy[0]);
+        if (!filteredData.length || !filteredData[0].values.length) {
+          return null;
+        }
+        let minx = Math.abs(filteredData[0].values[0].x - px);
+        const distances = {};
+        const py = y.invert(xy[1]);
+        let i, j, diff;
+        // Find closest on x axis
+        for (j = 0; j < filteredData.length; j++) {
+          for (i = 0; i < filteredData[j].values.length; i++) {
+            diff = Math.abs(fGetNumericValue(filteredData[j].values[i].x) - px);
+            if (!distances[diff]) {
+              distances[diff] = [];
+            }
+            filteredData[j].values[i].seriesKey = filteredData[j].key;
+            distances[diff].push(filteredData[j].values[i]);
+            if (diff < minx) {
+              minx = diff;
+            }
+          }
+        }
+        // Find series with y axis
+        let miny = Number.MAX_VALUE;
+        const distancesy = {};
+        for (i = 0; i < distances[minx].length; i++) {
+          diff = Math.abs(distances[minx][i].y - py);
+          if (!distancesy[diff]) {
+            distancesy[diff] = [];
+          }
+          distancesy[diff].push(distances[minx][i]);
+          if (diff < miny) {
+            miny = diff;
+          }
+        }
+        return distancesy[miny];
+      }
+
+      function onMouseMove() {
+        const el = getElByMouse.call(this);
+        // If we're mousing over a circle that doesn't have class hover, set class and dispatch mouseover
+        const target = container
+          .selectAll('g.nv-wrap.nv-lineChart circle:not(.hover)')
+          .filter(rect => {
+            return (
+              el &&
+              el.some(d => {
+                return (
+                  fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) &&
+                  d.series === rect.series
+                );
+              })
+            );
+          });
+
+        if (el && el.length && displayValuesInLegend) {
+          const legendG = legendSvg.select('.nvd3.nv-wrap.nv-legendWrap');
+          const elBySerie = el.reduce((elBySerie, el) => {
+            elBySerie[el.seriesKey] = el;
+            return elBySerie;
+          }, {});
+          legendG
+            .selectAll('g.nv-series text.nv-series-value')
+            .text(d => {
+              if (elBySerie[d.key]) {
+                const value = yAxis.tickFormat()(d.values[elBySerie[d.key].index].y) + '';
+                const addEllipsis = value.length > 5;
+                return value && (addEllipsis ? '...' : '') + value.substring(value.length - 5);
+              } else {
+                return '';
+              }
+            })
+            .append('title')
+            .text(d => {
+              if (elBySerie[d.key]) {
+                return yAxis.tickFormat()(d.values[elBySerie[d.key].index].y);
+              } else {
+                return '';
+              }
+            });
+        }
+        // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
+        const others = container.selectAll('g.nv-wrap.nv-lineChart circle.hover').filter(rect => {
+          return (
+            !el ||
+            !el.some(d => {
+              return (
+                fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) &&
+                d.series === rect.series
+              );
+            })
+          );
+        });
+        if (others.size()) {
+          others.classed('hover', false).each((d, i) => {
+            lines.dispatch.elementMouseout({
+              value: getY(d),
+              point: d,
+              series: filteredData[d.series],
+              pointIndex: i,
+              seriesIndex: d.series,
+              e: d3v3.event
+            });
+          });
+        }
+        if (target.size()) {
+          const e = d3v3.event; // Keep reference to event for setTimeout
+          setTimeout(() => {
+            // Delayed to conteract conflict with elementMouseout.
+            target.classed('hover', true);
+            let max,
+              maxi = 0;
+            target.each((d, i) => {
+              if (isNaN(max) || max < getY(d)) {
+                max = getY(d);
+                maxi = i;
+              }
+            });
+            d3v3.select(target[0][maxi]).each(d => {
+              lines.dispatch.elementMouseover({
+                value: getY(d),
+                point: d,
+                series: filteredData[d.series],
+                pos: [x(getX(d)), y(getY(d))],
+                pointIndex: -1,
+                seriesIndex: d.series,
+                list: el.map(d => {
+                  return {
+                    value: getY(d),
+                    point: d,
+                    series: filteredData[d.series],
+                    pos: [x(getX(d)), y(getY(d))],
+                    pointIndex: -1,
+                    seriesIndex: d.series
+                  };
+                }),
+                e: e
+              });
+            });
+          });
+        }
+      }
+
+      function onMouseOut() {
+        const others = container.selectAll('g.nv-wrap.nv-lineChart circle.hover');
+        if (others.size()) {
+          others.classed('hover', false).each(d => {
+            lines.dispatch.elementMouseout({
+              value: getY(d),
+              point: d,
+              series: filteredData[d.series],
+              pointIndex: d.index,
+              seriesIndex: d.series,
+              e: d3v3.event
+            });
+          });
+        }
+      }
+
+      function onClick() {
+        const el = getElByMouse.call(this);
+        const d = el[0];
+        lines.dispatch.elementClick({
+          value: getY(d),
+          point: d,
+          series: filteredData[d.series],
+          pointIndex: d.index,
+          seriesIndex: d.series,
+          e: d3v3.event
+        });
+      }
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Event Handling/Dispatching (out of chart's scope)
+  //------------------------------------------------------------
+
+  lines.dispatch.on('elementMouseover.tooltip', e => {
+    e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+    dispatch.tooltipShow(e);
+  });
+
+  lines.dispatch.on('elementMouseout.tooltip', e => {
+    dispatch.tooltipHide(e);
+  });
+
+  dispatch.on('tooltipHide', () => {
+    if (tooltips) {
+      nv.tooltip.cleanup();
+    }
+  });
+
+  //============================================================
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  // expose chart's sub-components
+  chart.dispatch = dispatch;
+  chart.lines = lines;
+  chart.legend = legend;
+  chart.xAxis = xAxis;
+  chart.yAxis = yAxis;
+  chart.xScale = lines.xScale;
+  chart.interactiveLayer = interactiveLayer;
+
+  d3v3.rebind(
+    chart,
+    lines,
+    'defined',
+    'isArea',
+    'x',
+    'y',
+    'size',
+    'xScale',
+    'yScale',
+    'xDomain',
+    'yDomain',
+    'xRange',
+    'yRange',
+    'forceX',
+    'forceY',
+    'interactive',
+    'clipEdge',
+    'clipVoronoi',
+    'useVoronoi',
+    'id',
+    'interpolate'
+  );
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    legend.color(color);
+    return chart;
+  };
+
+  chart.showControls = function(_) {
+    if (!arguments.length) {
+      return showControls;
+    }
+    showControls = _;
+    return chart;
+  };
+
+  chart.showLegend = function(_) {
+    if (!arguments.length) {
+      return showLegend;
+    }
+    showLegend = _;
+    return chart;
+  };
+
+  chart.showXAxis = function(_) {
+    if (!arguments.length) {
+      return showXAxis;
+    }
+    showXAxis = _;
+    return chart;
+  };
+
+  chart.showYAxis = function(_) {
+    if (!arguments.length) {
+      return showYAxis;
+    }
+    showYAxis = _;
+    return chart;
+  };
+
+  chart.rightAlignYAxis = function(_) {
+    if (!arguments.length) {
+      return rightAlignYAxis;
+    }
+    rightAlignYAxis = _;
+    yAxis.orient(_ ? 'right' : 'left');
+    return chart;
+  };
+
+  chart.useInteractiveGuideline = function(_) {
+    if (!arguments.length) {
+      return useInteractiveGuideline;
+    }
+    useInteractiveGuideline = _;
+    if (_ === true) {
+      chart.interactive(false);
+      chart.useVoronoi(false);
+    }
+    return chart;
+  };
+
+  chart.tooltips = function(_) {
+    if (!arguments.length) {
+      return tooltips;
+    }
+    tooltips = _;
+    return chart;
+  };
+
+  chart.tooltipContent = function(_) {
+    if (!arguments.length) {
+      return tooltip;
+    }
+    tooltip = _;
+    return chart;
+  };
+
+  chart.state = function(_) {
+    if (!arguments.length) {
+      return state;
+    }
+    state = _;
+    return chart;
+  };
+
+  chart.defaultState = function(_) {
+    if (!arguments.length) {
+      return defaultState;
+    }
+    defaultState = _;
+    return chart;
+  };
+
+  chart.noData = function(_) {
+    if (!arguments.length) {
+      return noData;
+    }
+    noData = _;
+    return chart;
+  };
+
+  chart.transitionDuration = function(_) {
+    if (!arguments.length) {
+      return transitionDuration;
+    }
+    transitionDuration = _;
+    return chart;
+  };
+
+  chart.enableSelection = function() {
+    selectionEnabled = true;
+    return chart;
+  };
+
+  chart.disableSelection = function() {
+    selectionEnabled = false;
+    return chart;
+  };
+
+  chart.isSelectionEnabled = function() {
+    return selectionEnabled;
+  };
+
+  chart.hideSelection = function() {
+    selectionHidden = true;
+    return chart;
+  };
+
+  chart.showSelection = function() {
+    selectionHidden = false;
+    return chart;
+  };
+
+  chart.onSelectRange = function(_) {
+    if (!arguments.length) {
+      return onSelectRange;
+    }
+    onSelectRange = _;
+    return chart;
+  };
+
+  chart.onChartUpdate = function(_) {
+    if (!arguments.length) {
+      return onChartUpdate;
+    }
+    onChartUpdate = _;
+    return chart;
+  };
+
+  chart.onStateChange = function(_) {
+    if (!arguments.length) {
+      return onStateChange;
+    }
+    onStateChange = _;
+    return chart;
+  };
+
+  chart.onLegendChange = function(_) {
+    if (!arguments.length) {
+      return onLegendChange;
+    }
+    onLegendChange = _;
+    return chart;
+  };
+
+  chart.displayValuesInLegend = function(_) {
+    if (!arguments.length) {
+      return displayValuesInLegend;
+    }
+    displayValuesInLegend = _;
+    return chart;
+  };
+
+  chart.brush = function(_) {
+    if (!arguments.length) {
+      return brush;
+    }
+    brush = _;
+    return chart;
+  };
+
+  chart.selectBars = function(args) {
+    if (!arguments.length) {
+      return chart.brushDomain;
+    }
+    if (args && args.rangeValues) {
+      chart.brushDomain = [args.rangeValues[0].from, args.rangeValues[0].to];
+    } else {
+      chart.brushDomain = null;
+    }
+    return chart;
+  };
+
+  //============================================================
+
+  return chart;
+};

+ 1275 - 0
desktop/core/src/desktop/js/nvd3/nv.d3.multiBarWithBrushChart.js

@@ -0,0 +1,1275 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import d3v3 from 'd3v3';
+
+import hueUtils from 'utils/hueUtils';
+import nv from 'ext/nv.d3.1.1.15b.custom';
+
+nv.models.multiBarWithBrushChart = function() {
+  'use strict';
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  const LABELS = {
+    STACKED: 'Stacked',
+    GROUPED: 'Grouped',
+    SELECT: 'Enable selection'
+  };
+
+  const multibar = nv.models.growingMultiBar(),
+    xAxis = nv.models.axis(),
+    yAxis = nv.models.axis(),
+    legend = nv.models.legend(),
+    controls = nv.models.legend(),
+    margin = { top: 30, right: 20, bottom: 50, left: 60 };
+  let brush = d3v3.svg.brush(),
+    width = null,
+    height = null,
+    color = nv.utils.defaultColor(),
+    showControls = true,
+    showLegend = true,
+    showXAxis = true,
+    showYAxis = true,
+    rightAlignYAxis = false,
+    reduceXTicks = true, // if false a tick will show for every data point
+    staggerLabels = false,
+    rotateLabels = 0,
+    tooltips = true,
+    tooltip = null,
+    minTickWidth = 60,
+    displayValuesInLegend = false,
+    tooltipContent = null,
+    x, //can be accessed via chart.xScale()
+    y, //can be accessed via chart.yScale()
+    state = { stacked: false, selectionEnabled: false },
+    defaultState = null,
+    noData = 'No Data Available.';
+  const tooltipSimple = function(value) {
+      return (
+        '<h3>' +
+        hueUtils.htmlEncode(value.key) +
+        '</h3>' +
+        '<p>' +
+        hueUtils.htmlEncode(value.x) +
+        '</p>'
+      );
+    },
+    tooltipMultiple = function(values) {
+      return (
+        '<h3>' +
+        hueUtils.htmlEncode(values[0] && values[0].x) +
+        '</h3>' +
+        values
+          .map(value => {
+            return (
+              '<p><span class="circle" style="background-color:' +
+              value.color +
+              '"></span><b>' +
+              hueUtils.htmlEncode(value.key) +
+              '</b> ' +
+              hueUtils.htmlEncode(value.y) +
+              '</p>'
+            );
+          })
+          .join('')
+      );
+    },
+    getX = function(d) {
+      return d.x;
+    }, // accessor to get the x value
+    getY = function(d) {
+      return d.y;
+    }, // accessor to get the y value
+    dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'brush'),
+    controlWidth = function() {
+      return showControls ? (selectionHidden ? 240 : 300) : 0;
+    },
+    legendWidth = 175;
+  let transitionDuration = 250,
+    extent,
+    selectionEnabled = false,
+    selectionHidden = false,
+    stackedHidden = false,
+    onSelectRange = null,
+    onStateChange = null,
+    onLegendChange = null,
+    onChartUpdate = null,
+    selectedBars = null,
+    selectBars = null;
+  multibar.stacked(false);
+  xAxis
+    .orient('bottom')
+    .tickPadding(7)
+    .highlightZero(true)
+    .showMaxMin(false)
+    .tickFormat(d => {
+      return d;
+    });
+  yAxis.orient(rightAlignYAxis ? 'right' : 'left').tickFormat(d3v3.format(',.1f'));
+
+  controls.updateState(false);
+  //============================================================
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  const showTooltip = function(e, offsetElement) {
+    let values;
+    if (!tooltipContent) {
+      values = (e.list || [e]).map(e => {
+        const x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
+          y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex));
+        return {
+          x: x,
+          y: y,
+          key:
+            (displayValuesInLegend &&
+              (e.point.obj.field || (e.point.obj.fq_fields && e.point.obj.fq_fields[0]))) ||
+            e.series.key,
+          color: e.series.color || color(e.series, e.point.series)
+        };
+      });
+    } else {
+      values = tooltipContent(
+        (e.list || [e]).map(e => {
+          const x = multibar.x()(e.point, e.pointIndex),
+            y = multibar.y()(e.point, e.pointIndex);
+          return {
+            x: x,
+            y: y,
+            key:
+              (displayValuesInLegend &&
+                (e.point.obj.field || (e.point.obj.fq_fields && e.point.obj.fq_fields[0]))) ||
+              e.series.key,
+            color: e.series.color || color(e.series, e.point.series)
+          };
+        })
+      );
+    }
+
+    const left = e.pos[0] + (offsetElement.offsetLeft || 0),
+      top = e.pos[1] + (offsetElement.offsetTop || 0),
+      content = displayValuesInLegend ? tooltipSimple(values[0]) : tooltipMultiple(values);
+
+    nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+  };
+
+  //============================================================
+
+  function chart(selection) {
+    selection.each(function(data) {
+      const container = d3v3.select(this),
+        that = this;
+
+      const availableWidth =
+          (width || parseInt(container.style('width')) || 960) - margin.left - margin.right,
+        availableChartWidth = Math.max(availableWidth - showLegend * legendWidth, 0),
+        availableHeight =
+          (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;
+
+      chart.recommendedTicks = function() {
+        return Math.floor(availableWidth / minTickWidth);
+      };
+      chart.update = function() {
+        container
+          .transition()
+          .duration(transitionDuration)
+          .each('end', onChartUpdate)
+          .call(chart);
+        filteredData = data.filter(series => {
+          return !series.disabled;
+        });
+        if (selectionEnabled) {
+          enableBrush();
+        } else {
+          disableBrush();
+        }
+      };
+      chart.container = this;
+
+      //set state.disabled
+      state.disabled = data.map(d => {
+        return !!d.disabled;
+      });
+
+      if (!defaultState) {
+        let key;
+        defaultState = {};
+        for (key in state) {
+          if (state[key] instanceof Array) {
+            defaultState[key] = state[key].slice(0);
+          } else {
+            defaultState[key] = state[key];
+          }
+        }
+      }
+      //------------------------------------------------------------
+      // Display noData message if there's nothing to show.
+
+      if (
+        !data ||
+        !data.length ||
+        !data.filter(d => {
+          return d.values.length;
+        }).length
+      ) {
+        const noDataText = container.selectAll('.nv-noData').data([noData]);
+
+        noDataText
+          .enter()
+          .append('text')
+          .attr('class', 'nvd3 nv-noData')
+          .attr('dy', '-.7em')
+          .style('text-anchor', 'middle');
+
+        noDataText
+          .attr('x', margin.left + availableWidth / 2)
+          .attr('y', margin.top + availableHeight / 2)
+          .text(d => {
+            return d;
+          });
+
+        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'hidden');
+        container.selectAll('.nv-noData').style('visibility', 'visible');
+
+        return chart;
+      } else {
+        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'visible');
+        container.selectAll('.nv-noData').style('visibility', 'hidden');
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Scales
+
+      x = multibar.xScale();
+      y = multibar.yScale();
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      const wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]);
+      const gEnter = wrap
+        .enter()
+        .append('g')
+        .attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend')
+        .append('g');
+      const g = wrap.select('g');
+
+      gEnter.append('rect').style('opacity', 0);
+      gEnter.append('g').attr('class', 'nv-x nv-axis');
+      gEnter.append('g').attr('class', 'nv-y nv-axis');
+      gEnter.append('g').attr('class', 'nv-barsWrap');
+      // We put the legend in an another SVG to support scrolling
+      const legendDiv = d3v3.select(container.node().parentNode).select('div');
+      const legendSvg =
+        legendDiv.select('svg').size() === 0 ? legendDiv.append('svg') : legendDiv.select('svg');
+      legendSvg
+        .style('height', data.length * 20 + 6 + 'px')
+        .selectAll('g')
+        .remove();
+      const legendG = legendSvg.append('g').attr('class', 'nvd3 nv-wrap nv-legendWrap');
+      gEnter.append('g').attr('class', 'nv-controlsWrap');
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Legend
+
+      if (showLegend) {
+        legend.width(legendWidth / 2);
+        legend.height(availableHeight);
+        legend.rightAlign(false);
+        legend.margin({ top: 5, right: 0, left: 10, bottom: 0 });
+        if (multibar.barColor()) {
+          data.forEach((series, i) => {
+            series.color = d3v3
+              .rgb('#ccc')
+              .darker(i * 1.5)
+              .toString();
+          });
+        } else {
+          data.forEach((series, i) => {
+            series.color = color(series, i);
+          });
+        }
+
+        try {
+          legendG
+            .datum(data)
+            .call(legend)
+            .selectAll('text')
+            .text(d => {
+              const value = d.key && d.key + '';
+              if (displayValuesInLegend) {
+                const addEllipsis = value && value.length > 12;
+                return value && value.substring(0, 12) + (addEllipsis ? '...' : '');
+              } else {
+                return value;
+              }
+            })
+            .append('title')
+            .text(d => {
+              return d.key;
+            });
+          if (displayValuesInLegend) {
+            legendG
+              .selectAll('g.nv-series')
+              .append('text')
+              .classed('nv-series-value', true)
+              .text(() => {
+                return '';
+              })
+              .attr('dx', 125)
+              .attr('dy', '.32em')
+              .attr('text-anchor', 'end')
+              .append('title')
+              .text(() => {
+                return '';
+              });
+          }
+        } catch (e) {}
+      }
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Controls
+
+      let controlsData = [];
+      if (showControls) {
+        if (!stackedHidden) {
+          controlsData.push({ key: LABELS.GROUPED, disabled: multibar.stacked() });
+          controlsData.push({ key: LABELS.STACKED, disabled: !multibar.stacked() });
+        }
+
+        if (!selectionHidden) {
+          controlsData.push({
+            key: LABELS.SELECT,
+            disabled: !selectionEnabled,
+            checkbox: selectionEnabled
+          });
+        }
+
+        controls.width(controlWidth()).color(['#444', '#444', '#444']);
+        g.select('.nv-controlsWrap')
+          .datum(controlsData)
+          .attr('transform', 'translate(0,' + -margin.top + ')')
+          .call(controls);
+      }
+
+      //------------------------------------------------------------
+
+      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      if (rightAlignYAxis) {
+        g.select('.nv-y.nv-axis').attr('transform', 'translate(' + availableChartWidth + ',0)');
+      }
+
+      //------------------------------------------------------------
+      // Main Chart Component(s)
+      let filteredData = data.filter(series => {
+        return !series.disabled;
+      });
+      multibar
+        .disabled(
+          data.map(series => {
+            return series.disabled;
+          })
+        )
+        .width(availableChartWidth)
+        .height(availableHeight)
+        .color(
+          data
+            .map((d, i) => {
+              return d.color || color(d, i);
+            })
+            .filter((d, i) => {
+              return !data[i].disabled;
+            })
+        );
+
+      selectBars = multibar.selectBars;
+
+      const barsWrap = g.select('.nv-barsWrap').datum(
+        data.filter(d => {
+          return !d.disabled;
+        })
+      );
+
+      barsWrap.transition().call(multibar);
+
+      //------------------------------------------------------------
+
+      //------------------------------------------------------------
+      // Setup Brush
+      let overlay;
+      if (selectionEnabled) {
+        enableBrush();
+        overlay = g.select('rect');
+        overlay.style('display', 'none');
+      } else {
+        disableBrush();
+        overlay = g.select('rect');
+        overlay
+          .style('display', 'inherit')
+          .attr('height', availableHeight)
+          .attr('width', availableWidth)
+          .on('mousemove', onMouseMove)
+          .on('mouseout', onMouseOut)
+          .on('click', onClick);
+      }
+      if (selectBars && selectedBars) {
+        selectBars(selectedBars);
+      }
+
+      function enableBrush() {
+        if (!g) {
+          // Can happen if the state change before the charts has been created.
+          return;
+        }
+        brush
+          .x(x)
+          .on('brush', onBrush)
+          .on('brushstart', onBrushStart)
+          .on('brushend', onBrushEnd);
+        if (chart.brushDomain) {
+          const selection = fromSelection(chart.brushDomain);
+          if (!selection.isWholeDomain) {
+            // If brush is the whole domain, don't display brush
+            brush.extent(fromSelection(chart.brushDomain).range);
+          } else {
+            brush.clear();
+          }
+        } else {
+          brush.clear();
+        }
+        let gBrush;
+
+        if (g.selectAll('.nv-brush')[0].length === 0) {
+          g.append('g').attr('class', 'nv-brushBackground');
+          g.append('g').attr('class', 'nv-x nv-brush');
+
+          const brushBG = g
+            .select('.nv-brushBackground')
+            .selectAll('g')
+            .data([chart.brushExtent || brush.extent()]);
+          const brushBGenter = brushBG.enter().append('g');
+
+          brushBGenter
+            .append('rect')
+            .attr('class', 'left')
+            .attr('x', 0)
+            .attr('y', 0)
+            .attr('height', availableHeight);
+
+          brushBGenter
+            .append('rect')
+            .attr('class', 'right')
+            .attr('x', 0)
+            .attr('y', 0)
+            .attr('height', availableHeight);
+
+          gBrush = g.select('.nv-x.nv-brush').call(brush);
+        } else {
+          g.selectAll('.nv-brush').attr('display', 'inline');
+          gBrush = g.select('.nv-x.nv-brush').call(brush);
+        }
+        gBrush
+          .selectAll('rect')
+          .attr('height', availableHeight)
+          .on('mousemove', onMouseMove)
+          .on('mouseout', onMouseOut);
+      }
+
+      function disableBrush() {
+        try {
+          g.selectAll('.nv-brush').attr('display', 'none');
+        } catch (e) {}
+      }
+
+      //------------------------------------------------------------
+      // Setup Axes
+
+      if (showXAxis) {
+        const tickSkip = () => Math.ceil(minTickWidth / xAxis.rangeBand());
+
+        xAxis
+          .scale(x)
+          .tickValues(
+            x.domain().filter((d, i) => {
+              return reduceXTicks && !(i % tickSkip());
+            })
+          )
+          .tickSize(-availableHeight, 0);
+
+        g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')');
+        g.select('.nv-x.nv-axis')
+          .transition()
+          .call(xAxis);
+
+        const xTicks = g.selectAll('.nv-x.nv-axis g.tick');
+
+        xTicks.selectAll('line, text').style('opacity', 1);
+
+        if (staggerLabels) {
+          const getTranslate = function(x, y) {
+            return 'translate(' + x + ',' + y + ')';
+          };
+
+          const rangeBand = x.rangeBand();
+
+          const staggerUp = 5,
+            staggerDown = 17; //pixels to stagger by
+          // Issue #140
+          xTicks.selectAll('text').attr('transform', function(d, i, j) {
+            const self = d3v3.select(this);
+            let textLength = self.node().getComputedTextLength(),
+              text = self.text();
+            while (textLength > rangeBand && text.length > 0) {
+              text = text.slice(0, -1);
+              self.text(text + '...');
+              textLength = self.node().getComputedTextLength();
+            }
+            return getTranslate(0, j % 2 === 0 ? staggerUp : staggerDown);
+          });
+
+          const totalInBetweenTicks = d3v3.selectAll('.nv-x.nv-axis .nv-wrap g g text')[0].length;
+          g.selectAll('.nv-x.nv-axis .nv-axisMaxMin text').attr('transform', (d, i) => {
+            return getTranslate(
+              0,
+              i === 0 || totalInBetweenTicks % 2 !== 0 ? staggerDown : staggerUp
+            );
+          });
+        }
+        if (rotateLabels) {
+          xTicks
+            .selectAll('.tick text')
+            .attr('transform', 'rotate(' + rotateLabels + ' 0,0)')
+            .style('text-anchor', rotateLabels > 0 ? 'start' : 'end');
+        }
+
+        g.select('.nv-x.nv-axis')
+          .selectAll('g.nv-axisMaxMin text')
+          .style('opacity', 1);
+      }
+
+      if (showYAxis) {
+        yAxis
+          .scale(y)
+          .ticks(availableHeight / 36)
+          .tickSize(-availableChartWidth, 0);
+
+        g.select('.nv-y.nv-axis')
+          .transition()
+          .call(yAxis);
+      }
+
+      //------------------------------------------------------------
+
+      //============================================================
+      // Event Handling/Dispatching (in chart's scope)
+      //------------------------------------------------------------
+
+      legend.dispatch.on('stateChange', newState => {
+        state = newState;
+        dispatch.stateChange(state);
+        if (onLegendChange != null) {
+          onLegendChange(state);
+        }
+        chart.update();
+      });
+
+      controls.dispatch.on('legendClick', d => {
+        if (typeof d.checkbox == 'undefined') {
+          if (!d.disabled) {
+            return;
+          }
+          controlsData = controlsData.map(s => {
+            s.disabled = true;
+            return s;
+          });
+          d.disabled = false;
+        }
+
+        switch (d.key) {
+          case LABELS.GROUPED:
+            multibar.stacked(false);
+            break;
+          case LABELS.STACKED:
+            multibar.stacked(true);
+            break;
+          case LABELS.SELECT:
+            selectionEnabled = !selectionEnabled;
+            break;
+        }
+
+        state.stacked = multibar.stacked();
+        state.selectionEnabled = selectionEnabled;
+        if (onStateChange != null) {
+          onStateChange(state);
+        }
+        dispatch.stateChange(state);
+        chart.update();
+      });
+
+      dispatch.on('tooltipShow', e => {
+        showTooltip(e, that.parentNode);
+      });
+
+      // Update chart from a state object passed to event handler
+      dispatch.on('changeState', e => {
+        if (typeof e.disabled !== 'undefined') {
+          data.forEach((series, i) => {
+            series.disabled = e.disabled[i];
+          });
+
+          state.disabled = e.disabled;
+        }
+
+        if (typeof e.stacked !== 'undefined') {
+          multibar.stacked(e.stacked);
+          state.stacked = e.stacked;
+        }
+
+        chart.update();
+      });
+
+      //============================================================
+      function fGetNumericValue(o) {
+        return o instanceof Date ? o.getTime() : o;
+      }
+
+      function onBrush() {
+        chart.brushExtent = brush.empty() ? null : brush.extent();
+        extent = brush.empty() ? x.domain() : brush.extent();
+
+        dispatch.brush({ extent: extent, brush: brush });
+      }
+
+      function onBrushStart() {
+        gEnter
+          .select('.nv-brush')
+          .select('.extent')
+          .style('display', 'block');
+      }
+
+      function onBrushEnd() {
+        extent = brush.empty() ? [d3v3.mouse(this)[0], d3v3.mouse(this)[0]] : brush.extent();
+        const _leftEdges = x.range();
+        const _width = x.rangeBand() + multibar.groupSpacing() * x.rangeBand();
+        let _l, _j;
+        for (_l = 0; extent[0] > _leftEdges[_l] + _width; _l++) {}
+        _l = typeof x.domain()[_l] !== 'undefined' ? _l : 0;
+        const _from = x.domain()[_l];
+
+        for (_j = 0; extent[1] > _leftEdges[_j] + _width; _j++) {}
+        const _to =
+          typeof x.domain()[_j + 1] !== 'undefined'
+            ? x.domain()[_j + 1]
+            : filteredData[0].values[filteredData[0].values.length - 1].x_end;
+        const range = [
+          x.range()[_l],
+          typeof x.range()[_j + 1] !== 'undefined' ? x.range()[_j + 1] : x.range()[_j] + _width
+        ];
+        brush.extent((chart.brushExtent = range));
+        g.select('.nv-x.nv-brush').call(brush);
+        if (onSelectRange != null) {
+          if (_from > _to) {
+            onSelectRange(_to, _from);
+          } else {
+            onSelectRange(_from, _to);
+          }
+        }
+      }
+
+      function getElByMouse(coords, allSeries) {
+        const xy = d3v3.mouse(this);
+        const extent = coords || xy[0];
+        let _l;
+        const _width = x.rangeBand();
+        const _leftEdges = x.range();
+        for (_l = 0; extent >= _leftEdges[_l]; _l++) {}
+        _l = Math.max(_l - 1, 0);
+        const value = fGetNumericValue(x.domain()[_l]);
+        let values = [];
+        let i, j;
+        if (allSeries) {
+          for (j = 0; j < filteredData.length; j++) {
+            for (i = 0; i < filteredData[j].values.length; i++) {
+              if (fGetNumericValue(getX(filteredData[j].values[i])) === value) {
+                values.push(filteredData[j].values[i]);
+              }
+            }
+          }
+        } else if (!multibar.stacked()) {
+          const serieIndex = Math.floor(
+            Math.min(extent - _leftEdges[_l], _width - 0.001) / (_width / filteredData.length)
+          ); // Math.min(extent - _leftEdges[_l], _width - 0.001) to handle the padding at the end. Would it make sense to remove the padding?
+          let i;
+          if (serieIndex < 0) {
+            return null;
+          }
+          for (i = 0; i < filteredData[serieIndex].values.length; i++) {
+            if (fGetNumericValue(getX(filteredData[serieIndex].values[i])) === value) {
+              values.push(filteredData[serieIndex].values[i]);
+              break;
+            }
+          }
+        } else {
+          // serieIndex depends on the y position of the bar
+          // y(getY(d) + (multibar.stacked() ? d.y0 : 0)
+          // get all series for the x value
+          const py = Math.round(y.invert(xy[1]));
+          let mindy = Number.MAX_VALUE;
+          const distances = {};
+          for (j = 0; j < filteredData.length; j++) {
+            for (i = 0; i < filteredData[j].values.length; i++) {
+              if (fGetNumericValue(getX(filteredData[j].values[i])) === value) {
+                if (py >= filteredData[j].values[i].y0 && py <= filteredData[j].values[i].y1) {
+                  values.push(filteredData[j].values[i]);
+                } else {
+                  const ym =
+                    filteredData[j].values[i].y0 +
+                    (filteredData[j].values[i].y1 - filteredData[j].values[i].y0) / 2;
+                  const dy = Math.abs(py - ym);
+                  if (!distances[dy]) {
+                    distances[dy] = [];
+                  }
+                  distances[dy].push(filteredData[j].values[i]);
+                  if (dy < mindy) {
+                    mindy = dy;
+                  }
+                }
+              }
+            }
+          }
+          if (!values.length) {
+            values = distances[mindy];
+          }
+        }
+        return values;
+      }
+
+      function fromSelection(selection) {
+        const _width = x.rangeBand() + multibar.groupSpacing() * x.rangeBand();
+        const _leftEdges = x.domain();
+        if (!_leftEdges.length) {
+          return null;
+        }
+        let _l, _j;
+        const isDescending = _leftEdges[0] < _leftEdges[1];
+        if (!isDescending) {
+          selection = [Math.max(selection[0], selection[1]), Math.min(selection[0], selection[1])];
+        }
+        if (isDescending) {
+          for (_l = 0; selection[0] >= _leftEdges[_l]; _l++) {}
+        } else {
+          for (_l = _leftEdges.length - 1; selection[0] > _leftEdges[_l]; _l--) {}
+        }
+
+        _l =
+          x.range()[_l + typeof (isDescending ? -1 : 0)] !== 'undefined'
+            ? _l + (isDescending ? -1 : 0)
+            : isDescending
+            ? _leftEdges.length - 1
+            : 0;
+        const _fromRange = typeof x.range()[_l] !== 'undefined' ? x.range()[_l] : 0;
+
+        if (isDescending) {
+          for (_j = 0; selection[1] > _leftEdges[_j]; _j++) {}
+        } else {
+          for (_j = _leftEdges.length - 1; selection[1] > _leftEdges[_j]; _j--) {}
+        }
+        const _toRange =
+          typeof x.range()[_j] !== 'undefined'
+            ? x.range()[_j]
+            : x.range()[_leftEdges.length - 1] + _width;
+        return {
+          range: [_fromRange, _fromRange === _toRange ? _fromRange + x.rangeBand() : _toRange],
+          isWholeDomain:
+            selection[0] <= _leftEdges[0] && selection[1] >= _leftEdges[_leftEdges.length - 1]
+        };
+      }
+
+      function onMouseMove() {
+        const el = getElByMouse.call(this);
+        // If we're mousing over a rectangle that doesn't have class hover, set class and dispatch mouseover
+        const target = container
+          .selectAll('g.nv-wrap.nv-multiBarWithLegend rect:not(.hover)')
+          .filter(rect => {
+            return (
+              el &&
+              el.some(d => {
+                return (
+                  fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) &&
+                  d.series === rect.series
+                );
+              })
+            );
+          });
+
+        if (el && el.length && displayValuesInLegend) {
+          const legendG = legendSvg.select('.nvd3.nv-wrap.nv-legendWrap');
+          const elBySerie = el.reduce((elBySerie, el) => {
+            elBySerie[el.seriesKey] = el;
+            return elBySerie;
+          }, {});
+          legendG
+            .selectAll('g.nv-series text.nv-series-value')
+            .text(d => {
+              if (elBySerie[d.key]) {
+                const value = yAxis.tickFormat()(d.values[elBySerie[d.key].index].y) + '';
+                const addEllipsis = value.length > 5;
+                return value && (addEllipsis ? '...' : '') + value.substring(value.length - 5);
+              } else {
+                return '';
+              }
+            })
+            .append('title')
+            .text(d => {
+              if (elBySerie[d.key]) {
+                return yAxis.tickFormat()(d.values[elBySerie[d.key].index].y);
+              } else {
+                return '';
+              }
+            });
+        }
+
+        // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
+        const others = container
+          .selectAll('g.nv-wrap.nv-multiBarWithLegend rect.hover')
+          .filter(rect => {
+            return (
+              !el ||
+              !el.some(d => {
+                return (
+                  fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) &&
+                  d.series === rect.series
+                );
+              })
+            );
+          });
+        if (others.size()) {
+          others.classed('hover', false).each((d, i) => {
+            multibar.dispatch.elementMouseout({
+              value: getY(d, i),
+              point: d,
+              series: filteredData[d.series],
+              pointIndex: i,
+              seriesIndex: d.series,
+              e: d3v3.event
+            });
+          });
+        }
+        if (target.size()) {
+          const e = d3v3.event; // Keep reference to event for setTimeout
+          setTimeout(() => {
+            // Delayed to conteract conflict with elementMouseout.
+            target.classed('hover', true);
+            let max,
+              maxi = 0;
+            target.each((d, i) => {
+              if (isNaN(max) || max < getY(d)) {
+                max = getY(d);
+                maxi = i;
+              }
+            });
+            const width = x.rangeBand();
+            d3v3.select(target[0][maxi]).each((d, i) => {
+              multibar.dispatch.elementMouseover({
+                value: getY(d),
+                point: d,
+                series: filteredData[d.series],
+                pos: [x(getX(d)) + width * 0.5, y(getY(d) + (multibar.stacked() ? d.y0 : 0))],
+                pointIndex: i,
+                seriesIndex: d.series,
+                list: el.map(d => {
+                  return {
+                    value: getY(d),
+                    point: d,
+                    series: filteredData[d.series],
+                    pos: [x(getX(d)) + width * 0.5, y(getY(d) + (multibar.stacked() ? d.y0 : 0))],
+                    pointIndex: -1,
+                    seriesIndex: d.series
+                  };
+                }),
+                e: e
+              });
+            });
+          }, 0);
+        }
+      }
+
+      function onMouseOut() {
+        const others = container.selectAll('g.nv-wrap.nv-multiBarWithLegend rect.hover');
+        if (others.size()) {
+          others.classed('hover', false).each((d, i) => {
+            multibar.dispatch.elementMouseout({
+              value: getY(d, i),
+              point: d,
+              series: filteredData[d.series],
+              pointIndex: d.index,
+              seriesIndex: d.series,
+              e: d3v3.event
+            });
+          });
+        }
+      }
+
+      function onClick() {
+        const el = getElByMouse.call(this);
+        const d = el[0];
+        multibar.dispatch.elementClick({
+          value: getY(d),
+          point: d,
+          series: filteredData[d.series],
+          pointIndex: d.index,
+          seriesIndex: d.series,
+          e: d3v3.event
+        });
+      }
+    });
+
+    return chart;
+  }
+
+  //============================================================
+  // Event Handling/Dispatching (out of chart's scope)
+  //------------------------------------------------------------
+
+  multibar.dispatch.on('elementMouseover.tooltip', e => {
+    e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+    dispatch.tooltipShow(e);
+  });
+
+  multibar.dispatch.on('elementMouseout.tooltip', e => {
+    dispatch.tooltipHide(e);
+  });
+  dispatch.on('tooltipHide', () => {
+    if (tooltips) {
+      nv.tooltip.cleanup();
+    }
+  });
+
+  //============================================================
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  // expose chart's sub-components
+  chart.dispatch = dispatch;
+  chart.multibar = multibar;
+  chart.legend = legend;
+  chart.xAxis = xAxis;
+  chart.yAxis = yAxis;
+  chart.xScale = multibar.xScale;
+  chart.LABELS = LABELS;
+
+  d3v3.rebind(
+    chart,
+    multibar,
+    'x',
+    'y',
+    'xDomain',
+    'yDomain',
+    'xRange',
+    'yRange',
+    'forceX',
+    'forceY',
+    'clipEdge',
+    'id',
+    'stacked',
+    'stackOffset',
+    'delay',
+    'barColor',
+    'groupSpacing'
+  );
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+
+  chart.margin = function(_) {
+    if (!arguments.length) {
+      return margin;
+    }
+    margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+    margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+    return chart;
+  };
+
+  chart.width = function(_) {
+    if (!arguments.length) {
+      return width;
+    }
+    width = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) {
+      return height;
+    }
+    height = _;
+    return chart;
+  };
+
+  chart.color = function(_) {
+    if (!arguments.length) {
+      return color;
+    }
+    color = nv.utils.getColor(_);
+    legend.color(color);
+    return chart;
+  };
+
+  chart.showControls = function(_) {
+    if (!arguments.length) {
+      return showControls;
+    }
+    showControls = _;
+    return chart;
+  };
+
+  chart.showLegend = function(_) {
+    if (!arguments.length) {
+      return showLegend;
+    }
+    showLegend = _;
+    return chart;
+  };
+
+  chart.showXAxis = function(_) {
+    if (!arguments.length) {
+      return showXAxis;
+    }
+    showXAxis = _;
+    return chart;
+  };
+
+  chart.showYAxis = function(_) {
+    if (!arguments.length) {
+      return showYAxis;
+    }
+    showYAxis = _;
+    return chart;
+  };
+
+  chart.rightAlignYAxis = function(_) {
+    if (!arguments.length) {
+      return rightAlignYAxis;
+    }
+    rightAlignYAxis = _;
+    yAxis.orient(_ ? 'right' : 'left');
+    return chart;
+  };
+
+  chart.reduceXTicks = function(_) {
+    if (!arguments.length) {
+      return reduceXTicks;
+    }
+    reduceXTicks = _;
+    return chart;
+  };
+
+  chart.rotateLabels = function(_) {
+    if (!arguments.length) {
+      return rotateLabels;
+    }
+    rotateLabels = _;
+    return chart;
+  };
+
+  chart.staggerLabels = function(_) {
+    if (!arguments.length) {
+      return staggerLabels;
+    }
+    staggerLabels = _;
+    return chart;
+  };
+
+  chart.tooltip = function(_) {
+    if (!arguments.length) {
+      return tooltip;
+    }
+    tooltip = _;
+    return chart;
+  };
+
+  chart.tooltips = function(_) {
+    if (!arguments.length) {
+      return tooltips;
+    }
+    tooltips = _;
+    return chart;
+  };
+
+  chart.tooltipContent = function(_) {
+    if (!arguments.length) {
+      return tooltipContent;
+    }
+    tooltipContent = _;
+    return chart;
+  };
+
+  chart.state = function(_) {
+    if (!arguments.length) {
+      return state;
+    }
+    state = _;
+    return chart;
+  };
+
+  chart.defaultState = function(_) {
+    if (!arguments.length) {
+      return defaultState;
+    }
+    defaultState = _;
+    return chart;
+  };
+
+  chart.noData = function(_) {
+    if (!arguments.length) {
+      return noData;
+    }
+    noData = _;
+    return chart;
+  };
+
+  chart.transitionDuration = function(_) {
+    if (!arguments.length) {
+      return transitionDuration;
+    }
+    transitionDuration = _;
+    return chart;
+  };
+
+  chart.enableSelection = function() {
+    selectionEnabled = true;
+    return chart;
+  };
+
+  chart.disableSelection = function() {
+    selectionEnabled = false;
+    return chart;
+  };
+
+  chart.isSelectionEnabled = function() {
+    return selectionEnabled;
+  };
+
+  chart.hideSelection = function() {
+    selectionHidden = true;
+    return chart;
+  };
+
+  chart.showSelection = function() {
+    selectionHidden = false;
+    return chart;
+  };
+
+  chart.showStacked = function() {
+    stackedHidden = false;
+  };
+
+  chart.hideStacked = function() {
+    stackedHidden = true;
+  };
+
+  chart.onSelectRange = function(_) {
+    if (!arguments.length) {
+      return onSelectRange;
+    }
+    onSelectRange = _;
+    return chart;
+  };
+
+  chart.onStateChange = function(_) {
+    if (!arguments.length) {
+      return onStateChange;
+    }
+    onStateChange = _;
+    return chart;
+  };
+
+  chart.onLegendChange = function(_) {
+    if (!arguments.length) {
+      return onLegendChange;
+    }
+    onLegendChange = _;
+    return chart;
+  };
+
+  chart.onChartUpdate = function(_) {
+    if (!arguments.length) {
+      return onChartUpdate;
+    }
+    onChartUpdate = _;
+    return chart;
+  };
+
+  chart.minTickWidth = function(val) {
+    if (!arguments.length) {
+      return minTickWidth;
+    }
+    minTickWidth = val;
+    return chart;
+  };
+
+  chart.selectBars = function(args) {
+    if (!arguments.length) {
+      return selectBars;
+    }
+    if (args && args.rangeValues) {
+      chart.brushDomain = [args.rangeValues[0].from, args.rangeValues[0].to];
+    } else {
+      chart.brushDomain = null;
+    }
+    selectedBars = args;
+    if (selectBars) {
+      selectBars(args);
+    }
+    return chart;
+  };
+
+  chart.displayValuesInLegend = function(val) {
+    if (!arguments.length) {
+      return displayValuesInLegend;
+    }
+    displayValuesInLegend = val;
+    return chart;
+  };
+
+  chart.brush = function(val) {
+    if (!arguments.length) {
+      return brush;
+    }
+    brush = val;
+    return chart;
+  };
+
+  //============================================================
+
+  return chart;
+};

+ 2338 - 0
desktop/core/src/desktop/js/utils/hueGeo.js

@@ -0,0 +1,2338 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you 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.
+
+import $ from 'jquery';
+
+const NominatimAPI = function(options) {
+  this.BASE_URL = 'http://nominatim.openstreetmap.org/search?format=json';
+  this.limit = options && options.limit ? options.limit : 1;
+
+  this.lookupCity = function(city, callback) {
+    $.getJSON(
+      this.BASE_URL + '&city=' + city + '&limit=' + this.limit + '&json_callback=?',
+      data => {
+        callback(data);
+      }
+    );
+  };
+
+  this.lookupAddress = function(address, callback) {
+    $.getJSON(
+      this.BASE_URL + '&q=' + address + '&limit=' + this.limit + '&json_callback=?',
+      data => {
+        callback(data);
+      }
+    );
+  };
+};
+
+const HueGeo = {
+  ISO_3166: [
+    {
+      name: 'Afghanistan',
+      alpha2: 'AF',
+      alpha3: 'AFG',
+      'country-code': '004',
+      'iso_3166-2': 'ISO 3166-2:AF',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Åland Islands',
+      alpha2: 'AX',
+      alpha3: 'ALA',
+      'country-code': '248',
+      'iso_3166-2': 'ISO 3166-2:AX',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Albania',
+      alpha2: 'AL',
+      alpha3: 'ALB',
+      'country-code': '008',
+      'iso_3166-2': 'ISO 3166-2:AL',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Algeria',
+      alpha2: 'DZ',
+      alpha3: 'DZA',
+      'country-code': '012',
+      'iso_3166-2': 'ISO 3166-2:DZ',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'American Samoa',
+      alpha2: 'AS',
+      alpha3: 'ASM',
+      'country-code': '016',
+      'iso_3166-2': 'ISO 3166-2:AS',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Andorra',
+      alpha2: 'AD',
+      alpha3: 'AND',
+      'country-code': '020',
+      'iso_3166-2': 'ISO 3166-2:AD',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Angola',
+      alpha2: 'AO',
+      alpha3: 'AGO',
+      'country-code': '024',
+      'iso_3166-2': 'ISO 3166-2:AO',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Anguilla',
+      alpha2: 'AI',
+      alpha3: 'AIA',
+      'country-code': '660',
+      'iso_3166-2': 'ISO 3166-2:AI',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Antarctica',
+      alpha2: 'AQ',
+      alpha3: 'ATA',
+      'country-code': '010',
+      'iso_3166-2': 'ISO 3166-2:AQ'
+    },
+    {
+      name: 'Antigua and Barbuda',
+      alpha2: 'AG',
+      alpha3: 'ATG',
+      'country-code': '028',
+      'iso_3166-2': 'ISO 3166-2:AG',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Argentina',
+      alpha2: 'AR',
+      alpha3: 'ARG',
+      'country-code': '032',
+      'iso_3166-2': 'ISO 3166-2:AR',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Armenia',
+      alpha2: 'AM',
+      alpha3: 'ARM',
+      'country-code': '051',
+      'iso_3166-2': 'ISO 3166-2:AM',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Aruba',
+      alpha2: 'AW',
+      alpha3: 'ABW',
+      'country-code': '533',
+      'iso_3166-2': 'ISO 3166-2:AW',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Australia',
+      alpha2: 'AU',
+      alpha3: 'AUS',
+      'country-code': '036',
+      'iso_3166-2': 'ISO 3166-2:AU',
+      'region-code': '009',
+      'sub-region-code': '053'
+    },
+    {
+      name: 'Austria',
+      alpha2: 'AT',
+      alpha3: 'AUT',
+      'country-code': '040',
+      'iso_3166-2': 'ISO 3166-2:AT',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Azerbaijan',
+      alpha2: 'AZ',
+      alpha3: 'AZE',
+      'country-code': '031',
+      'iso_3166-2': 'ISO 3166-2:AZ',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Bahamas',
+      alpha2: 'BS',
+      alpha3: 'BHS',
+      'country-code': '044',
+      'iso_3166-2': 'ISO 3166-2:BS',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Bahrain',
+      alpha2: 'BH',
+      alpha3: 'BHR',
+      'country-code': '048',
+      'iso_3166-2': 'ISO 3166-2:BH',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Bangladesh',
+      alpha2: 'BD',
+      alpha3: 'BGD',
+      'country-code': '050',
+      'iso_3166-2': 'ISO 3166-2:BD',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Barbados',
+      alpha2: 'BB',
+      alpha3: 'BRB',
+      'country-code': '052',
+      'iso_3166-2': 'ISO 3166-2:BB',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Belarus',
+      alpha2: 'BY',
+      alpha3: 'BLR',
+      'country-code': '112',
+      'iso_3166-2': 'ISO 3166-2:BY',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Belgium',
+      alpha2: 'BE',
+      alpha3: 'BEL',
+      'country-code': '056',
+      'iso_3166-2': 'ISO 3166-2:BE',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Belize',
+      alpha2: 'BZ',
+      alpha3: 'BLZ',
+      'country-code': '084',
+      'iso_3166-2': 'ISO 3166-2:BZ',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Benin',
+      alpha2: 'BJ',
+      alpha3: 'BEN',
+      'country-code': '204',
+      'iso_3166-2': 'ISO 3166-2:BJ',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Bermuda',
+      alpha2: 'BM',
+      alpha3: 'BMU',
+      'country-code': '060',
+      'iso_3166-2': 'ISO 3166-2:BM',
+      'region-code': '019',
+      'sub-region-code': '021'
+    },
+    {
+      name: 'Bhutan',
+      alpha2: 'BT',
+      alpha3: 'BTN',
+      'country-code': '064',
+      'iso_3166-2': 'ISO 3166-2:BT',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Bolivia, Plurinational State of',
+      alpha2: 'BO',
+      alpha3: 'BOL',
+      'country-code': '068',
+      'iso_3166-2': 'ISO 3166-2:BO',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Bonaire, Sint Eustatius and Saba',
+      alpha2: 'BQ',
+      alpha3: 'BES',
+      'country-code': '535',
+      'iso_3166-2': 'ISO 3166-2:BQ',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Bosnia and Herzegovina',
+      alpha2: 'BA',
+      alpha3: 'BIH',
+      'country-code': '070',
+      'iso_3166-2': 'ISO 3166-2:BA',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Botswana',
+      alpha2: 'BW',
+      alpha3: 'BWA',
+      'country-code': '072',
+      'iso_3166-2': 'ISO 3166-2:BW',
+      'region-code': '002',
+      'sub-region-code': '018'
+    },
+    {
+      name: 'Bouvet Island',
+      alpha2: 'BV',
+      alpha3: 'BVT',
+      'country-code': '074',
+      'iso_3166-2': 'ISO 3166-2:BV'
+    },
+    {
+      name: 'Brazil',
+      alpha2: 'BR',
+      alpha3: 'BRA',
+      'country-code': '076',
+      'iso_3166-2': 'ISO 3166-2:BR',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'British Indian Ocean Territory',
+      alpha2: 'IO',
+      alpha3: 'IOT',
+      'country-code': '086',
+      'iso_3166-2': 'ISO 3166-2:IO'
+    },
+    {
+      name: 'Brunei Darussalam',
+      alpha2: 'BN',
+      alpha3: 'BRN',
+      'country-code': '096',
+      'iso_3166-2': 'ISO 3166-2:BN',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Bulgaria',
+      alpha2: 'BG',
+      alpha3: 'BGR',
+      'country-code': '100',
+      'iso_3166-2': 'ISO 3166-2:BG',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Burkina Faso',
+      alpha2: 'BF',
+      alpha3: 'BFA',
+      'country-code': '854',
+      'iso_3166-2': 'ISO 3166-2:BF',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Burundi',
+      alpha2: 'BI',
+      alpha3: 'BDI',
+      'country-code': '108',
+      'iso_3166-2': 'ISO 3166-2:BI',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Cambodia',
+      alpha2: 'KH',
+      alpha3: 'KHM',
+      'country-code': '116',
+      'iso_3166-2': 'ISO 3166-2:KH',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Cameroon',
+      alpha2: 'CM',
+      alpha3: 'CMR',
+      'country-code': '120',
+      'iso_3166-2': 'ISO 3166-2:CM',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Canada',
+      alpha2: 'CA',
+      alpha3: 'CAN',
+      'country-code': '124',
+      'iso_3166-2': 'ISO 3166-2:CA',
+      'region-code': '019',
+      'sub-region-code': '021'
+    },
+    {
+      name: 'Cape Verde',
+      alpha2: 'CV',
+      alpha3: 'CPV',
+      'country-code': '132',
+      'iso_3166-2': 'ISO 3166-2:CV',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Cayman Islands',
+      alpha2: 'KY',
+      alpha3: 'CYM',
+      'country-code': '136',
+      'iso_3166-2': 'ISO 3166-2:KY',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Central African Republic',
+      alpha2: 'CF',
+      alpha3: 'CAF',
+      'country-code': '140',
+      'iso_3166-2': 'ISO 3166-2:CF',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Chad',
+      alpha2: 'TD',
+      alpha3: 'TCD',
+      'country-code': '148',
+      'iso_3166-2': 'ISO 3166-2:TD',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Chile',
+      alpha2: 'CL',
+      alpha3: 'CHL',
+      'country-code': '152',
+      'iso_3166-2': 'ISO 3166-2:CL',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'China',
+      alpha2: 'CN',
+      alpha3: 'CHN',
+      'country-code': '156',
+      'iso_3166-2': 'ISO 3166-2:CN',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Christmas Island',
+      alpha2: 'CX',
+      alpha3: 'CXR',
+      'country-code': '162',
+      'iso_3166-2': 'ISO 3166-2:CX'
+    },
+    {
+      name: 'Cocos (Keeling) Islands',
+      alpha2: 'CC',
+      alpha3: 'CCK',
+      'country-code': '166',
+      'iso_3166-2': 'ISO 3166-2:CC'
+    },
+    {
+      name: 'Colombia',
+      alpha2: 'CO',
+      alpha3: 'COL',
+      'country-code': '170',
+      'iso_3166-2': 'ISO 3166-2:CO',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Comoros',
+      alpha2: 'KM',
+      alpha3: 'COM',
+      'country-code': '174',
+      'iso_3166-2': 'ISO 3166-2:KM',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Congo',
+      alpha2: 'CG',
+      alpha3: 'COG',
+      'country-code': '178',
+      'iso_3166-2': 'ISO 3166-2:CG',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Congo, the Democratic Republic of the',
+      alpha2: 'CD',
+      alpha3: 'COD',
+      'country-code': '180',
+      'iso_3166-2': 'ISO 3166-2:CD',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Cook Islands',
+      alpha2: 'CK',
+      alpha3: 'COK',
+      'country-code': '184',
+      'iso_3166-2': 'ISO 3166-2:CK',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Costa Rica',
+      alpha2: 'CR',
+      alpha3: 'CRI',
+      'country-code': '188',
+      'iso_3166-2': 'ISO 3166-2:CR',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: "Côte d'Ivoire",
+      alpha2: 'CI',
+      alpha3: 'CIV',
+      'country-code': '384',
+      'iso_3166-2': 'ISO 3166-2:CI',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Croatia',
+      alpha2: 'HR',
+      alpha3: 'HRV',
+      'country-code': '191',
+      'iso_3166-2': 'ISO 3166-2:HR',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Cuba',
+      alpha2: 'CU',
+      alpha3: 'CUB',
+      'country-code': '192',
+      'iso_3166-2': 'ISO 3166-2:CU',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Curaçao',
+      alpha2: 'CW',
+      alpha3: 'CUW',
+      'country-code': '531',
+      'iso_3166-2': 'ISO 3166-2:CW',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Cyprus',
+      alpha2: 'CY',
+      alpha3: 'CYP',
+      'country-code': '196',
+      'iso_3166-2': 'ISO 3166-2:CY',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Czech Republic',
+      alpha2: 'CZ',
+      alpha3: 'CZE',
+      'country-code': '203',
+      'iso_3166-2': 'ISO 3166-2:CZ',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Denmark',
+      alpha2: 'DK',
+      alpha3: 'DNK',
+      'country-code': '208',
+      'iso_3166-2': 'ISO 3166-2:DK',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Djibouti',
+      alpha2: 'DJ',
+      alpha3: 'DJI',
+      'country-code': '262',
+      'iso_3166-2': 'ISO 3166-2:DJ',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Dominica',
+      alpha2: 'DM',
+      alpha3: 'DMA',
+      'country-code': '212',
+      'iso_3166-2': 'ISO 3166-2:DM',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Dominican Republic',
+      alpha2: 'DO',
+      alpha3: 'DOM',
+      'country-code': '214',
+      'iso_3166-2': 'ISO 3166-2:DO',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Ecuador',
+      alpha2: 'EC',
+      alpha3: 'ECU',
+      'country-code': '218',
+      'iso_3166-2': 'ISO 3166-2:EC',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Egypt',
+      alpha2: 'EG',
+      alpha3: 'EGY',
+      'country-code': '818',
+      'iso_3166-2': 'ISO 3166-2:EG',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'El Salvador',
+      alpha2: 'SV',
+      alpha3: 'SLV',
+      'country-code': '222',
+      'iso_3166-2': 'ISO 3166-2:SV',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Equatorial Guinea',
+      alpha2: 'GQ',
+      alpha3: 'GNQ',
+      'country-code': '226',
+      'iso_3166-2': 'ISO 3166-2:GQ',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Eritrea',
+      alpha2: 'ER',
+      alpha3: 'ERI',
+      'country-code': '232',
+      'iso_3166-2': 'ISO 3166-2:ER',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Estonia',
+      alpha2: 'EE',
+      alpha3: 'EST',
+      'country-code': '233',
+      'iso_3166-2': 'ISO 3166-2:EE',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Ethiopia',
+      alpha2: 'ET',
+      alpha3: 'ETH',
+      'country-code': '231',
+      'iso_3166-2': 'ISO 3166-2:ET',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Falkland Islands (Malvinas)',
+      alpha2: 'FK',
+      alpha3: 'FLK',
+      'country-code': '238',
+      'iso_3166-2': 'ISO 3166-2:FK',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Faroe Islands',
+      alpha2: 'FO',
+      alpha3: 'FRO',
+      'country-code': '234',
+      'iso_3166-2': 'ISO 3166-2:FO',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Fiji',
+      alpha2: 'FJ',
+      alpha3: 'FJI',
+      'country-code': '242',
+      'iso_3166-2': 'ISO 3166-2:FJ',
+      'region-code': '009',
+      'sub-region-code': '054'
+    },
+    {
+      name: 'Finland',
+      alpha2: 'FI',
+      alpha3: 'FIN',
+      'country-code': '246',
+      'iso_3166-2': 'ISO 3166-2:FI',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'France',
+      alpha2: 'FR',
+      alpha3: 'FRA',
+      'country-code': '250',
+      'iso_3166-2': 'ISO 3166-2:FR',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'French Guiana',
+      alpha2: 'GF',
+      alpha3: 'GUF',
+      'country-code': '254',
+      'iso_3166-2': 'ISO 3166-2:GF',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'French Polynesia',
+      alpha2: 'PF',
+      alpha3: 'PYF',
+      'country-code': '258',
+      'iso_3166-2': 'ISO 3166-2:PF',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'French Southern Territories',
+      alpha2: 'TF',
+      alpha3: 'ATF',
+      'country-code': '260',
+      'iso_3166-2': 'ISO 3166-2:TF'
+    },
+    {
+      name: 'Gabon',
+      alpha2: 'GA',
+      alpha3: 'GAB',
+      'country-code': '266',
+      'iso_3166-2': 'ISO 3166-2:GA',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Gambia',
+      alpha2: 'GM',
+      alpha3: 'GMB',
+      'country-code': '270',
+      'iso_3166-2': 'ISO 3166-2:GM',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Georgia',
+      alpha2: 'GE',
+      alpha3: 'GEO',
+      'country-code': '268',
+      'iso_3166-2': 'ISO 3166-2:GE',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Germany',
+      alpha2: 'DE',
+      alpha3: 'DEU',
+      'country-code': '276',
+      'iso_3166-2': 'ISO 3166-2:DE',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Ghana',
+      alpha2: 'GH',
+      alpha3: 'GHA',
+      'country-code': '288',
+      'iso_3166-2': 'ISO 3166-2:GH',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Gibraltar',
+      alpha2: 'GI',
+      alpha3: 'GIB',
+      'country-code': '292',
+      'iso_3166-2': 'ISO 3166-2:GI',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Greece',
+      alpha2: 'GR',
+      alpha3: 'GRC',
+      'country-code': '300',
+      'iso_3166-2': 'ISO 3166-2:GR',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Greenland',
+      alpha2: 'GL',
+      alpha3: 'GRL',
+      'country-code': '304',
+      'iso_3166-2': 'ISO 3166-2:GL',
+      'region-code': '019',
+      'sub-region-code': '021'
+    },
+    {
+      name: 'Grenada',
+      alpha2: 'GD',
+      alpha3: 'GRD',
+      'country-code': '308',
+      'iso_3166-2': 'ISO 3166-2:GD',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Guadeloupe',
+      alpha2: 'GP',
+      alpha3: 'GLP',
+      'country-code': '312',
+      'iso_3166-2': 'ISO 3166-2:GP',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Guam',
+      alpha2: 'GU',
+      alpha3: 'GUM',
+      'country-code': '316',
+      'iso_3166-2': 'ISO 3166-2:GU',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: 'Guatemala',
+      alpha2: 'GT',
+      alpha3: 'GTM',
+      'country-code': '320',
+      'iso_3166-2': 'ISO 3166-2:GT',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Guernsey',
+      alpha2: 'GG',
+      alpha3: 'GGY',
+      'country-code': '831',
+      'iso_3166-2': 'ISO 3166-2:GG',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Guinea',
+      alpha2: 'GN',
+      alpha3: 'GIN',
+      'country-code': '324',
+      'iso_3166-2': 'ISO 3166-2:GN',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Guinea-Bissau',
+      alpha2: 'GW',
+      alpha3: 'GNB',
+      'country-code': '624',
+      'iso_3166-2': 'ISO 3166-2:GW',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Guyana',
+      alpha2: 'GY',
+      alpha3: 'GUY',
+      'country-code': '328',
+      'iso_3166-2': 'ISO 3166-2:GY',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Haiti',
+      alpha2: 'HT',
+      alpha3: 'HTI',
+      'country-code': '332',
+      'iso_3166-2': 'ISO 3166-2:HT',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Heard Island and McDonald Islands',
+      alpha2: 'HM',
+      alpha3: 'HMD',
+      'country-code': '334',
+      'iso_3166-2': 'ISO 3166-2:HM'
+    },
+    {
+      name: 'Holy See (Vatican City State)',
+      alpha2: 'VA',
+      alpha3: 'VAT',
+      'country-code': '336',
+      'iso_3166-2': 'ISO 3166-2:VA',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Honduras',
+      alpha2: 'HN',
+      alpha3: 'HND',
+      'country-code': '340',
+      'iso_3166-2': 'ISO 3166-2:HN',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Hong Kong',
+      alpha2: 'HK',
+      alpha3: 'HKG',
+      'country-code': '344',
+      'iso_3166-2': 'ISO 3166-2:HK',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Hungary',
+      alpha2: 'HU',
+      alpha3: 'HUN',
+      'country-code': '348',
+      'iso_3166-2': 'ISO 3166-2:HU',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Iceland',
+      alpha2: 'IS',
+      alpha3: 'ISL',
+      'country-code': '352',
+      'iso_3166-2': 'ISO 3166-2:IS',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'India',
+      alpha2: 'IN',
+      alpha3: 'IND',
+      'country-code': '356',
+      'iso_3166-2': 'ISO 3166-2:IN',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Indonesia',
+      alpha2: 'ID',
+      alpha3: 'IDN',
+      'country-code': '360',
+      'iso_3166-2': 'ISO 3166-2:ID',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Iran, Islamic Republic of',
+      alpha2: 'IR',
+      alpha3: 'IRN',
+      'country-code': '364',
+      'iso_3166-2': 'ISO 3166-2:IR',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Iraq',
+      alpha2: 'IQ',
+      alpha3: 'IRQ',
+      'country-code': '368',
+      'iso_3166-2': 'ISO 3166-2:IQ',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Ireland',
+      alpha2: 'IE',
+      alpha3: 'IRL',
+      'country-code': '372',
+      'iso_3166-2': 'ISO 3166-2:IE',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Isle of Man',
+      alpha2: 'IM',
+      alpha3: 'IMN',
+      'country-code': '833',
+      'iso_3166-2': 'ISO 3166-2:IM',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Israel',
+      alpha2: 'IL',
+      alpha3: 'ISR',
+      'country-code': '376',
+      'iso_3166-2': 'ISO 3166-2:IL',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Italy',
+      alpha2: 'IT',
+      alpha3: 'ITA',
+      'country-code': '380',
+      'iso_3166-2': 'ISO 3166-2:IT',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Jamaica',
+      alpha2: 'JM',
+      alpha3: 'JAM',
+      'country-code': '388',
+      'iso_3166-2': 'ISO 3166-2:JM',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Japan',
+      alpha2: 'JP',
+      alpha3: 'JPN',
+      'country-code': '392',
+      'iso_3166-2': 'ISO 3166-2:JP',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Jersey',
+      alpha2: 'JE',
+      alpha3: 'JEY',
+      'country-code': '832',
+      'iso_3166-2': 'ISO 3166-2:JE',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Jordan',
+      alpha2: 'JO',
+      alpha3: 'JOR',
+      'country-code': '400',
+      'iso_3166-2': 'ISO 3166-2:JO',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Kazakhstan',
+      alpha2: 'KZ',
+      alpha3: 'KAZ',
+      'country-code': '398',
+      'iso_3166-2': 'ISO 3166-2:KZ',
+      'region-code': '142',
+      'sub-region-code': '143'
+    },
+    {
+      name: 'Kenya',
+      alpha2: 'KE',
+      alpha3: 'KEN',
+      'country-code': '404',
+      'iso_3166-2': 'ISO 3166-2:KE',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Kiribati',
+      alpha2: 'KI',
+      alpha3: 'KIR',
+      'country-code': '296',
+      'iso_3166-2': 'ISO 3166-2:KI',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: "Korea, Democratic People's Republic of",
+      alpha2: 'KP',
+      alpha3: 'PRK',
+      'country-code': '408',
+      'iso_3166-2': 'ISO 3166-2:KP',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Korea, Republic of',
+      alpha2: 'KR',
+      alpha3: 'KOR',
+      'country-code': '410',
+      'iso_3166-2': 'ISO 3166-2:KR',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Kuwait',
+      alpha2: 'KW',
+      alpha3: 'KWT',
+      'country-code': '414',
+      'iso_3166-2': 'ISO 3166-2:KW',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Kyrgyzstan',
+      alpha2: 'KG',
+      alpha3: 'KGZ',
+      'country-code': '417',
+      'iso_3166-2': 'ISO 3166-2:KG',
+      'region-code': '142',
+      'sub-region-code': '143'
+    },
+    {
+      name: "Lao People's Democratic Republic",
+      alpha2: 'LA',
+      alpha3: 'LAO',
+      'country-code': '418',
+      'iso_3166-2': 'ISO 3166-2:LA',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Latvia',
+      alpha2: 'LV',
+      alpha3: 'LVA',
+      'country-code': '428',
+      'iso_3166-2': 'ISO 3166-2:LV',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Lebanon',
+      alpha2: 'LB',
+      alpha3: 'LBN',
+      'country-code': '422',
+      'iso_3166-2': 'ISO 3166-2:LB',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Lesotho',
+      alpha2: 'LS',
+      alpha3: 'LSO',
+      'country-code': '426',
+      'iso_3166-2': 'ISO 3166-2:LS',
+      'region-code': '002',
+      'sub-region-code': '018'
+    },
+    {
+      name: 'Liberia',
+      alpha2: 'LR',
+      alpha3: 'LBR',
+      'country-code': '430',
+      'iso_3166-2': 'ISO 3166-2:LR',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Libya',
+      alpha2: 'LY',
+      alpha3: 'LBY',
+      'country-code': '434',
+      'iso_3166-2': 'ISO 3166-2:LY',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'Liechtenstein',
+      alpha2: 'LI',
+      alpha3: 'LIE',
+      'country-code': '438',
+      'iso_3166-2': 'ISO 3166-2:LI',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Lithuania',
+      alpha2: 'LT',
+      alpha3: 'LTU',
+      'country-code': '440',
+      'iso_3166-2': 'ISO 3166-2:LT',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Luxembourg',
+      alpha2: 'LU',
+      alpha3: 'LUX',
+      'country-code': '442',
+      'iso_3166-2': 'ISO 3166-2:LU',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Macao',
+      alpha2: 'MO',
+      alpha3: 'MAC',
+      'country-code': '446',
+      'iso_3166-2': 'ISO 3166-2:MO',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Macedonia, the former Yugoslav Republic of',
+      alpha2: 'MK',
+      alpha3: 'MKD',
+      'country-code': '807',
+      'iso_3166-2': 'ISO 3166-2:MK',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Madagascar',
+      alpha2: 'MG',
+      alpha3: 'MDG',
+      'country-code': '450',
+      'iso_3166-2': 'ISO 3166-2:MG',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Malawi',
+      alpha2: 'MW',
+      alpha3: 'MWI',
+      'country-code': '454',
+      'iso_3166-2': 'ISO 3166-2:MW',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Malaysia',
+      alpha2: 'MY',
+      alpha3: 'MYS',
+      'country-code': '458',
+      'iso_3166-2': 'ISO 3166-2:MY',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Maldives',
+      alpha2: 'MV',
+      alpha3: 'MDV',
+      'country-code': '462',
+      'iso_3166-2': 'ISO 3166-2:MV',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Mali',
+      alpha2: 'ML',
+      alpha3: 'MLI',
+      'country-code': '466',
+      'iso_3166-2': 'ISO 3166-2:ML',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Malta',
+      alpha2: 'MT',
+      alpha3: 'MLT',
+      'country-code': '470',
+      'iso_3166-2': 'ISO 3166-2:MT',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Marshall Islands',
+      alpha2: 'MH',
+      alpha3: 'MHL',
+      'country-code': '584',
+      'iso_3166-2': 'ISO 3166-2:MH',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: 'Martinique',
+      alpha2: 'MQ',
+      alpha3: 'MTQ',
+      'country-code': '474',
+      'iso_3166-2': 'ISO 3166-2:MQ',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Mauritania',
+      alpha2: 'MR',
+      alpha3: 'MRT',
+      'country-code': '478',
+      'iso_3166-2': 'ISO 3166-2:MR',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Mauritius',
+      alpha2: 'MU',
+      alpha3: 'MUS',
+      'country-code': '480',
+      'iso_3166-2': 'ISO 3166-2:MU',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Mayotte',
+      alpha2: 'YT',
+      alpha3: 'MYT',
+      'country-code': '175',
+      'iso_3166-2': 'ISO 3166-2:YT',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Mexico',
+      alpha2: 'MX',
+      alpha3: 'MEX',
+      'country-code': '484',
+      'iso_3166-2': 'ISO 3166-2:MX',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Micronesia, Federated States of',
+      alpha2: 'FM',
+      alpha3: 'FSM',
+      'country-code': '583',
+      'iso_3166-2': 'ISO 3166-2:FM',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: 'Moldova, Republic of',
+      alpha2: 'MD',
+      alpha3: 'MDA',
+      'country-code': '498',
+      'iso_3166-2': 'ISO 3166-2:MD',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Monaco',
+      alpha2: 'MC',
+      alpha3: 'MCO',
+      'country-code': '492',
+      'iso_3166-2': 'ISO 3166-2:MC',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Mongolia',
+      alpha2: 'MN',
+      alpha3: 'MNG',
+      'country-code': '496',
+      'iso_3166-2': 'ISO 3166-2:MN',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Montenegro',
+      alpha2: 'ME',
+      alpha3: 'MNE',
+      'country-code': '499',
+      'iso_3166-2': 'ISO 3166-2:ME',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Montserrat',
+      alpha2: 'MS',
+      alpha3: 'MSR',
+      'country-code': '500',
+      'iso_3166-2': 'ISO 3166-2:MS',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Morocco',
+      alpha2: 'MA',
+      alpha3: 'MAR',
+      'country-code': '504',
+      'iso_3166-2': 'ISO 3166-2:MA',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'Mozambique',
+      alpha2: 'MZ',
+      alpha3: 'MOZ',
+      'country-code': '508',
+      'iso_3166-2': 'ISO 3166-2:MZ',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Myanmar',
+      alpha2: 'MM',
+      alpha3: 'MMR',
+      'country-code': '104',
+      'iso_3166-2': 'ISO 3166-2:MM',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Namibia',
+      alpha2: 'NA',
+      alpha3: 'NAM',
+      'country-code': '516',
+      'iso_3166-2': 'ISO 3166-2:NA',
+      'region-code': '002',
+      'sub-region-code': '018'
+    },
+    {
+      name: 'Nauru',
+      alpha2: 'NR',
+      alpha3: 'NRU',
+      'country-code': '520',
+      'iso_3166-2': 'ISO 3166-2:NR',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: 'Nepal',
+      alpha2: 'NP',
+      alpha3: 'NPL',
+      'country-code': '524',
+      'iso_3166-2': 'ISO 3166-2:NP',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Netherlands',
+      alpha2: 'NL',
+      alpha3: 'NLD',
+      'country-code': '528',
+      'iso_3166-2': 'ISO 3166-2:NL',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'New Caledonia',
+      alpha2: 'NC',
+      alpha3: 'NCL',
+      'country-code': '540',
+      'iso_3166-2': 'ISO 3166-2:NC',
+      'region-code': '009',
+      'sub-region-code': '054'
+    },
+    {
+      name: 'New Zealand',
+      alpha2: 'NZ',
+      alpha3: 'NZL',
+      'country-code': '554',
+      'iso_3166-2': 'ISO 3166-2:NZ',
+      'region-code': '009',
+      'sub-region-code': '053'
+    },
+    {
+      name: 'Nicaragua',
+      alpha2: 'NI',
+      alpha3: 'NIC',
+      'country-code': '558',
+      'iso_3166-2': 'ISO 3166-2:NI',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Niger',
+      alpha2: 'NE',
+      alpha3: 'NER',
+      'country-code': '562',
+      'iso_3166-2': 'ISO 3166-2:NE',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Nigeria',
+      alpha2: 'NG',
+      alpha3: 'NGA',
+      'country-code': '566',
+      'iso_3166-2': 'ISO 3166-2:NG',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Niue',
+      alpha2: 'NU',
+      alpha3: 'NIU',
+      'country-code': '570',
+      'iso_3166-2': 'ISO 3166-2:NU',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Norfolk Island',
+      alpha2: 'NF',
+      alpha3: 'NFK',
+      'country-code': '574',
+      'iso_3166-2': 'ISO 3166-2:NF',
+      'region-code': '009',
+      'sub-region-code': '053'
+    },
+    {
+      name: 'Northern Mariana Islands',
+      alpha2: 'MP',
+      alpha3: 'MNP',
+      'country-code': '580',
+      'iso_3166-2': 'ISO 3166-2:MP',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: 'Norway',
+      alpha2: 'NO',
+      alpha3: 'NOR',
+      'country-code': '578',
+      'iso_3166-2': 'ISO 3166-2:NO',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Oman',
+      alpha2: 'OM',
+      alpha3: 'OMN',
+      'country-code': '512',
+      'iso_3166-2': 'ISO 3166-2:OM',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Pakistan',
+      alpha2: 'PK',
+      alpha3: 'PAK',
+      'country-code': '586',
+      'iso_3166-2': 'ISO 3166-2:PK',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Palau',
+      alpha2: 'PW',
+      alpha3: 'PLW',
+      'country-code': '585',
+      'iso_3166-2': 'ISO 3166-2:PW',
+      'region-code': '009',
+      'sub-region-code': '057'
+    },
+    {
+      name: 'Palestine, State of',
+      alpha2: 'PS',
+      alpha3: 'PSE',
+      'country-code': '275',
+      'iso_3166-2': 'ISO 3166-2:PS',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Panama',
+      alpha2: 'PA',
+      alpha3: 'PAN',
+      'country-code': '591',
+      'iso_3166-2': 'ISO 3166-2:PA',
+      'region-code': '019',
+      'sub-region-code': '013'
+    },
+    {
+      name: 'Papua New Guinea',
+      alpha2: 'PG',
+      alpha3: 'PNG',
+      'country-code': '598',
+      'iso_3166-2': 'ISO 3166-2:PG',
+      'region-code': '009',
+      'sub-region-code': '054'
+    },
+    {
+      name: 'Paraguay',
+      alpha2: 'PY',
+      alpha3: 'PRY',
+      'country-code': '600',
+      'iso_3166-2': 'ISO 3166-2:PY',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Peru',
+      alpha2: 'PE',
+      alpha3: 'PER',
+      'country-code': '604',
+      'iso_3166-2': 'ISO 3166-2:PE',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Philippines',
+      alpha2: 'PH',
+      alpha3: 'PHL',
+      'country-code': '608',
+      'iso_3166-2': 'ISO 3166-2:PH',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Pitcairn',
+      alpha2: 'PN',
+      alpha3: 'PCN',
+      'country-code': '612',
+      'iso_3166-2': 'ISO 3166-2:PN',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Poland',
+      alpha2: 'PL',
+      alpha3: 'POL',
+      'country-code': '616',
+      'iso_3166-2': 'ISO 3166-2:PL',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Portugal',
+      alpha2: 'PT',
+      alpha3: 'PRT',
+      'country-code': '620',
+      'iso_3166-2': 'ISO 3166-2:PT',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Puerto Rico',
+      alpha2: 'PR',
+      alpha3: 'PRI',
+      'country-code': '630',
+      'iso_3166-2': 'ISO 3166-2:PR',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Qatar',
+      alpha2: 'QA',
+      alpha3: 'QAT',
+      'country-code': '634',
+      'iso_3166-2': 'ISO 3166-2:QA',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Réunion',
+      alpha2: 'RE',
+      alpha3: 'REU',
+      'country-code': '638',
+      'iso_3166-2': 'ISO 3166-2:RE',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Romania',
+      alpha2: 'RO',
+      alpha3: 'ROU',
+      'country-code': '642',
+      'iso_3166-2': 'ISO 3166-2:RO',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Russian Federation',
+      alpha2: 'RU',
+      alpha3: 'RUS',
+      'country-code': '643',
+      'iso_3166-2': 'ISO 3166-2:RU',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Rwanda',
+      alpha2: 'RW',
+      alpha3: 'RWA',
+      'country-code': '646',
+      'iso_3166-2': 'ISO 3166-2:RW',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Saint Barthélemy',
+      alpha2: 'BL',
+      alpha3: 'BLM',
+      'country-code': '652',
+      'iso_3166-2': 'ISO 3166-2:BL',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Saint Helena, Ascension and Tristan da Cunha',
+      alpha2: 'SH',
+      alpha3: 'SHN',
+      'country-code': '654',
+      'iso_3166-2': 'ISO 3166-2:SH',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Saint Kitts and Nevis',
+      alpha2: 'KN',
+      alpha3: 'KNA',
+      'country-code': '659',
+      'iso_3166-2': 'ISO 3166-2:KN',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Saint Lucia',
+      alpha2: 'LC',
+      alpha3: 'LCA',
+      'country-code': '662',
+      'iso_3166-2': 'ISO 3166-2:LC',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Saint Martin (French part)',
+      alpha2: 'MF',
+      alpha3: 'MAF',
+      'country-code': '663',
+      'iso_3166-2': 'ISO 3166-2:MF',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Saint Pierre and Miquelon',
+      alpha2: 'PM',
+      alpha3: 'SPM',
+      'country-code': '666',
+      'iso_3166-2': 'ISO 3166-2:PM',
+      'region-code': '019',
+      'sub-region-code': '021'
+    },
+    {
+      name: 'Saint Vincent and the Grenadines',
+      alpha2: 'VC',
+      alpha3: 'VCT',
+      'country-code': '670',
+      'iso_3166-2': 'ISO 3166-2:VC',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Samoa',
+      alpha2: 'WS',
+      alpha3: 'WSM',
+      'country-code': '882',
+      'iso_3166-2': 'ISO 3166-2:WS',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'San Marino',
+      alpha2: 'SM',
+      alpha3: 'SMR',
+      'country-code': '674',
+      'iso_3166-2': 'ISO 3166-2:SM',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Sao Tome and Principe',
+      alpha2: 'ST',
+      alpha3: 'STP',
+      'country-code': '678',
+      'iso_3166-2': 'ISO 3166-2:ST',
+      'region-code': '002',
+      'sub-region-code': '017'
+    },
+    {
+      name: 'Saudi Arabia',
+      alpha2: 'SA',
+      alpha3: 'SAU',
+      'country-code': '682',
+      'iso_3166-2': 'ISO 3166-2:SA',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Senegal',
+      alpha2: 'SN',
+      alpha3: 'SEN',
+      'country-code': '686',
+      'iso_3166-2': 'ISO 3166-2:SN',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Serbia',
+      alpha2: 'RS',
+      alpha3: 'SRB',
+      'country-code': '688',
+      'iso_3166-2': 'ISO 3166-2:RS',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Seychelles',
+      alpha2: 'SC',
+      alpha3: 'SYC',
+      'country-code': '690',
+      'iso_3166-2': 'ISO 3166-2:SC',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Sierra Leone',
+      alpha2: 'SL',
+      alpha3: 'SLE',
+      'country-code': '694',
+      'iso_3166-2': 'ISO 3166-2:SL',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Singapore',
+      alpha2: 'SG',
+      alpha3: 'SGP',
+      'country-code': '702',
+      'iso_3166-2': 'ISO 3166-2:SG',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Sint Maarten (Dutch part)',
+      alpha2: 'SX',
+      alpha3: 'SXM',
+      'country-code': '534',
+      'iso_3166-2': 'ISO 3166-2:SX',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Slovakia',
+      alpha2: 'SK',
+      alpha3: 'SVK',
+      'country-code': '703',
+      'iso_3166-2': 'ISO 3166-2:SK',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'Slovenia',
+      alpha2: 'SI',
+      alpha3: 'SVN',
+      'country-code': '705',
+      'iso_3166-2': 'ISO 3166-2:SI',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Solomon Islands',
+      alpha2: 'SB',
+      alpha3: 'SLB',
+      'country-code': '090',
+      'iso_3166-2': 'ISO 3166-2:SB',
+      'region-code': '009',
+      'sub-region-code': '054'
+    },
+    {
+      name: 'Somalia',
+      alpha2: 'SO',
+      alpha3: 'SOM',
+      'country-code': '706',
+      'iso_3166-2': 'ISO 3166-2:SO',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'South Africa',
+      alpha2: 'ZA',
+      alpha3: 'ZAF',
+      'country-code': '710',
+      'iso_3166-2': 'ISO 3166-2:ZA',
+      'region-code': '002',
+      'sub-region-code': '018'
+    },
+    {
+      name: 'South Georgia and the South Sandwich Islands',
+      alpha2: 'GS',
+      alpha3: 'SGS',
+      'country-code': '239',
+      'iso_3166-2': 'ISO 3166-2:GS'
+    },
+    {
+      name: 'South Sudan',
+      alpha2: 'SS',
+      alpha3: 'SSD',
+      'country-code': '728',
+      'iso_3166-2': 'ISO 3166-2:SS',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Spain',
+      alpha2: 'ES',
+      alpha3: 'ESP',
+      'country-code': '724',
+      'iso_3166-2': 'ISO 3166-2:ES',
+      'region-code': '150',
+      'sub-region-code': '039'
+    },
+    {
+      name: 'Sri Lanka',
+      alpha2: 'LK',
+      alpha3: 'LKA',
+      'country-code': '144',
+      'iso_3166-2': 'ISO 3166-2:LK',
+      'region-code': '142',
+      'sub-region-code': '034'
+    },
+    {
+      name: 'Sudan',
+      alpha2: 'SD',
+      alpha3: 'SDN',
+      'country-code': '729',
+      'iso_3166-2': 'ISO 3166-2:SD',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'Suriname',
+      alpha2: 'SR',
+      alpha3: 'SUR',
+      'country-code': '740',
+      'iso_3166-2': 'ISO 3166-2:SR',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Svalbard and Jan Mayen',
+      alpha2: 'SJ',
+      alpha3: 'SJM',
+      'country-code': '744',
+      'iso_3166-2': 'ISO 3166-2:SJ',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Swaziland',
+      alpha2: 'SZ',
+      alpha3: 'SWZ',
+      'country-code': '748',
+      'iso_3166-2': 'ISO 3166-2:SZ',
+      'region-code': '002',
+      'sub-region-code': '018'
+    },
+    {
+      name: 'Sweden',
+      alpha2: 'SE',
+      alpha3: 'SWE',
+      'country-code': '752',
+      'iso_3166-2': 'ISO 3166-2:SE',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'Switzerland',
+      alpha2: 'CH',
+      alpha3: 'CHE',
+      'country-code': '756',
+      'iso_3166-2': 'ISO 3166-2:CH',
+      'region-code': '150',
+      'sub-region-code': '155'
+    },
+    {
+      name: 'Syrian Arab Republic',
+      alpha2: 'SY',
+      alpha3: 'SYR',
+      'country-code': '760',
+      'iso_3166-2': 'ISO 3166-2:SY',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Taiwan, Province of China',
+      alpha2: 'TW',
+      alpha3: 'TWN',
+      'country-code': '158',
+      'iso_3166-2': 'ISO 3166-2:TW',
+      'region-code': '142',
+      'sub-region-code': '030'
+    },
+    {
+      name: 'Tajikistan',
+      alpha2: 'TJ',
+      alpha3: 'TJK',
+      'country-code': '762',
+      'iso_3166-2': 'ISO 3166-2:TJ',
+      'region-code': '142',
+      'sub-region-code': '143'
+    },
+    {
+      name: 'Tanzania, United Republic of',
+      alpha2: 'TZ',
+      alpha3: 'TZA',
+      'country-code': '834',
+      'iso_3166-2': 'ISO 3166-2:TZ',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Thailand',
+      alpha2: 'TH',
+      alpha3: 'THA',
+      'country-code': '764',
+      'iso_3166-2': 'ISO 3166-2:TH',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Timor-Leste',
+      alpha2: 'TL',
+      alpha3: 'TLS',
+      'country-code': '626',
+      'iso_3166-2': 'ISO 3166-2:TL',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Togo',
+      alpha2: 'TG',
+      alpha3: 'TGO',
+      'country-code': '768',
+      'iso_3166-2': 'ISO 3166-2:TG',
+      'region-code': '002',
+      'sub-region-code': '011'
+    },
+    {
+      name: 'Tokelau',
+      alpha2: 'TK',
+      alpha3: 'TKL',
+      'country-code': '772',
+      'iso_3166-2': 'ISO 3166-2:TK',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Tonga',
+      alpha2: 'TO',
+      alpha3: 'TON',
+      'country-code': '776',
+      'iso_3166-2': 'ISO 3166-2:TO',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Trinidad and Tobago',
+      alpha2: 'TT',
+      alpha3: 'TTO',
+      'country-code': '780',
+      'iso_3166-2': 'ISO 3166-2:TT',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Tunisia',
+      alpha2: 'TN',
+      alpha3: 'TUN',
+      'country-code': '788',
+      'iso_3166-2': 'ISO 3166-2:TN',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'Turkey',
+      alpha2: 'TR',
+      alpha3: 'TUR',
+      'country-code': '792',
+      'iso_3166-2': 'ISO 3166-2:TR',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Turkmenistan',
+      alpha2: 'TM',
+      alpha3: 'TKM',
+      'country-code': '795',
+      'iso_3166-2': 'ISO 3166-2:TM',
+      'region-code': '142',
+      'sub-region-code': '143'
+    },
+    {
+      name: 'Turks and Caicos Islands',
+      alpha2: 'TC',
+      alpha3: 'TCA',
+      'country-code': '796',
+      'iso_3166-2': 'ISO 3166-2:TC',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Tuvalu',
+      alpha2: 'TV',
+      alpha3: 'TUV',
+      'country-code': '798',
+      'iso_3166-2': 'ISO 3166-2:TV',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Uganda',
+      alpha2: 'UG',
+      alpha3: 'UGA',
+      'country-code': '800',
+      'iso_3166-2': 'ISO 3166-2:UG',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Ukraine',
+      alpha2: 'UA',
+      alpha3: 'UKR',
+      'country-code': '804',
+      'iso_3166-2': 'ISO 3166-2:UA',
+      'region-code': '150',
+      'sub-region-code': '151'
+    },
+    {
+      name: 'United Arab Emirates',
+      alpha2: 'AE',
+      alpha3: 'ARE',
+      'country-code': '784',
+      'iso_3166-2': 'ISO 3166-2:AE',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'United Kingdom',
+      alpha2: 'GB',
+      alpha3: 'GBR',
+      'country-code': '826',
+      'iso_3166-2': 'ISO 3166-2:GB',
+      'region-code': '150',
+      'sub-region-code': '154'
+    },
+    {
+      name: 'United States',
+      alpha2: 'US',
+      alpha3: 'USA',
+      'country-code': '840',
+      'iso_3166-2': 'ISO 3166-2:US',
+      'region-code': '019',
+      'sub-region-code': '021'
+    },
+    {
+      name: 'United States Minor Outlying Islands',
+      alpha2: 'UM',
+      alpha3: 'UMI',
+      'country-code': '581',
+      'iso_3166-2': 'ISO 3166-2:UM'
+    },
+    {
+      name: 'Uruguay',
+      alpha2: 'UY',
+      alpha3: 'URY',
+      'country-code': '858',
+      'iso_3166-2': 'ISO 3166-2:UY',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Uzbekistan',
+      alpha2: 'UZ',
+      alpha3: 'UZB',
+      'country-code': '860',
+      'iso_3166-2': 'ISO 3166-2:UZ',
+      'region-code': '142',
+      'sub-region-code': '143'
+    },
+    {
+      name: 'Vanuatu',
+      alpha2: 'VU',
+      alpha3: 'VUT',
+      'country-code': '548',
+      'iso_3166-2': 'ISO 3166-2:VU',
+      'region-code': '009',
+      'sub-region-code': '054'
+    },
+    {
+      name: 'Venezuela, Bolivarian Republic of',
+      alpha2: 'VE',
+      alpha3: 'VEN',
+      'country-code': '862',
+      'iso_3166-2': 'ISO 3166-2:VE',
+      'region-code': '019',
+      'sub-region-code': '005'
+    },
+    {
+      name: 'Viet Nam',
+      alpha2: 'VN',
+      alpha3: 'VNM',
+      'country-code': '704',
+      'iso_3166-2': 'ISO 3166-2:VN',
+      'region-code': '142',
+      'sub-region-code': '035'
+    },
+    {
+      name: 'Virgin Islands, British',
+      alpha2: 'VG',
+      alpha3: 'VGB',
+      'country-code': '092',
+      'iso_3166-2': 'ISO 3166-2:VG',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Virgin Islands, U.S.',
+      alpha2: 'VI',
+      alpha3: 'VIR',
+      'country-code': '850',
+      'iso_3166-2': 'ISO 3166-2:VI',
+      'region-code': '019',
+      'sub-region-code': '029'
+    },
+    {
+      name: 'Wallis and Futuna',
+      alpha2: 'WF',
+      alpha3: 'WLF',
+      'country-code': '876',
+      'iso_3166-2': 'ISO 3166-2:WF',
+      'region-code': '009',
+      'sub-region-code': '061'
+    },
+    {
+      name: 'Western Sahara',
+      alpha2: 'EH',
+      alpha3: 'ESH',
+      'country-code': '732',
+      'iso_3166-2': 'ISO 3166-2:EH',
+      'region-code': '002',
+      'sub-region-code': '015'
+    },
+    {
+      name: 'Yemen',
+      alpha2: 'YE',
+      alpha3: 'YEM',
+      'country-code': '887',
+      'iso_3166-2': 'ISO 3166-2:YE',
+      'region-code': '142',
+      'sub-region-code': '145'
+    },
+    {
+      name: 'Zambia',
+      alpha2: 'ZM',
+      alpha3: 'ZMB',
+      'country-code': '894',
+      'iso_3166-2': 'ISO 3166-2:ZM',
+      'region-code': '002',
+      'sub-region-code': '014'
+    },
+    {
+      name: 'Zimbabwe',
+      alpha2: 'ZW',
+      alpha3: 'ZWE',
+      'country-code': '716',
+      'iso_3166-2': 'ISO 3166-2:ZW',
+      'region-code': '002',
+      'sub-region-code': '014'
+    }
+  ],
+  getCountryFromName: function(name) {
+    for (let i = 0; i < this.ISO_3166.length; i++) {
+      if (this.ISO_3166[i].name.toLowerCase().indexOf(name.toLowerCase()) > -1) {
+        return this.ISO_3166[i];
+      }
+    }
+    return null;
+  },
+  getCountryFromCode: function(code) {
+    for (let i = 0; i < this.ISO_3166.length; i++) {
+      if (
+        code.toLowerCase().indexOf(this.ISO_3166[i].alpha2.toLowerCase()) > -1 ||
+        code.toLowerCase().indexOf(this.ISO_3166[i].alpha3.toLowerCase()) > -1
+      ) {
+        return this.ISO_3166[i];
+      }
+    }
+    return null;
+  },
+  getISOAlpha2: function(code) {
+    const _country = HueGeo.getCountryFromCode(code);
+    return _country ? _country.alpha2 : 'AQ';
+  },
+  getISOAlpha3: function(code) {
+    const _country = HueGeo.getCountryFromCode(code);
+    return _country ? _country.alpha3 : 'ATA';
+  },
+  getCity: function(city, callback) {
+    const api = new NominatimAPI();
+    api.lookupCity(city, rawdata => {
+      if (rawdata.length > 1) {
+        callback(rawdata);
+      } else {
+        callback(rawdata[0]);
+      }
+    });
+  },
+  getCityCoordinates: function(city, callback) {
+    const api = new NominatimAPI();
+    api.lookupCity(city, rawdata => {
+      if (rawdata.length > 1) {
+        callback(rawdata);
+      } else {
+        callback(rawdata[0].lat, rawdata[0].lon);
+      }
+    });
+  },
+  getAddressFromCoordinates: function(lat, lng, callback) {
+    const api = new NominatimAPI();
+    api.lookupAddress(lat + ',' + lng, rawdata => {
+      if (rawdata.length > 1) {
+        callback(rawdata);
+      } else {
+        callback(rawdata[0].display_name);
+      }
+    });
+  },
+
+  getAddressCoordinates: function(address, callback) {
+    const api = new NominatimAPI();
+    api.lookupAddress(address, rawdata => {
+      if (rawdata.length > 1) {
+        callback(rawdata);
+      } else {
+        callback(rawdata[0].lat, rawdata[0].lon);
+      }
+    });
+  }
+};
+
+export default HueGeo;

File diff suppressed because it is too large
+ 0 - 6
desktop/core/src/desktop/static/desktop/ext/js/plotly-latest.min.js


+ 0 - 355
desktop/core/src/desktop/static/desktop/js/hue.geo.js

@@ -1,355 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-var HueGeo = {
-  ISO_3166: [
-    {"name": "Afghanistan", "alpha2": "AF", "alpha3": "AFG", "country-code": "004", "iso_3166-2": "ISO 3166-2:AF", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Åland Islands", "alpha2": "AX", "alpha3": "ALA", "country-code": "248", "iso_3166-2": "ISO 3166-2:AX", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Albania", "alpha2": "AL", "alpha3": "ALB", "country-code": "008", "iso_3166-2": "ISO 3166-2:AL", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Algeria", "alpha2": "DZ", "alpha3": "DZA", "country-code": "012", "iso_3166-2": "ISO 3166-2:DZ", "region-code": "002", "sub-region-code": "015"},
-    {"name": "American Samoa", "alpha2": "AS", "alpha3": "ASM", "country-code": "016", "iso_3166-2": "ISO 3166-2:AS", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Andorra", "alpha2": "AD", "alpha3": "AND", "country-code": "020", "iso_3166-2": "ISO 3166-2:AD", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Angola", "alpha2": "AO", "alpha3": "AGO", "country-code": "024", "iso_3166-2": "ISO 3166-2:AO", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Anguilla", "alpha2": "AI", "alpha3": "AIA", "country-code": "660", "iso_3166-2": "ISO 3166-2:AI", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Antarctica", "alpha2": "AQ", "alpha3": "ATA", "country-code": "010", "iso_3166-2": "ISO 3166-2:AQ"},
-    {"name": "Antigua and Barbuda", "alpha2": "AG", "alpha3": "ATG", "country-code": "028", "iso_3166-2": "ISO 3166-2:AG", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Argentina", "alpha2": "AR", "alpha3": "ARG", "country-code": "032", "iso_3166-2": "ISO 3166-2:AR", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Armenia", "alpha2": "AM", "alpha3": "ARM", "country-code": "051", "iso_3166-2": "ISO 3166-2:AM", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Aruba", "alpha2": "AW", "alpha3": "ABW", "country-code": "533", "iso_3166-2": "ISO 3166-2:AW", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Australia", "alpha2": "AU", "alpha3": "AUS", "country-code": "036", "iso_3166-2": "ISO 3166-2:AU", "region-code": "009", "sub-region-code": "053"},
-    {"name": "Austria", "alpha2": "AT", "alpha3": "AUT", "country-code": "040", "iso_3166-2": "ISO 3166-2:AT", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Azerbaijan", "alpha2": "AZ", "alpha3": "AZE", "country-code": "031", "iso_3166-2": "ISO 3166-2:AZ", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Bahamas", "alpha2": "BS", "alpha3": "BHS", "country-code": "044", "iso_3166-2": "ISO 3166-2:BS", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Bahrain", "alpha2": "BH", "alpha3": "BHR", "country-code": "048", "iso_3166-2": "ISO 3166-2:BH", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Bangladesh", "alpha2": "BD", "alpha3": "BGD", "country-code": "050", "iso_3166-2": "ISO 3166-2:BD", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Barbados", "alpha2": "BB", "alpha3": "BRB", "country-code": "052", "iso_3166-2": "ISO 3166-2:BB", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Belarus", "alpha2": "BY", "alpha3": "BLR", "country-code": "112", "iso_3166-2": "ISO 3166-2:BY", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Belgium", "alpha2": "BE", "alpha3": "BEL", "country-code": "056", "iso_3166-2": "ISO 3166-2:BE", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Belize", "alpha2": "BZ", "alpha3": "BLZ", "country-code": "084", "iso_3166-2": "ISO 3166-2:BZ", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Benin", "alpha2": "BJ", "alpha3": "BEN", "country-code": "204", "iso_3166-2": "ISO 3166-2:BJ", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Bermuda", "alpha2": "BM", "alpha3": "BMU", "country-code": "060", "iso_3166-2": "ISO 3166-2:BM", "region-code": "019", "sub-region-code": "021"},
-    {"name": "Bhutan", "alpha2": "BT", "alpha3": "BTN", "country-code": "064", "iso_3166-2": "ISO 3166-2:BT", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Bolivia, Plurinational State of", "alpha2": "BO", "alpha3": "BOL", "country-code": "068", "iso_3166-2": "ISO 3166-2:BO", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Bonaire, Sint Eustatius and Saba", "alpha2": "BQ", "alpha3": "BES", "country-code": "535", "iso_3166-2": "ISO 3166-2:BQ", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Bosnia and Herzegovina", "alpha2": "BA", "alpha3": "BIH", "country-code": "070", "iso_3166-2": "ISO 3166-2:BA", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Botswana", "alpha2": "BW", "alpha3": "BWA", "country-code": "072", "iso_3166-2": "ISO 3166-2:BW", "region-code": "002", "sub-region-code": "018"},
-    {"name": "Bouvet Island", "alpha2": "BV", "alpha3": "BVT", "country-code": "074", "iso_3166-2": "ISO 3166-2:BV"},
-    {"name": "Brazil", "alpha2": "BR", "alpha3": "BRA", "country-code": "076", "iso_3166-2": "ISO 3166-2:BR", "region-code": "019", "sub-region-code": "005"},
-    {"name": "British Indian Ocean Territory", "alpha2": "IO", "alpha3": "IOT", "country-code": "086", "iso_3166-2": "ISO 3166-2:IO"},
-    {"name": "Brunei Darussalam", "alpha2": "BN", "alpha3": "BRN", "country-code": "096", "iso_3166-2": "ISO 3166-2:BN", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Bulgaria", "alpha2": "BG", "alpha3": "BGR", "country-code": "100", "iso_3166-2": "ISO 3166-2:BG", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Burkina Faso", "alpha2": "BF", "alpha3": "BFA", "country-code": "854", "iso_3166-2": "ISO 3166-2:BF", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Burundi", "alpha2": "BI", "alpha3": "BDI", "country-code": "108", "iso_3166-2": "ISO 3166-2:BI", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Cambodia", "alpha2": "KH", "alpha3": "KHM", "country-code": "116", "iso_3166-2": "ISO 3166-2:KH", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Cameroon", "alpha2": "CM", "alpha3": "CMR", "country-code": "120", "iso_3166-2": "ISO 3166-2:CM", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Canada", "alpha2": "CA", "alpha3": "CAN", "country-code": "124", "iso_3166-2": "ISO 3166-2:CA", "region-code": "019", "sub-region-code": "021"},
-    {"name": "Cape Verde", "alpha2": "CV", "alpha3": "CPV", "country-code": "132", "iso_3166-2": "ISO 3166-2:CV", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Cayman Islands", "alpha2": "KY", "alpha3": "CYM", "country-code": "136", "iso_3166-2": "ISO 3166-2:KY", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Central African Republic", "alpha2": "CF", "alpha3": "CAF", "country-code": "140", "iso_3166-2": "ISO 3166-2:CF", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Chad", "alpha2": "TD", "alpha3": "TCD", "country-code": "148", "iso_3166-2": "ISO 3166-2:TD", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Chile", "alpha2": "CL", "alpha3": "CHL", "country-code": "152", "iso_3166-2": "ISO 3166-2:CL", "region-code": "019", "sub-region-code": "005"},
-    {"name": "China", "alpha2": "CN", "alpha3": "CHN", "country-code": "156", "iso_3166-2": "ISO 3166-2:CN", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Christmas Island", "alpha2": "CX", "alpha3": "CXR", "country-code": "162", "iso_3166-2": "ISO 3166-2:CX"},
-    {"name": "Cocos (Keeling) Islands", "alpha2": "CC", "alpha3": "CCK", "country-code": "166", "iso_3166-2": "ISO 3166-2:CC"},
-    {"name": "Colombia", "alpha2": "CO", "alpha3": "COL", "country-code": "170", "iso_3166-2": "ISO 3166-2:CO", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Comoros", "alpha2": "KM", "alpha3": "COM", "country-code": "174", "iso_3166-2": "ISO 3166-2:KM", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Congo", "alpha2": "CG", "alpha3": "COG", "country-code": "178", "iso_3166-2": "ISO 3166-2:CG", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Congo, the Democratic Republic of the", "alpha2": "CD", "alpha3": "COD", "country-code": "180", "iso_3166-2": "ISO 3166-2:CD", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Cook Islands", "alpha2": "CK", "alpha3": "COK", "country-code": "184", "iso_3166-2": "ISO 3166-2:CK", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Costa Rica", "alpha2": "CR", "alpha3": "CRI", "country-code": "188", "iso_3166-2": "ISO 3166-2:CR", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Côte d'Ivoire", "alpha2": "CI", "alpha3": "CIV", "country-code": "384", "iso_3166-2": "ISO 3166-2:CI", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Croatia", "alpha2": "HR", "alpha3": "HRV", "country-code": "191", "iso_3166-2": "ISO 3166-2:HR", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Cuba", "alpha2": "CU", "alpha3": "CUB", "country-code": "192", "iso_3166-2": "ISO 3166-2:CU", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Curaçao", "alpha2": "CW", "alpha3": "CUW", "country-code": "531", "iso_3166-2": "ISO 3166-2:CW", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Cyprus", "alpha2": "CY", "alpha3": "CYP", "country-code": "196", "iso_3166-2": "ISO 3166-2:CY", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Czech Republic", "alpha2": "CZ", "alpha3": "CZE", "country-code": "203", "iso_3166-2": "ISO 3166-2:CZ", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Denmark", "alpha2": "DK", "alpha3": "DNK", "country-code": "208", "iso_3166-2": "ISO 3166-2:DK", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Djibouti", "alpha2": "DJ", "alpha3": "DJI", "country-code": "262", "iso_3166-2": "ISO 3166-2:DJ", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Dominica", "alpha2": "DM", "alpha3": "DMA", "country-code": "212", "iso_3166-2": "ISO 3166-2:DM", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Dominican Republic", "alpha2": "DO", "alpha3": "DOM", "country-code": "214", "iso_3166-2": "ISO 3166-2:DO", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Ecuador", "alpha2": "EC", "alpha3": "ECU", "country-code": "218", "iso_3166-2": "ISO 3166-2:EC", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Egypt", "alpha2": "EG", "alpha3": "EGY", "country-code": "818", "iso_3166-2": "ISO 3166-2:EG", "region-code": "002", "sub-region-code": "015"},
-    {"name": "El Salvador", "alpha2": "SV", "alpha3": "SLV", "country-code": "222", "iso_3166-2": "ISO 3166-2:SV", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Equatorial Guinea", "alpha2": "GQ", "alpha3": "GNQ", "country-code": "226", "iso_3166-2": "ISO 3166-2:GQ", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Eritrea", "alpha2": "ER", "alpha3": "ERI", "country-code": "232", "iso_3166-2": "ISO 3166-2:ER", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Estonia", "alpha2": "EE", "alpha3": "EST", "country-code": "233", "iso_3166-2": "ISO 3166-2:EE", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Ethiopia", "alpha2": "ET", "alpha3": "ETH", "country-code": "231", "iso_3166-2": "ISO 3166-2:ET", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Falkland Islands (Malvinas)", "alpha2": "FK", "alpha3": "FLK", "country-code": "238", "iso_3166-2": "ISO 3166-2:FK", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Faroe Islands", "alpha2": "FO", "alpha3": "FRO", "country-code": "234", "iso_3166-2": "ISO 3166-2:FO", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Fiji", "alpha2": "FJ", "alpha3": "FJI", "country-code": "242", "iso_3166-2": "ISO 3166-2:FJ", "region-code": "009", "sub-region-code": "054"},
-    {"name": "Finland", "alpha2": "FI", "alpha3": "FIN", "country-code": "246", "iso_3166-2": "ISO 3166-2:FI", "region-code": "150", "sub-region-code": "154"},
-    {"name": "France", "alpha2": "FR", "alpha3": "FRA", "country-code": "250", "iso_3166-2": "ISO 3166-2:FR", "region-code": "150", "sub-region-code": "155"},
-    {"name": "French Guiana", "alpha2": "GF", "alpha3": "GUF", "country-code": "254", "iso_3166-2": "ISO 3166-2:GF", "region-code": "019", "sub-region-code": "005"},
-    {"name": "French Polynesia", "alpha2": "PF", "alpha3": "PYF", "country-code": "258", "iso_3166-2": "ISO 3166-2:PF", "region-code": "009", "sub-region-code": "061"},
-    {"name": "French Southern Territories", "alpha2": "TF", "alpha3": "ATF", "country-code": "260", "iso_3166-2": "ISO 3166-2:TF"},
-    {"name": "Gabon", "alpha2": "GA", "alpha3": "GAB", "country-code": "266", "iso_3166-2": "ISO 3166-2:GA", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Gambia", "alpha2": "GM", "alpha3": "GMB", "country-code": "270", "iso_3166-2": "ISO 3166-2:GM", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Georgia", "alpha2": "GE", "alpha3": "GEO", "country-code": "268", "iso_3166-2": "ISO 3166-2:GE", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Germany", "alpha2": "DE", "alpha3": "DEU", "country-code": "276", "iso_3166-2": "ISO 3166-2:DE", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Ghana", "alpha2": "GH", "alpha3": "GHA", "country-code": "288", "iso_3166-2": "ISO 3166-2:GH", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Gibraltar", "alpha2": "GI", "alpha3": "GIB", "country-code": "292", "iso_3166-2": "ISO 3166-2:GI", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Greece", "alpha2": "GR", "alpha3": "GRC", "country-code": "300", "iso_3166-2": "ISO 3166-2:GR", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Greenland", "alpha2": "GL", "alpha3": "GRL", "country-code": "304", "iso_3166-2": "ISO 3166-2:GL", "region-code": "019", "sub-region-code": "021"},
-    {"name": "Grenada", "alpha2": "GD", "alpha3": "GRD", "country-code": "308", "iso_3166-2": "ISO 3166-2:GD", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Guadeloupe", "alpha2": "GP", "alpha3": "GLP", "country-code": "312", "iso_3166-2": "ISO 3166-2:GP", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Guam", "alpha2": "GU", "alpha3": "GUM", "country-code": "316", "iso_3166-2": "ISO 3166-2:GU", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Guatemala", "alpha2": "GT", "alpha3": "GTM", "country-code": "320", "iso_3166-2": "ISO 3166-2:GT", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Guernsey", "alpha2": "GG", "alpha3": "GGY", "country-code": "831", "iso_3166-2": "ISO 3166-2:GG", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Guinea", "alpha2": "GN", "alpha3": "GIN", "country-code": "324", "iso_3166-2": "ISO 3166-2:GN", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Guinea-Bissau", "alpha2": "GW", "alpha3": "GNB", "country-code": "624", "iso_3166-2": "ISO 3166-2:GW", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Guyana", "alpha2": "GY", "alpha3": "GUY", "country-code": "328", "iso_3166-2": "ISO 3166-2:GY", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Haiti", "alpha2": "HT", "alpha3": "HTI", "country-code": "332", "iso_3166-2": "ISO 3166-2:HT", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Heard Island and McDonald Islands", "alpha2": "HM", "alpha3": "HMD", "country-code": "334", "iso_3166-2": "ISO 3166-2:HM"},
-    {"name": "Holy See (Vatican City State)", "alpha2": "VA", "alpha3": "VAT", "country-code": "336", "iso_3166-2": "ISO 3166-2:VA", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Honduras", "alpha2": "HN", "alpha3": "HND", "country-code": "340", "iso_3166-2": "ISO 3166-2:HN", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Hong Kong", "alpha2": "HK", "alpha3": "HKG", "country-code": "344", "iso_3166-2": "ISO 3166-2:HK", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Hungary", "alpha2": "HU", "alpha3": "HUN", "country-code": "348", "iso_3166-2": "ISO 3166-2:HU", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Iceland", "alpha2": "IS", "alpha3": "ISL", "country-code": "352", "iso_3166-2": "ISO 3166-2:IS", "region-code": "150", "sub-region-code": "154"},
-    {"name": "India", "alpha2": "IN", "alpha3": "IND", "country-code": "356", "iso_3166-2": "ISO 3166-2:IN", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Indonesia", "alpha2": "ID", "alpha3": "IDN", "country-code": "360", "iso_3166-2": "ISO 3166-2:ID", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Iran, Islamic Republic of", "alpha2": "IR", "alpha3": "IRN", "country-code": "364", "iso_3166-2": "ISO 3166-2:IR", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Iraq", "alpha2": "IQ", "alpha3": "IRQ", "country-code": "368", "iso_3166-2": "ISO 3166-2:IQ", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Ireland", "alpha2": "IE", "alpha3": "IRL", "country-code": "372", "iso_3166-2": "ISO 3166-2:IE", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Isle of Man", "alpha2": "IM", "alpha3": "IMN", "country-code": "833", "iso_3166-2": "ISO 3166-2:IM", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Israel", "alpha2": "IL", "alpha3": "ISR", "country-code": "376", "iso_3166-2": "ISO 3166-2:IL", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Italy", "alpha2": "IT", "alpha3": "ITA", "country-code": "380", "iso_3166-2": "ISO 3166-2:IT", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Jamaica", "alpha2": "JM", "alpha3": "JAM", "country-code": "388", "iso_3166-2": "ISO 3166-2:JM", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Japan", "alpha2": "JP", "alpha3": "JPN", "country-code": "392", "iso_3166-2": "ISO 3166-2:JP", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Jersey", "alpha2": "JE", "alpha3": "JEY", "country-code": "832", "iso_3166-2": "ISO 3166-2:JE", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Jordan", "alpha2": "JO", "alpha3": "JOR", "country-code": "400", "iso_3166-2": "ISO 3166-2:JO", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Kazakhstan", "alpha2": "KZ", "alpha3": "KAZ", "country-code": "398", "iso_3166-2": "ISO 3166-2:KZ", "region-code": "142", "sub-region-code": "143"},
-    {"name": "Kenya", "alpha2": "KE", "alpha3": "KEN", "country-code": "404", "iso_3166-2": "ISO 3166-2:KE", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Kiribati", "alpha2": "KI", "alpha3": "KIR", "country-code": "296", "iso_3166-2": "ISO 3166-2:KI", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Korea, Democratic People's Republic of", "alpha2": "KP", "alpha3": "PRK", "country-code": "408", "iso_3166-2": "ISO 3166-2:KP", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Korea, Republic of", "alpha2": "KR", "alpha3": "KOR", "country-code": "410", "iso_3166-2": "ISO 3166-2:KR", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Kuwait", "alpha2": "KW", "alpha3": "KWT", "country-code": "414", "iso_3166-2": "ISO 3166-2:KW", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Kyrgyzstan", "alpha2": "KG", "alpha3": "KGZ", "country-code": "417", "iso_3166-2": "ISO 3166-2:KG", "region-code": "142", "sub-region-code": "143"},
-    {"name": "Lao People's Democratic Republic", "alpha2": "LA", "alpha3": "LAO", "country-code": "418", "iso_3166-2": "ISO 3166-2:LA", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Latvia", "alpha2": "LV", "alpha3": "LVA", "country-code": "428", "iso_3166-2": "ISO 3166-2:LV", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Lebanon", "alpha2": "LB", "alpha3": "LBN", "country-code": "422", "iso_3166-2": "ISO 3166-2:LB", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Lesotho", "alpha2": "LS", "alpha3": "LSO", "country-code": "426", "iso_3166-2": "ISO 3166-2:LS", "region-code": "002", "sub-region-code": "018"},
-    {"name": "Liberia", "alpha2": "LR", "alpha3": "LBR", "country-code": "430", "iso_3166-2": "ISO 3166-2:LR", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Libya", "alpha2": "LY", "alpha3": "LBY", "country-code": "434", "iso_3166-2": "ISO 3166-2:LY", "region-code": "002", "sub-region-code": "015"},
-    {"name": "Liechtenstein", "alpha2": "LI", "alpha3": "LIE", "country-code": "438", "iso_3166-2": "ISO 3166-2:LI", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Lithuania", "alpha2": "LT", "alpha3": "LTU", "country-code": "440", "iso_3166-2": "ISO 3166-2:LT", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Luxembourg", "alpha2": "LU", "alpha3": "LUX", "country-code": "442", "iso_3166-2": "ISO 3166-2:LU", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Macao", "alpha2": "MO", "alpha3": "MAC", "country-code": "446", "iso_3166-2": "ISO 3166-2:MO", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Macedonia, the former Yugoslav Republic of", "alpha2": "MK", "alpha3": "MKD", "country-code": "807", "iso_3166-2": "ISO 3166-2:MK", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Madagascar", "alpha2": "MG", "alpha3": "MDG", "country-code": "450", "iso_3166-2": "ISO 3166-2:MG", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Malawi", "alpha2": "MW", "alpha3": "MWI", "country-code": "454", "iso_3166-2": "ISO 3166-2:MW", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Malaysia", "alpha2": "MY", "alpha3": "MYS", "country-code": "458", "iso_3166-2": "ISO 3166-2:MY", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Maldives", "alpha2": "MV", "alpha3": "MDV", "country-code": "462", "iso_3166-2": "ISO 3166-2:MV", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Mali", "alpha2": "ML", "alpha3": "MLI", "country-code": "466", "iso_3166-2": "ISO 3166-2:ML", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Malta", "alpha2": "MT", "alpha3": "MLT", "country-code": "470", "iso_3166-2": "ISO 3166-2:MT", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Marshall Islands", "alpha2": "MH", "alpha3": "MHL", "country-code": "584", "iso_3166-2": "ISO 3166-2:MH", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Martinique", "alpha2": "MQ", "alpha3": "MTQ", "country-code": "474", "iso_3166-2": "ISO 3166-2:MQ", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Mauritania", "alpha2": "MR", "alpha3": "MRT", "country-code": "478", "iso_3166-2": "ISO 3166-2:MR", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Mauritius", "alpha2": "MU", "alpha3": "MUS", "country-code": "480", "iso_3166-2": "ISO 3166-2:MU", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Mayotte", "alpha2": "YT", "alpha3": "MYT", "country-code": "175", "iso_3166-2": "ISO 3166-2:YT", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Mexico", "alpha2": "MX", "alpha3": "MEX", "country-code": "484", "iso_3166-2": "ISO 3166-2:MX", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Micronesia, Federated States of", "alpha2": "FM", "alpha3": "FSM", "country-code": "583", "iso_3166-2": "ISO 3166-2:FM", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Moldova, Republic of", "alpha2": "MD", "alpha3": "MDA", "country-code": "498", "iso_3166-2": "ISO 3166-2:MD", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Monaco", "alpha2": "MC", "alpha3": "MCO", "country-code": "492", "iso_3166-2": "ISO 3166-2:MC", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Mongolia", "alpha2": "MN", "alpha3": "MNG", "country-code": "496", "iso_3166-2": "ISO 3166-2:MN", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Montenegro", "alpha2": "ME", "alpha3": "MNE", "country-code": "499", "iso_3166-2": "ISO 3166-2:ME", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Montserrat", "alpha2": "MS", "alpha3": "MSR", "country-code": "500", "iso_3166-2": "ISO 3166-2:MS", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Morocco", "alpha2": "MA", "alpha3": "MAR", "country-code": "504", "iso_3166-2": "ISO 3166-2:MA", "region-code": "002", "sub-region-code": "015"},
-    {"name": "Mozambique", "alpha2": "MZ", "alpha3": "MOZ", "country-code": "508", "iso_3166-2": "ISO 3166-2:MZ", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Myanmar", "alpha2": "MM", "alpha3": "MMR", "country-code": "104", "iso_3166-2": "ISO 3166-2:MM", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Namibia", "alpha2": "NA", "alpha3": "NAM", "country-code": "516", "iso_3166-2": "ISO 3166-2:NA", "region-code": "002", "sub-region-code": "018"},
-    {"name": "Nauru", "alpha2": "NR", "alpha3": "NRU", "country-code": "520", "iso_3166-2": "ISO 3166-2:NR", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Nepal", "alpha2": "NP", "alpha3": "NPL", "country-code": "524", "iso_3166-2": "ISO 3166-2:NP", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Netherlands", "alpha2": "NL", "alpha3": "NLD", "country-code": "528", "iso_3166-2": "ISO 3166-2:NL", "region-code": "150", "sub-region-code": "155"},
-    {"name": "New Caledonia", "alpha2": "NC", "alpha3": "NCL", "country-code": "540", "iso_3166-2": "ISO 3166-2:NC", "region-code": "009", "sub-region-code": "054"},
-    {"name": "New Zealand", "alpha2": "NZ", "alpha3": "NZL", "country-code": "554", "iso_3166-2": "ISO 3166-2:NZ", "region-code": "009", "sub-region-code": "053"},
-    {"name": "Nicaragua", "alpha2": "NI", "alpha3": "NIC", "country-code": "558", "iso_3166-2": "ISO 3166-2:NI", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Niger", "alpha2": "NE", "alpha3": "NER", "country-code": "562", "iso_3166-2": "ISO 3166-2:NE", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Nigeria", "alpha2": "NG", "alpha3": "NGA", "country-code": "566", "iso_3166-2": "ISO 3166-2:NG", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Niue", "alpha2": "NU", "alpha3": "NIU", "country-code": "570", "iso_3166-2": "ISO 3166-2:NU", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Norfolk Island", "alpha2": "NF", "alpha3": "NFK", "country-code": "574", "iso_3166-2": "ISO 3166-2:NF", "region-code": "009", "sub-region-code": "053"},
-    {"name": "Northern Mariana Islands", "alpha2": "MP", "alpha3": "MNP", "country-code": "580", "iso_3166-2": "ISO 3166-2:MP", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Norway", "alpha2": "NO", "alpha3": "NOR", "country-code": "578", "iso_3166-2": "ISO 3166-2:NO", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Oman", "alpha2": "OM", "alpha3": "OMN", "country-code": "512", "iso_3166-2": "ISO 3166-2:OM", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Pakistan", "alpha2": "PK", "alpha3": "PAK", "country-code": "586", "iso_3166-2": "ISO 3166-2:PK", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Palau", "alpha2": "PW", "alpha3": "PLW", "country-code": "585", "iso_3166-2": "ISO 3166-2:PW", "region-code": "009", "sub-region-code": "057"},
-    {"name": "Palestine, State of", "alpha2": "PS", "alpha3": "PSE", "country-code": "275", "iso_3166-2": "ISO 3166-2:PS", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Panama", "alpha2": "PA", "alpha3": "PAN", "country-code": "591", "iso_3166-2": "ISO 3166-2:PA", "region-code": "019", "sub-region-code": "013"},
-    {"name": "Papua New Guinea", "alpha2": "PG", "alpha3": "PNG", "country-code": "598", "iso_3166-2": "ISO 3166-2:PG", "region-code": "009", "sub-region-code": "054"},
-    {"name": "Paraguay", "alpha2": "PY", "alpha3": "PRY", "country-code": "600", "iso_3166-2": "ISO 3166-2:PY", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Peru", "alpha2": "PE", "alpha3": "PER", "country-code": "604", "iso_3166-2": "ISO 3166-2:PE", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Philippines", "alpha2": "PH", "alpha3": "PHL", "country-code": "608", "iso_3166-2": "ISO 3166-2:PH", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Pitcairn", "alpha2": "PN", "alpha3": "PCN", "country-code": "612", "iso_3166-2": "ISO 3166-2:PN", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Poland", "alpha2": "PL", "alpha3": "POL", "country-code": "616", "iso_3166-2": "ISO 3166-2:PL", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Portugal", "alpha2": "PT", "alpha3": "PRT", "country-code": "620", "iso_3166-2": "ISO 3166-2:PT", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Puerto Rico", "alpha2": "PR", "alpha3": "PRI", "country-code": "630", "iso_3166-2": "ISO 3166-2:PR", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Qatar", "alpha2": "QA", "alpha3": "QAT", "country-code": "634", "iso_3166-2": "ISO 3166-2:QA", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Réunion", "alpha2": "RE", "alpha3": "REU", "country-code": "638", "iso_3166-2": "ISO 3166-2:RE", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Romania", "alpha2": "RO", "alpha3": "ROU", "country-code": "642", "iso_3166-2": "ISO 3166-2:RO", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Russian Federation", "alpha2": "RU", "alpha3": "RUS", "country-code": "643", "iso_3166-2": "ISO 3166-2:RU", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Rwanda", "alpha2": "RW", "alpha3": "RWA", "country-code": "646", "iso_3166-2": "ISO 3166-2:RW", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Saint Barthélemy", "alpha2": "BL", "alpha3": "BLM", "country-code": "652", "iso_3166-2": "ISO 3166-2:BL", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Saint Helena, Ascension and Tristan da Cunha", "alpha2": "SH", "alpha3": "SHN", "country-code": "654", "iso_3166-2": "ISO 3166-2:SH", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Saint Kitts and Nevis", "alpha2": "KN", "alpha3": "KNA", "country-code": "659", "iso_3166-2": "ISO 3166-2:KN", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Saint Lucia", "alpha2": "LC", "alpha3": "LCA", "country-code": "662", "iso_3166-2": "ISO 3166-2:LC", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Saint Martin (French part)", "alpha2": "MF", "alpha3": "MAF", "country-code": "663", "iso_3166-2": "ISO 3166-2:MF", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Saint Pierre and Miquelon", "alpha2": "PM", "alpha3": "SPM", "country-code": "666", "iso_3166-2": "ISO 3166-2:PM", "region-code": "019", "sub-region-code": "021"},
-    {"name": "Saint Vincent and the Grenadines", "alpha2": "VC", "alpha3": "VCT", "country-code": "670", "iso_3166-2": "ISO 3166-2:VC", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Samoa", "alpha2": "WS", "alpha3": "WSM", "country-code": "882", "iso_3166-2": "ISO 3166-2:WS", "region-code": "009", "sub-region-code": "061"},
-    {"name": "San Marino", "alpha2": "SM", "alpha3": "SMR", "country-code": "674", "iso_3166-2": "ISO 3166-2:SM", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Sao Tome and Principe", "alpha2": "ST", "alpha3": "STP", "country-code": "678", "iso_3166-2": "ISO 3166-2:ST", "region-code": "002", "sub-region-code": "017"},
-    {"name": "Saudi Arabia", "alpha2": "SA", "alpha3": "SAU", "country-code": "682", "iso_3166-2": "ISO 3166-2:SA", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Senegal", "alpha2": "SN", "alpha3": "SEN", "country-code": "686", "iso_3166-2": "ISO 3166-2:SN", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Serbia", "alpha2": "RS", "alpha3": "SRB", "country-code": "688", "iso_3166-2": "ISO 3166-2:RS", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Seychelles", "alpha2": "SC", "alpha3": "SYC", "country-code": "690", "iso_3166-2": "ISO 3166-2:SC", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Sierra Leone", "alpha2": "SL", "alpha3": "SLE", "country-code": "694", "iso_3166-2": "ISO 3166-2:SL", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Singapore", "alpha2": "SG", "alpha3": "SGP", "country-code": "702", "iso_3166-2": "ISO 3166-2:SG", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Sint Maarten (Dutch part)", "alpha2": "SX", "alpha3": "SXM", "country-code": "534", "iso_3166-2": "ISO 3166-2:SX", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Slovakia", "alpha2": "SK", "alpha3": "SVK", "country-code": "703", "iso_3166-2": "ISO 3166-2:SK", "region-code": "150", "sub-region-code": "151"},
-    {"name": "Slovenia", "alpha2": "SI", "alpha3": "SVN", "country-code": "705", "iso_3166-2": "ISO 3166-2:SI", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Solomon Islands", "alpha2": "SB", "alpha3": "SLB", "country-code": "090", "iso_3166-2": "ISO 3166-2:SB", "region-code": "009", "sub-region-code": "054"},
-    {"name": "Somalia", "alpha2": "SO", "alpha3": "SOM", "country-code": "706", "iso_3166-2": "ISO 3166-2:SO", "region-code": "002", "sub-region-code": "014"},
-    {"name": "South Africa", "alpha2": "ZA", "alpha3": "ZAF", "country-code": "710", "iso_3166-2": "ISO 3166-2:ZA", "region-code": "002", "sub-region-code": "018"},
-    {"name": "South Georgia and the South Sandwich Islands", "alpha2": "GS", "alpha3": "SGS", "country-code": "239", "iso_3166-2": "ISO 3166-2:GS"},
-    {"name": "South Sudan", "alpha2": "SS", "alpha3": "SSD", "country-code": "728", "iso_3166-2": "ISO 3166-2:SS", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Spain", "alpha2": "ES", "alpha3": "ESP", "country-code": "724", "iso_3166-2": "ISO 3166-2:ES", "region-code": "150", "sub-region-code": "039"},
-    {"name": "Sri Lanka", "alpha2": "LK", "alpha3": "LKA", "country-code": "144", "iso_3166-2": "ISO 3166-2:LK", "region-code": "142", "sub-region-code": "034"},
-    {"name": "Sudan", "alpha2": "SD", "alpha3": "SDN", "country-code": "729", "iso_3166-2": "ISO 3166-2:SD", "region-code": "002", "sub-region-code": "015"},
-    {"name": "Suriname", "alpha2": "SR", "alpha3": "SUR", "country-code": "740", "iso_3166-2": "ISO 3166-2:SR", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Svalbard and Jan Mayen", "alpha2": "SJ", "alpha3": "SJM", "country-code": "744", "iso_3166-2": "ISO 3166-2:SJ", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Swaziland", "alpha2": "SZ", "alpha3": "SWZ", "country-code": "748", "iso_3166-2": "ISO 3166-2:SZ", "region-code": "002", "sub-region-code": "018"},
-    {"name": "Sweden", "alpha2": "SE", "alpha3": "SWE", "country-code": "752", "iso_3166-2": "ISO 3166-2:SE", "region-code": "150", "sub-region-code": "154"},
-    {"name": "Switzerland", "alpha2": "CH", "alpha3": "CHE", "country-code": "756", "iso_3166-2": "ISO 3166-2:CH", "region-code": "150", "sub-region-code": "155"},
-    {"name": "Syrian Arab Republic", "alpha2": "SY", "alpha3": "SYR", "country-code": "760", "iso_3166-2": "ISO 3166-2:SY", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Taiwan, Province of China", "alpha2": "TW", "alpha3": "TWN", "country-code": "158", "iso_3166-2": "ISO 3166-2:TW", "region-code": "142", "sub-region-code": "030"},
-    {"name": "Tajikistan", "alpha2": "TJ", "alpha3": "TJK", "country-code": "762", "iso_3166-2": "ISO 3166-2:TJ", "region-code": "142", "sub-region-code": "143"},
-    {"name": "Tanzania, United Republic of", "alpha2": "TZ", "alpha3": "TZA", "country-code": "834", "iso_3166-2": "ISO 3166-2:TZ", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Thailand", "alpha2": "TH", "alpha3": "THA", "country-code": "764", "iso_3166-2": "ISO 3166-2:TH", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Timor-Leste", "alpha2": "TL", "alpha3": "TLS", "country-code": "626", "iso_3166-2": "ISO 3166-2:TL", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Togo", "alpha2": "TG", "alpha3": "TGO", "country-code": "768", "iso_3166-2": "ISO 3166-2:TG", "region-code": "002", "sub-region-code": "011"},
-    {"name": "Tokelau", "alpha2": "TK", "alpha3": "TKL", "country-code": "772", "iso_3166-2": "ISO 3166-2:TK", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Tonga", "alpha2": "TO", "alpha3": "TON", "country-code": "776", "iso_3166-2": "ISO 3166-2:TO", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Trinidad and Tobago", "alpha2": "TT", "alpha3": "TTO", "country-code": "780", "iso_3166-2": "ISO 3166-2:TT", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Tunisia", "alpha2": "TN", "alpha3": "TUN", "country-code": "788", "iso_3166-2": "ISO 3166-2:TN", "region-code": "002", "sub-region-code": "015"},
-    {"name": "Turkey", "alpha2": "TR", "alpha3": "TUR", "country-code": "792", "iso_3166-2": "ISO 3166-2:TR", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Turkmenistan", "alpha2": "TM", "alpha3": "TKM", "country-code": "795", "iso_3166-2": "ISO 3166-2:TM", "region-code": "142", "sub-region-code": "143"},
-    {"name": "Turks and Caicos Islands", "alpha2": "TC", "alpha3": "TCA", "country-code": "796", "iso_3166-2": "ISO 3166-2:TC", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Tuvalu", "alpha2": "TV", "alpha3": "TUV", "country-code": "798", "iso_3166-2": "ISO 3166-2:TV", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Uganda", "alpha2": "UG", "alpha3": "UGA", "country-code": "800", "iso_3166-2": "ISO 3166-2:UG", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Ukraine", "alpha2": "UA", "alpha3": "UKR", "country-code": "804", "iso_3166-2": "ISO 3166-2:UA", "region-code": "150", "sub-region-code": "151"},
-    {"name": "United Arab Emirates", "alpha2": "AE", "alpha3": "ARE", "country-code": "784", "iso_3166-2": "ISO 3166-2:AE", "region-code": "142", "sub-region-code": "145"},
-    {"name": "United Kingdom", "alpha2": "GB", "alpha3": "GBR", "country-code": "826", "iso_3166-2": "ISO 3166-2:GB", "region-code": "150", "sub-region-code": "154"},
-    {"name": "United States", "alpha2": "US", "alpha3": "USA", "country-code": "840", "iso_3166-2": "ISO 3166-2:US", "region-code": "019", "sub-region-code": "021"},
-    {"name": "United States Minor Outlying Islands", "alpha2": "UM", "alpha3": "UMI", "country-code": "581", "iso_3166-2": "ISO 3166-2:UM"},
-    {"name": "Uruguay", "alpha2": "UY", "alpha3": "URY", "country-code": "858", "iso_3166-2": "ISO 3166-2:UY", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Uzbekistan", "alpha2": "UZ", "alpha3": "UZB", "country-code": "860", "iso_3166-2": "ISO 3166-2:UZ", "region-code": "142", "sub-region-code": "143"},
-    {"name": "Vanuatu", "alpha2": "VU", "alpha3": "VUT", "country-code": "548", "iso_3166-2": "ISO 3166-2:VU", "region-code": "009", "sub-region-code": "054"},
-    {"name": "Venezuela, Bolivarian Republic of", "alpha2": "VE", "alpha3": "VEN", "country-code": "862", "iso_3166-2": "ISO 3166-2:VE", "region-code": "019", "sub-region-code": "005"},
-    {"name": "Viet Nam", "alpha2": "VN", "alpha3": "VNM", "country-code": "704", "iso_3166-2": "ISO 3166-2:VN", "region-code": "142", "sub-region-code": "035"},
-    {"name": "Virgin Islands, British", "alpha2": "VG", "alpha3": "VGB", "country-code": "092", "iso_3166-2": "ISO 3166-2:VG", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Virgin Islands, U.S.", "alpha2": "VI", "alpha3": "VIR", "country-code": "850", "iso_3166-2": "ISO 3166-2:VI", "region-code": "019", "sub-region-code": "029"},
-    {"name": "Wallis and Futuna", "alpha2": "WF", "alpha3": "WLF", "country-code": "876", "iso_3166-2": "ISO 3166-2:WF", "region-code": "009", "sub-region-code": "061"},
-    {"name": "Western Sahara", "alpha2": "EH", "alpha3": "ESH", "country-code": "732", "iso_3166-2": "ISO 3166-2:EH", "region-code": "002", "sub-region-code": "015"},
-    {"name": "Yemen", "alpha2": "YE", "alpha3": "YEM", "country-code": "887", "iso_3166-2": "ISO 3166-2:YE", "region-code": "142", "sub-region-code": "145"},
-    {"name": "Zambia", "alpha2": "ZM", "alpha3": "ZMB", "country-code": "894", "iso_3166-2": "ISO 3166-2:ZM", "region-code": "002", "sub-region-code": "014"},
-    {"name": "Zimbabwe", "alpha2": "ZW", "alpha3": "ZWE", "country-code": "716", "iso_3166-2": "ISO 3166-2:ZW", "region-code": "002", "sub-region-code": "014"}
-  ],
-  getCountryFromName: function (name) {
-    for (var i = 0; i < this.ISO_3166.length; i++) {
-      if (this.ISO_3166[i].name.toLowerCase().indexOf(name.toLowerCase()) > -1) {
-        return this.ISO_3166[i];
-      }
-    }
-    return null;
-  },
-  getCountryFromCode: function (code) {
-    for (var i = 0; i < this.ISO_3166.length; i++) {
-      if (code.toLowerCase().indexOf(this.ISO_3166[i].alpha2.toLowerCase()) > -1 || code.toLowerCase().indexOf(this.ISO_3166[i].alpha3.toLowerCase()) > -1) {
-        return this.ISO_3166[i];
-      }
-    }
-    return null;
-  },
-  getISOAlpha2: function (code) {
-    var _country = HueGeo.getCountryFromCode(code);
-    return _country ? _country.alpha2 : "AQ";
-  },
-  getISOAlpha3: function (code) {
-    var _country = HueGeo.getCountryFromCode(code);
-    return _country ? _country.alpha3 : "ATA";
-  },
-  getCity: function (city, callback) {
-    var api = new NominatimAPI();
-    api.lookupCity(city, function (rawdata) {
-      if (rawdata.length > 1) {
-        callback(rawdata);
-      }
-      else {
-        callback(rawdata[0]);
-      }
-    });
-  },
-  getCityCoordinates: function (city, callback) {
-    var api = new NominatimAPI();
-    api.lookupCity(city, function (rawdata) {
-      if (rawdata.length > 1) {
-        callback(rawdata);
-      }
-      else {
-        callback(rawdata[0].lat, rawdata[0].lon);
-      }
-    });
-  },
-  getAddressFromCoordinates: function (lat, lng, callback) {
-    var api = new NominatimAPI();
-    api.lookupAddress(lat + "," + lng, function (rawdata) {
-      if (rawdata.length > 1) {
-        callback(rawdata);
-      }
-      else {
-        callback(rawdata[0].display_name);
-      }
-    });
-  },
-
-  getAddressCoordinates: function (address, callback) {
-    var api = new NominatimAPI();
-    api.lookupAddress(address, function (rawdata) {
-      if (rawdata.length > 1) {
-        callback(rawdata);
-      }
-      else {
-        callback(rawdata[0].lat, rawdata[0].lon);
-      }
-    });
-  }
-};
-
-var NominatimAPI = function (options) {
-  this.BASE_URL = "http://nominatim.openstreetmap.org/search?format=json";
-  this.limit = options && options.limit ? options.limit : 1;
-
-  this.lookupCity = function (city, callback) {
-    $.getJSON(this.BASE_URL + "&city=" + city + "&limit=" + this.limit + "&json_callback=?", function (data) {
-      callback(data);
-    });
-  };
-
-  this.lookupAddress = function (address, callback) {
-    $.getJSON(this.BASE_URL + "&q=" + address + "&limit=" + this.limit + "&json_callback=?", function (data) {
-      callback(data);
-    });
-  };
-};

+ 0 - 310
desktop/core/src/desktop/static/desktop/js/ko.charts.leaflet.js

@@ -1,310 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-(function () {
-
-  ko.bindingHandlers.leafletMapChart = {
-    update: function (element, valueAccessor) {
-      var _options = valueAccessor();
-      var _data = _options.transformer(valueAccessor().datum);
-
-      function toggleVisibility() {
-        if (!_data.message && ((_options.visible != null && _options.visible) || _options.visible == null || typeof _options == "undefined")) {
-          $(element).show();
-          $(element).siblings(".leaflet-nodata").remove();
-        }
-        else {
-          $(element).hide();
-          if ((_data.message || (_options.visible != null && _options.visible)) && !_options.isLoading) {
-            $(element).siblings(".leaflet-nodata").remove();
-            $(element).before($("<div>").addClass("leaflet-nodata").css({ "textAlign": "center", "fontSize": "18px", "fontWeight": 700, "marginTop": "20px"}).text(_data.message || window.I18n('No Data Available.')));
-          }
-        }
-      }
-
-      if ($(element).data("mapData") == null || $(element).data("mapData") != ko.toJSON(_data) || _options.forceRedraw) {
-
-        $(element).data("mapData", ko.toJSON(_data));
-
-        var _hasAtLeastOneLat = false;
-        _data.forEach(function (item) {
-          if (item.lat != null && $.isNumeric(item.lat)) {
-            _hasAtLeastOneLat = true;
-          }
-        });
-        var _hasAtLeastOneLng = false;
-        _data.forEach(function (item) {
-          if (item.lng != null && $.isNumeric(item.lng)) {
-            _hasAtLeastOneLng = true;
-          }
-        });
-
-        if (_options.height != null) {
-          $(element).height(_options.height * 1);
-        }
-        else {
-          if ($(element).parents(".tab-pane").length > 0) {
-            $(element).height($(element).parents(".tab-pane").height() - 100);
-          }
-          else {
-            $(element).height(300);
-          }
-        }
-
-        toggleVisibility();
-
-        var _map = null;
-        if ($(element).data('_map') != null) {
-          _map = $(element).data('_map');
-          _map.removeLayer($(element).data('_markerLayer'));
-          if ($(element).data('_heatLayer')){
-            _map.removeLayer($(element).data('_heatLayer'));
-            $(element).data('_heatLayer', null);
-          }
-        }
-
-        var _clusterGroup = L.markerClusterGroup({
-          maxClusterRadius: 10,
-          polygonOptions: {
-            weight: 1.5
-          }
-        });
-
-        if (_hasAtLeastOneLat && _hasAtLeastOneLng) {
-          try {
-            if (_map == null) {
-              if (LEAFLET_DEFAULTS.mapOptions.crs) {
-                LEAFLET_DEFAULTS.mapOptions.crs = L.CRS[LEAFLET_DEFAULTS.mapOptions.crs];
-              }
-              _map = L.map(element, LEAFLET_DEFAULTS.mapOptions);
-              var tileLayerOptions = {
-                layer: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
-                attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
-              };
-              if (LEAFLET_DEFAULTS.layer) {
-                tileLayerOptions.layer = LEAFLET_DEFAULTS.layer;
-              }
-              if (LEAFLET_DEFAULTS.attribution) {
-                tileLayerOptions.attribution = LEAFLET_DEFAULTS.attribution;
-              }
-              if (LEAFLET_DEFAULTS.layerOptions) {
-                tileLayerOptions = $.extend(tileLayerOptions, LEAFLET_DEFAULTS.layerOptions);
-              }
-              L.tileLayer(tileLayerOptions.layer, tileLayerOptions).addTo(_map);
-
-              if (L.control.zoomBox) {
-                var _zoomBox = L.control.zoomBox({
-                  modal: true
-                });
-                _map.addControl(_zoomBox);
-              }
-
-              if (_options.showMoveCheckbox) {
-                var _command = L.control({
-                  position: $(element).width() > 300 ? "topright" : "bottomleft"
-                });
-
-                _command.onAdd = function (map) {
-                  var div = L.DomUtil.create("div", "leaflet-search-command leaflet-bar leaflet-move-label");
-                  div.innerHTML = '<button id="command' + $(element).parents(".card-widget").attr("id") + '" type="button" class="btn btn-mini disable-feedback"><i class="fa fa-fw fa-square-o"></i> ' + (_options.moveCheckboxLabel ? _options.moveCheckboxLabel : 'Search as I move the map') + '</button>';
-                  return div;
-                };
-
-                _command.addTo(_map);
-
-                if (_options.onRegionChange == null) {
-                  _options.onRegionChange = function () {
-                  };
-                }
-
-                var _onRegionChange = function () {
-                };
-
-                $('#command' + $(element).parents('.card-widget').attr('id')).on('click', function (e) {
-                  $(this).toggleClass('btn-primary');
-                  $(this).find('.fa-fw').toggleClass('fa-check-square');
-                  if ($(this).hasClass("btn-primary")) {
-                    if (_options.onRegionChange != null) {
-                      _onRegionChange = _options.onRegionChange;
-                    }
-                  }
-                  else {
-                    _onRegionChange = function () {
-                    };
-                  }
-                });
-
-                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
-                  $('#command' + $(element).parents('.card-widget').attr('id')).off('click');
-                });
-
-                _map.on("boxzoomend", function (e) {
-                  _onRegionChange(e.boxZoomBounds);
-                });
-                _map.on("dragend", function () {
-                  _onRegionChange(_map.getBounds());
-                });
-                _map.on("zoomend", function () {
-                  _onRegionChange(_map.getBounds());
-                });
-                _map.on("viewreset", function(){
-                  huePubSub.publish('leaflet.afterplot', element);
-                });
-              }
-
-            }
-
-            var heatData = [];
-
-            function sumHeatData(data) {
-              var sumData = [];
-              data.forEach(function (d) {
-                var found = false;
-                if (d.length === 3) {
-                  sumData.forEach(function (s) {
-                    if (d[0] == s[0] && d[1] == s[1]) {
-                      found = true;
-                      s[2] += d[2];
-                    }
-                  });
-                }
-                if (!found) {
-                  sumData.push(d);
-                }
-              });
-              return sumData;
-            }
-
-            function getMaxIntensity(data) {
-              var maxIntensity = 0;
-              data.forEach(function (d) {
-                if (d[2] > maxIntensity) {
-                  maxIntensity = d[2];
-                }
-              });
-              return maxIntensity;
-            }
-
-            _data.forEach(function (item) {
-              if (item && item.lng != null && item.lat != null) {
-                var _addMarker = false;
-                try {
-                  var _latLngObj = L.latLng(item.lat, item.lng);
-                  _addMarker = true;
-                }
-                catch (e) {
-                  if (typeof console != "undefined") {
-                    console.error(e);
-                  }
-                }
-                if (_addMarker) {
-                  var _marker = L.marker([item.lat, item.lng]);
-                  if (item.isHeat) {
-                    if (item.intensity != null) {
-                      heatData.push([item.lat, item.lng, item.intensity]);
-                    }
-                    else {
-                      heatData.push([item.lat, item.lng]);
-                    }
-                  }
-                  else {
-                    if (item.label != null) {
-                      _marker.bindPopup($.isArray(item.label) ? item.label.join("") : item.label);
-                    }
-                  }
-                  _clusterGroup.addLayer(_marker);
-                }
-              }
-            });
-            var heat;
-            if (heatData.length > 0) {
-              heatData = sumHeatData(heatData);
-              heat = L.heatLayer(heatData);
-              if (heatData[0].length === 3) { // it has intensity
-                heat.setOptions(getMaxIntensity(heatData));
-              }
-            }
-
-            window.setTimeout(function () {
-              if (!$("#command" + $(element).parents(".card-widget").attr("id")).is(":checked")) {
-                _map.fitBounds(_clusterGroup.getBounds());
-              }
-              if ($(element).find('.leaflet-tile-pane').children().length > 0) {
-                if (heatData.length == 0) {
-                  _map.addLayer(_clusterGroup);
-                  $('.leaflet-heatmap-layer').remove();
-                }
-                else {
-                  try {
-                    $('.leaflet-heatmap-layer').remove();
-                    heat.addTo(_map);
-                  }
-                  catch (e) {
-                  } // context2D not initialized yet
-                }
-              }
-              if (_options.onComplete != null) {
-                _options.onComplete();
-              }
-            }, 0);
-
-            var resizeSubscription = huePubSub.subscribe('resize.leaflet.map', function () {
-              if ($(element).data('_map')) {
-                $(element).data('_map').invalidateSize();
-                if ($(element).data('_markerLayer')) {
-                  try {
-                    $(element).data('_map').fitBounds($(element).data('_markerLayer').getBounds());
-                  }
-                  catch (e) {
-                  }
-                }
-              }
-            });
-
-            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
-              resizeSubscription.remove();
-            });
-
-          }
-          catch (err) {
-            $.jHueNotify.error(err.message);
-          }
-        }
-
-        var previousMarkerLayer = $(element).data('_markerLayer');
-        if (previousMarkerLayer) {
-          window.setTimeout(function () {
-            try {
-              previousMarkerLayer.removeLayers(previousMarkerLayer.getLayers());
-            }
-            catch(e){}
-          }, 0);
-        }
-
-        $(element).data('_map', _map);
-        $(element).data('_markerLayer', _clusterGroup);
-        $(element).data('_heatLayer', heat);
-        if (_options.onComplete != null) {
-          _options.onComplete();
-        }
-      }
-      else {
-        toggleVisibility();
-      }
-    }
-  };
-
-})();

+ 0 - 173
desktop/core/src/desktop/static/desktop/js/ko.charts.plotly.js

@@ -1,173 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-(function () {
-
-  ko.HUE_CHARTS = {
-    TYPES: {
-      LINECHART: 'lines',
-      BARCHART: 'bars',
-      TIMELINECHART: 'timeline',
-      POINTCHART: 'points',
-      PIECHART: 'pie',
-      MAP: 'map',
-      GRADIENTMAP: 'gradientmap',
-      SCATTERCHART: 'scatter'
-    }
-  };
-
-  var PLOTLY_COMMON_LAYOUT = {
-    height: 400
-  };
-
-  var PLOTLY_COMMON_OPTIONS = {
-    displaylogo: false,
-    modeBarButtonsToRemove: ['sendDataToCloud', 'hoverCompareCartesian']
-  }
-
-  function resizeHandlers(element) {
-    var resizeEvent = function () {
-      try {
-        if ($(element).is(':visible')){
-          Plotly.Plots.resize(element);
-        }
-      }
-      catch (e) {}
-    };
-    var resizeSubscription = huePubSub.subscribe('resize.plotly.chart', resizeEvent);
-
-    $(window).on('resize', resizeEvent);
-    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
-      resizeSubscription.remove();
-      $(window).off('resize', resizeEvent);
-    });
-  }
-
-  function eventEmitterSetup(element) {
-    element.on('plotly_afterplot', function () {
-      huePubSub.publish('plotly.afterplot', element);
-    });
-  }
-
-  ko.bindingHandlers.pieChart = {
-    init: function (element, valueAccessor) {
-      resizeHandlers(element);
-    },
-    update: function (element, valueAccessor) {
-      var options = valueAccessor();
-      window.clearTimeout(element.plotterTimeout);
-      element.plotterTimeout = window.setTimeout(function () {
-        var data = options.transformer(options.data);
-        var chartData = {
-          values: [],
-          labels: [],
-          type: 'pie'
-        }
-        data.forEach(function (el) {
-          chartData.values.push(el.value);
-          chartData.labels.push(el.label);
-        });
-        Plotly.newPlot(element, [chartData], PLOTLY_COMMON_LAYOUT, PLOTLY_COMMON_OPTIONS);
-        eventEmitterSetup(element);
-      }, 200);
-    }
-  };
-
-  function basicChartBuilder(element, valueAccessor, chartType) {
-    var options = valueAccessor();
-    window.clearTimeout(element.plotterTimeout);
-    element.plotterTimeout = window.setTimeout(function () {
-      var data = options.transformer(options.datum);
-      var chartData = [];
-      data.forEach(function (el) {
-        var chartSerie = {
-          x: [],
-          y: [],
-          name: el.key,
-          type: options.chartType || chartType
-        }
-        el.values.forEach(function (serie) {
-          chartSerie.x.push(serie.x);
-          chartSerie.y.push(serie.y);
-        });
-        chartData.push(chartSerie)
-      });
-      Plotly.newPlot(element, chartData, PLOTLY_COMMON_LAYOUT, PLOTLY_COMMON_OPTIONS);
-      eventEmitterSetup(element);
-    }, 200);
-  }
-
-  ko.bindingHandlers.basicChart = {
-    init: function (element, valueAccessor) {
-      resizeHandlers(element);
-    },
-    update: function (element, valueAccessor) {
-      basicChartBuilder(element, valueAccessor);
-    }
-  }
-
-  ko.bindingHandlers.barChart = {
-    init: function (element, valueAccessor) {
-      resizeHandlers(element);
-    },
-    update: function (element, valueAccessor) {
-      basicChartBuilder(element, valueAccessor, 'bar');
-    }
-  };
-
-  ko.bindingHandlers.timelineChart = {
-    init: function (element, valueAccessor) {
-      resizeHandlers(element);
-    },
-    update: function (element, valueAccessor) {
-      basicChartBuilder(element, valueAccessor, 'scatter');
-    }
-  };
-
-  ko.bindingHandlers.lineChart = {
-    init: function (element, valueAccessor) {
-      resizeHandlers(element);
-    },
-    update: function (element, valueAccessor) {
-      basicChartBuilder(element, valueAccessor, 'scatter');
-    }
-  };
-
-  ko.bindingHandlers.mapChart = {
-    init: function (element, valueAccessor) {
-      $(element).html('To-do.');
-    },
-    update: function (element, valueAccessor, allBindingsAccessor) {
-      $(element).html('To-do.');
-    }
-  };
-
-  ko.bindingHandlers.scatterChart = {
-    update: function (element, valueAccessor) {
-      $(element).html('To-do.');
-    }
-  };
-
-  ko.bindingHandlers.partitionChart = {
-    init: function (element, valueAccessor) {
-      $(element).html('To-do.');
-    },
-    update: function (element, valueAccessor) {
-      $(element).html('To-do.');
-    }
-  };
-
-})();

+ 0 - 42
desktop/core/src/desktop/static/desktop/js/nv.d3.dom.js

@@ -1,42 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-/* Facade for queueing DOM write operations
- * with Fastdom (https://github.com/wilsonpage/fastdom)
- * if available.
- * This could easily be extended to support alternate
- * implementations in the future.
- */
-nv.dom.write = function (callback) {
-  if (window.fastdom !== undefined) {
-    return fastdom.mutate(callback);
-  }
-  return callback();
-};
-
-/* Facade for queueing DOM read operations
- * with Fastdom (https://github.com/wilsonpage/fastdom)
- * if available.
- * This could easily be extended to support alternate
- * implementations in the future.
- */
-nv.dom.read = function (callback) {
-  if (window.fastdom !== undefined) {
-    return fastdom.measure(callback);
-  }
-  return callback();
-};

+ 0 - 390
desktop/core/src/desktop/static/desktop/js/nv.d3.growingDiscreteBar.js

@@ -1,390 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-//TODO: consider deprecating by adding necessary features to multiBar model
-nv.models.growingDiscreteBar = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var margin = {top: 0, right: 0, bottom: 0, left: 0}
-    , width = 960
-    , height = 500
-    , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
-    , x = d3v3.scale.ordinal()
-    , y = d3v3.scale.linear()
-    , getX = function(d) { return d.x }
-    , getY = function(d) { return d.y }
-    , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
-    , color = nv.utils.defaultColor()
-    , showValues = false
-    , valueFormat = d3v3.format(',.2f')
-    , xDomain
-    , yDomain
-    , xRange
-    , yRange
-    , dispatch = d3v3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
-    , rectClass = 'discreteBar'
-    , selectBars = null
-    ;
-
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var x0, y0;
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var availableWidth = width - margin.left - margin.right,
-          availableHeight = height - margin.top - margin.bottom,
-          container = d3v3.select(this);
-
-
-      //add series index to each data point for reference
-      data.forEach(function(series, i) {
-        series.values.forEach(function(point) {
-          point.series = i;
-          point.seriesKey = series.key;
-        });
-      });
-
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      // remap and flatten the data for use in calculating the scales' domains
-      var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
-            data.map(function(d) {
-              return d.values.map(function(d,i) {
-                return { x: getX(d,i), y: getY(d,i), y0: d.y0 }
-              })
-            });
-
-      x   .domain(xDomain || d3v3.merge(seriesData).map(function(d) { return d.x }))
-          .rangeBands(xRange || [0, availableWidth], .1);
-
-      y   .domain(yDomain || d3v3.extent(d3v3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)));
-
-
-      // If showValues, pad the Y axis range to account for label height
-      if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
-      else y.range(yRange || [availableHeight, 0]);
-
-      //store old scales if they exist
-      x0 = x0 || x;
-      y0 = y0 || y.copy().range([y(0),y(0)]);
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]);
-      var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar');
-      var gEnter = wrapEnter.append('g');
-      var g = wrap.select('g');
-
-      gEnter.append('g').attr('class', 'nv-groups');
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      //------------------------------------------------------------
-
-
-
-      //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later
-      var groups = wrap.select('.nv-groups').selectAll('.nv-group')
-          .data(function(d) { return d }, function(d) { return d.key });
-      groups.enter().append('g')
-          .style('stroke-opacity', 1e-6)
-          .style('fill-opacity', 1e-6);
-      groups.exit()
-          .transition()
-          .style('stroke-opacity', 1e-6)
-          .style('fill-opacity', 1e-6)
-          .remove();
-      groups
-          .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
-          .classed('hover', function(d) { return d.hover });
-      groups
-          .transition()
-          .style('stroke-opacity', 1)
-          .style('fill-opacity', .75);
-
-
-      var bars = groups.selectAll('g.nv-bar')
-          .data(function(d) { return d.values }).classed('selected', false);
-
-      bars.exit().remove();
-
-      selectBars = function(selected) {
-        $(selected).each(function(cnt, item){
-          bars.each(function(d, i) {
-            if (d.x == item) {
-              d3v3.select(this).classed('selected', true);
-            }
-          });
-        });
-      };
-
-
-      var barsEnter = bars.enter().append('g')
-          .attr('transform', function(d,i,j) {
-              return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')'
-          })
-          .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
-            d3v3.select(this).classed('hover', true);
-            dispatch.elementMouseover({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pos: [x(getX(d,i)) + (x.rangeBand() * (d.series + .5) / data.length), y(getY(d,i))],  // TODO: Figure out why the value appears to be shifted
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          })
-          .on('mouseout', function(d,i) {
-            d3v3.select(this).classed('hover', false);
-            dispatch.elementMouseout({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          })
-          .on('click', function(d,i) {
-            dispatch.elementClick({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pos: [x(getX(d,i)) + (x.rangeBand() * (d.series + .5) / data.length), y(getY(d,i))],  // TODO: Figure out why the value appears to be shifted
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-            d3v3.event.stopPropagation();
-          })
-          .on('dblclick', function(d,i) {
-            dispatch.elementDblClick({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pos: [x(getX(d,i)) + (x.rangeBand() * (d.series + .5) / data.length), y(getY(d,i))],  // TODO: Figure out why the value appears to be shifted
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-            d3v3.event.stopPropagation();
-          });
-
-      barsEnter.append('rect')
-          .attr('height', 0)
-          .attr('x', function(d,i,j) {
-              return (j * x.rangeBand() / data.length )
-          })
-          .attr('width', (x.rangeBand() / data.length) )
-
-      if (showValues) {
-        barsEnter.append('text')
-          .attr('text-anchor', 'middle')
-          ;
-
-        bars.select('text')
-          .text(function(d,i) { return valueFormat(getY(d,i)) })
-          .transition()
-          .attr('x', function(d,i,j) {
-			      return (j * x.rangeBand() / data.length ) + (x.rangeBand() * .9 / data.length)/2
-          })
-          .attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 })
-
-          ;
-      } else {
-        bars.selectAll('text').remove();
-      }
-
-      bars
-          .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive' })
-          .style('fill', function(d,i) { return d.color || color(d,i) })
-          .style('stroke', function(d,i) { return d.color || color(d,i) })
-        .select('rect')
-          .attr('class', rectClass)
-          .transition()
-          .attr('x', function(d,i) {
-              return d.series * x.rangeBand() / data.length
-            })
-            .attr('width', (x.rangeBand() / data.length) * 0.9)
-      bars.transition()
-          .attr('transform', function(d,i) {
-            var left = x(getX(d,i)) + x.rangeBand() * .05,
-                top = getY(d,i) < 0 ?
-                        y(0) :
-                        y(0) - y(getY(d,i)) < 1 ?
-                          y(0) - 1 : //make 1 px positive bars show up above y=0
-                          y(getY(d,i));
-
-              return 'translate(' + left + ', ' + top + ')'
-          })
-        .select('rect')
-          .attr('height', function(d,i) {
-            return  Math.max(Math.abs(y(getY(d,i)) - y((yDomain && yDomain[0]) || 0)) || 1)
-          });
-
-
-      //store old scales for use in transitions on update
-      x0 = x.copy();
-      y0 = y.copy();
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  chart.dispatch = dispatch;
-
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.x = function(_) {
-    if (!arguments.length) return getX;
-    getX = _;
-    return chart;
-  };
-
-  chart.y = function(_) {
-    if (!arguments.length) return getY;
-    getY = _;
-    return chart;
-  };
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.xScale = function(_) {
-    if (!arguments.length) return x;
-    x = _;
-    return chart;
-  };
-
-  chart.yScale = function(_) {
-    if (!arguments.length) return y;
-    y = _;
-    return chart;
-  };
-
-  chart.xDomain = function(_) {
-    if (!arguments.length) return xDomain;
-    xDomain = _;
-    return chart;
-  };
-
-  chart.yDomain = function(_) {
-    if (!arguments.length) return yDomain;
-    yDomain = _;
-    return chart;
-  };
-
-  chart.xRange = function(_) {
-    if (!arguments.length) return xRange;
-    xRange = _;
-    return chart;
-  };
-
-  chart.yRange = function(_) {
-    if (!arguments.length) return yRange;
-    yRange = _;
-    return chart;
-  };
-
-  chart.forceY = function(_) {
-    if (!arguments.length) return forceY;
-    forceY = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    return chart;
-  };
-
-  chart.id = function(_) {
-    if (!arguments.length) return id;
-    id = _;
-    return chart;
-  };
-
-  chart.showValues = function(_) {
-    if (!arguments.length) return showValues;
-    showValues = _;
-    return chart;
-  };
-
-  chart.valueFormat= function(_) {
-    if (!arguments.length) return valueFormat;
-    valueFormat = _;
-    return chart;
-  };
-
-  chart.rectClass= function(_) {
-    if (!arguments.length) return rectClass;
-    rectClass = _;
-    return chart;
-  };
-
-  chart.selectBars = function(args) {
-    if (!arguments.length) return selectBars;
-    selectBars(args);
-    return chart;
-  };
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 387
desktop/core/src/desktop/static/desktop/js/nv.d3.growingDiscreteBarChart.js

@@ -1,387 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-nv.models.growingDiscreteBarChart = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var discretebar = nv.models.growingDiscreteBar()
-    , xAxis = nv.models.axis()
-    , yAxis = nv.models.axis()
-    ;
-
-  var margin = {top: 15, right: 10, bottom: 50, left: 60}
-    , width = null
-    , height = null
-    , color = nv.utils.getColor()
-    , showXAxis = true
-    , showYAxis = true
-    , rightAlignYAxis = false
-    , staggerLabels = false
-    , tooltips = true
-    , tooltip = function(key, x, y, e, graph) {
-        return '<h3>' + key + '</h3>' +
-               '<p>' +  y + ' on ' + x + '</p>'
-      }
-    , x
-    , y
-    , noData = "No Data Available."
-    , dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'beforeUpdate')
-    , transitionDuration = 250
-    , selectBars = null
-    ;
-
-  xAxis
-    .orient('bottom')
-    .highlightZero(false)
-    .showMaxMin(false)
-    .tickFormat(function(d) { return d })
-    ;
-  yAxis
-    .orient((rightAlignYAxis) ? 'right' : 'left')
-    .tickFormat(d3v3.format(',.1f'))
-    ;
-
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var showTooltip = function(e, offsetElement) {
-    var left = ($.browser.msie && $.browser.version.indexOf("9.") > -1) ? e.e.clientX : e.e.layerX,
-        top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        x = xAxis.tickFormat()(discretebar.x()(e.point, e.pointIndex)),
-        y = yAxis.tickFormat()(discretebar.y()(e.point, e.pointIndex)),
-        content = tooltip(e.point.seriesKey, x, y, e, chart);
-
-    nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
-  };
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var container = d3v3.select(this),
-          that = this;
-
-      var availableWidth = (width  || parseInt(container.style('width')) || 960)
-                             - margin.left - margin.right,
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-
-
-      chart.update = function() {
-        dispatch.beforeUpdate();
-        container.transition().duration(transitionDuration).call(chart);
-      };
-      chart.container = this;
-
-
-      //------------------------------------------------------------
-      // Display No Data message if there's nothing to show.
-
-      if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
-        var noDataText = container.selectAll('.nv-noData').data([noData]);
-
-        noDataText.enter().append('text')
-          .attr('class', 'nvd3 nv-noData')
-          .attr('dy', '-.7em')
-          .style('text-anchor', 'middle');
-
-        noDataText
-          .attr('x', margin.left + availableWidth / 2)
-          .attr('y', margin.top + availableHeight / 2)
-          .text(function(d) { return d });
-
-        container.selectAll('.nv-discreteBarWithAxes').style('visibility', 'hidden');
-        container.selectAll('.nv-noData').style('visibility', 'visible');
-
-        return chart;
-      } else {
-        container.selectAll('.nv-discreteBarWithAxes').style('visibility', 'visible');
-        container.selectAll('.nv-noData').style('visibility', 'hidden');
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      x = discretebar.xScale();
-      y = discretebar.yScale().clamp(true);
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([data]);
-      var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes').append('g');
-      var defsEnter = gEnter.append('defs');
-      var g = wrap.select('g');
-
-      gEnter.append('g').attr('class', 'nv-x nv-axis');
-      gEnter.append('g').attr('class', 'nv-y nv-axis')
-            .append('g').attr('class', 'nv-zeroLine')
-            .append('line');
-
-      gEnter.append('g').attr('class', 'nv-barsWrap');
-
-      g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      if (rightAlignYAxis) {
-          g.select(".nv-y.nv-axis")
-              .attr("transform", "translate(" + availableWidth + ",0)");
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Main Chart Component(s)
-
-      discretebar
-        .width(availableWidth)
-        .height(availableHeight);
-
-      selectBars = discretebar.selectBars;
-
-
-      var barsWrap = g.select('.nv-barsWrap')
-          .datum(data.filter(function(d) { return !d.disabled }))
-
-      barsWrap.transition().call(discretebar);
-
-      //------------------------------------------------------------
-
-
-
-      defsEnter.append('clipPath')
-          .attr('id', 'nv-x-label-clip-' + discretebar.id())
-        .append('rect');
-
-      g.select('#nv-x-label-clip-' + discretebar.id() + ' rect')
-          .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1))
-          .attr('height', 16)
-          .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 ));
-
-
-      //------------------------------------------------------------
-      // Setup Axes
-
-      if (showXAxis) {
-          xAxis
-            .scale(x)
-            .ticks( availableWidth / 100 )
-            .tickSize(-availableHeight, 0);
-
-          g.select('.nv-x.nv-axis')
-              .attr('transform', 'translate(0,' + (y.range()[0] + ((discretebar.showValues() && y.domain()[0] < 0) ? 16 : 0)) + ')');
-          //d3v3.transition(g.select('.nv-x.nv-axis'))
-          g.select('.nv-x.nv-axis').transition()
-              .call(xAxis);
-
-
-          var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
-
-          if (staggerLabels) {
-            var rangeBand = x.rangeBand();
-            xTicks
-                .selectAll('text')
-                .attr('transform', function(d,i,j) {
-                  var self = d3v3.select(this),
-                    textLength = self.node().getComputedTextLength(),
-                    text = self.text();
-                  while (textLength > rangeBand*2 && text.length > 0) {
-                    text = text.slice(0, -1);
-                    self.text(text + '...');
-                    textLength = self.node().getComputedTextLength();
-                    if (self.text() == '...') {
-                      self.text(' ');
-                      textLength = 0;
-                    }
-                  }
-                  return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')'
-                });
-          }
-      }
-
-      if (showYAxis) {
-          yAxis
-            .scale(y)
-            .ticks( availableHeight / 36 )
-            .tickSize( -availableWidth, 0);
-
-          g.select('.nv-y.nv-axis').transition()
-              .call(yAxis);
-      }
-
-      // Zero line
-      g.select(".nv-zeroLine line")
-        .attr("x1",0)
-        .attr("x2",availableWidth)
-        .attr("y1", y(0))
-        .attr("y2", y(0))
-        ;
-
-      //------------------------------------------------------------
-
-
-      //============================================================
-      // Event Handling/Dispatching (in chart's scope)
-      //------------------------------------------------------------
-
-      dispatch.on('tooltipShow', function(e) {
-        if (tooltips) showTooltip(e, that.parentNode);
-      });
-
-      //============================================================
-
-
-    });
-
-    return chart;
-  }
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-
-  discretebar.dispatch.on('elementMouseover.tooltip', function(e) {
-    e.pos = [e.pos[0] +  margin.left, e.pos[1] + margin.top];
-    dispatch.tooltipShow(e);
-  });
-
-  discretebar.dispatch.on('elementMouseout.tooltip', function(e) {
-    dispatch.tooltipHide(e);
-  });
-
-  dispatch.on('tooltipHide', function() {
-    if (tooltips) nv.tooltip.cleanup();
-  });
-
-  //============================================================
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  // expose chart's sub-components
-  chart.dispatch = dispatch;
-  chart.discretebar = discretebar;
-  chart.xAxis = xAxis;
-  chart.yAxis = yAxis;
-
-  d3v3.rebind(chart, discretebar, 'x', 'y', 'xDomain', 'yDomain', 'xRange', 'yRange', 'forceX', 'forceY', 'id', 'showValues', 'valueFormat');
-
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    discretebar.color(color);
-    return chart;
-  };
-
-  chart.showXAxis = function(_) {
-    if (!arguments.length) return showXAxis;
-    showXAxis = _;
-    return chart;
-  };
-
-  chart.showYAxis = function(_) {
-    if (!arguments.length) return showYAxis;
-    showYAxis = _;
-    return chart;
-  };
-
-  chart.rightAlignYAxis = function(_) {
-    if(!arguments.length) return rightAlignYAxis;
-    rightAlignYAxis = _;
-    yAxis.orient( (_) ? 'right' : 'left');
-    return chart;
-  };
-
-  chart.staggerLabels = function(_) {
-    if (!arguments.length) return staggerLabels;
-    staggerLabels = _;
-    return chart;
-  };
-
-  chart.tooltips = function(_) {
-    if (!arguments.length) return tooltips;
-    tooltips = _;
-    return chart;
-  };
-
-  chart.tooltipContent = function(_) {
-    if (!arguments.length) return tooltip;
-    tooltip = _;
-    return chart;
-  };
-
-  chart.noData = function(_) {
-    if (!arguments.length) return noData;
-    noData = _;
-    return chart;
-  };
-
-  chart.transitionDuration = function(_) {
-    if (!arguments.length) return transitionDuration;
-    transitionDuration = _;
-    return chart;
-  };
-
-  chart.selectBars = function(args) {
-    if (!arguments.length) return selectBars;
-    if (selectBars) selectBars(args);
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 528
desktop/core/src/desktop/static/desktop/js/nv.d3.growingMultiBar.js

@@ -1,528 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-nv.models.growingMultiBar = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var margin = {top: 0, right: 0, bottom: 0, left: 0}
-    , width = 960
-    , height = 500
-    , x = d3v3.scale.ordinal()
-    , y = d3v3.scale.linear()
-    , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
-    , getX = function(d) { return d.x }
-    , getY = function(d) { return d.y }
-    , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
-    , clipEdge = true
-    , stacked = false
-    , stackOffset = 'zero' // options include 'silhouette', 'wiggle', 'expand', 'zero', or a custom function
-    , color = nv.utils.defaultColor()
-    , hideable = false
-    , barColor = null // adding the ability to set the color for each rather than the whole group
-    , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled
-    , delay = 0
-    , xDomain
-    , yDomain
-    , xRange
-    , yRange
-    , groupSpacing = 0.1
-    , selectBars = null
-    , dispatch = d3v3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
-    ;
-
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var x0, y0 //used to store previous scales
-      ;
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var availableWidth = width - margin.left - margin.right,
-          availableHeight = height - margin.top - margin.bottom,
-          container = d3v3.select(this);
-
-      if(hideable && data.length) hideable = [{
-        values: data[0].values.map(function(d) {
-        return {
-          x: d.x,
-          y: 0,
-          series: d.series,
-          size: 0.01
-        };}
-      )}];
-
-      if (stacked)
-        data = d3v3.layout.stack()
-                 .offset(stackOffset)
-                 .values(function(d){ return d.values })
-                 .y(getY)
-                 (!data.length && hideable ? hideable : data);
-
-
-      //add series index to each data point for reference
-      data.forEach(function(series, i) {
-        series.values.forEach(function(point) {
-          point.series = i;
-          point.seriesKey = series.key;
-        });
-      });
-
-
-      //------------------------------------------------------------
-      // HACK for negative value stacking
-      if (stacked)
-        data[0].values.map(function(d,i) {
-          var posBase = 0, negBase = 0;
-          data.map(function(d) {
-            var f = d.values[i]
-            if (typeof f != 'undefined') {
-              f.size = Math.abs(f.y);
-              if (f.y < 0) {
-                f.y1 = negBase;
-                negBase = negBase - f.size;
-              } else {
-                f.y1 = f.size + posBase;
-                posBase = posBase + f.size;
-              }
-            }
-          });
-        });
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      // remap and flatten the data for use in calculating the scales' domains
-      var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
-            data.map(function(d) {
-              return d.values.map(function(d,i) {
-                return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1 }
-              })
-            });
-
-      x   .domain(xDomain || d3v3.merge(seriesData).map(function(d) { return d.x }))
-          .rangeBands(xRange || [0, availableWidth], groupSpacing);
-
-      //y   .domain(yDomain || d3v3.extent(d3v3.merge(seriesData).map(function(d) { return d.y + (stacked ? d.y1 : 0) }).concat(forceY)))
-      y   .domain(yDomain || d3v3.extent(d3v3.merge(seriesData).map(function(d) { return stacked ? (d.y > 0 ? d.y1 : d.y1 + d.y ) : d.y }).concat(forceY)))
-          .range(yRange || [availableHeight, 0]);
-
-      // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
-      if (x.domain()[0] === x.domain()[1])
-        x.domain()[0] ?
-            x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
-          : x.domain([-1,1]);
-
-      if (y.domain()[0] === y.domain()[1])
-        y.domain()[0] ?
-            y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
-          : y.domain([-1,1]);
-
-
-      x0 = x0 || x;
-      y0 = y0 || y;
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-multibar').data([data]);
-      var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibar');
-      var defsEnter = wrapEnter.append('defs');
-      var gEnter = wrapEnter.append('g');
-      var g = wrap.select('g')
-
-      gEnter.append('g').attr('class', 'nv-groups');
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      //------------------------------------------------------------
-
-
-
-      defsEnter.append('clipPath')
-          .attr('id', 'nv-edge-clip-' + id)
-        .append('rect');
-      wrap.select('#nv-edge-clip-' + id + ' rect')
-          .attr('width', availableWidth)
-          .attr('height', nv.utils.NaNtoZero(availableHeight) >= 0 ? nv.utils.NaNtoZero(availableHeight) : 0);
-
-      g   .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
-
-
-
-      var groups = wrap.select('.nv-groups').selectAll('.nv-group')
-          .data(function(d) { return d }, function(d,i) { return i });
-      groups.enter().append('g')
-          .style('stroke-opacity', 1e-6)
-          .style('fill-opacity', 1e-6);
-      groups.exit()
-        .transition()
-        .selectAll('rect.nv-bar')
-        .delay(function(d,i) {
-             return i * delay/ data[0].values.length;
-        })
-          .attr('y', function(d) { return stacked ? y0(d.y0) : y0(0) })
-          .attr('height', 0)
-          .remove();
-      groups
-          .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
-          .classed('hover', function(d) { return d.hover })
-          .style('fill', function(d,i){ return color(d, i) })
-          .style('stroke', function(d,i){ return color(d, i) });
-      groups
-          .transition()
-          .style('stroke-opacity', 1)
-          .style('fill-opacity', .75);
-
-
-      var bars = groups.selectAll('rect.nv-bar')
-          .data(function(d) { return (hideable && !data.length) ? hideable.values : d.values }).classed('selected', false);
-
-      bars.exit().remove();
-
-      selectBars = function(selected) {
-        if (selected.rangeValues){
-          $(selected.rangeValues).each(function(cnt, item){
-            bars.each(function(d, i) {
-              if (parseInt(d.x) >= parseInt(item.from) && parseInt(d.x_end) <= parseInt(item.to)) {
-                d3v3.select(this).classed('selected', true);
-              }
-            });
-          });
-        }
-        else {
-          var _pivotField = null;
-          if (!Array.isArray(selected)){
-            _pivotField = selected.field;
-            selected = selected.selected;
-          }
-
-          $(selected).each(function(cnt, item){
-            bars.each(function(d, i) {
-              if (_pivotField != null){
-                if ((Array.isArray(_pivotField) ? ko.toJSON(d.obj.fq_fields) == ko.toJSON(_pivotField) : d.obj.fq_fields == _pivotField) && (item.values ? ko.toJSON(d.obj.fq_values) == ko.toJSON(item.values) : d.obj.fq_values == item)){
-                  d3v3.select(this).classed('selected', true);
-                }
-              }
-              else {
-                if (d.x instanceof Date){
-                  if (moment(d.x).utc().format("YYYY-MM-DD[T]HH:mm:ss[Z]") == item) {
-                    d3v3.select(this).classed('selected', true);
-                  }
-                }
-                else {
-                  if (d.x == item) {
-                    d3v3.select(this).classed('selected', true);
-                  }
-                }
-              }
-            });
-          });
-        }
-      };
-
-
-      var barsEnter = bars.enter().append('rect')
-          .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
-          .attr('x', function(d,i,j) {
-              return stacked ? 0 : (j * x.rangeBand() / data.length )
-          })
-          .attr('y', function(d) { return y0(stacked ? d.y0 : 0) })
-          .attr('height', 0)
-          .attr('width', x.rangeBand() / (stacked ? 1 : data.length) )
-          .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; })
-          ;
-      bars
-          .style('fill', function(d,i,j){ return color(d, j, i);  })
-          .style('stroke', function(d,i,j){ return color(d, j, i); });
-      barsEnter
-          .on('mouseover', function(d,i) {
-            d3v3.select(this).classed('hover', true);
-            dispatch.elementMouseover({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))],  // TODO: Figure out why the value appears to be shifted
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          })
-          .on('mouseout', function(d,i) {
-            d3v3.select(this).classed('hover', false);
-            dispatch.elementMouseout({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          })
-          .on('click', function(d,i) {
-            dispatch.elementClick({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))],  // TODO: Figure out why the value appears to be shifted
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-            d3v3.event.stopPropagation();
-          })
-          .on('dblclick', function(d,i) {
-            dispatch.elementDblClick({
-              value: getY(d,i),
-              point: d,
-              series: data[d.series],
-              pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))],  // TODO: Figure out why the value appears to be shifted
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-            d3v3.event.stopPropagation();
-          });
-      bars
-          .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
-          .transition()
-          .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; })
-
-      if (barColor) {
-        if (!disabled) disabled = data.map(function() { return true });
-        bars
-          .style('fill', function(d,i,j) { return d3v3.rgb(barColor(d,i)).darker(  disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i]  })[j]   ).toString(); })
-          .style('stroke', function(d,i,j) { return d3v3.rgb(barColor(d,i)).darker(  disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i]  })[j]   ).toString(); });
-      }
-
-
-      if (stacked)
-          bars.transition()
-            .delay(function(d,i) {
-
-                  return i * delay / data[0].values.length;
-            })
-            .attr('y', function(d,i) {
-
-              return y((stacked ? d.y1 : 0));
-            })
-            .attr('height', function(d,i) {
-              return Math.max(Math.abs(y(d.y + (stacked ? d.y0 : 0)) - y((stacked ? d.y0 : 0))),1);
-            })
-            .attr('x', function(d,i) {
-                  return stacked ? 0 : (d.series * x.rangeBand() / data.length )
-            })
-            .attr('width', x.rangeBand() / (stacked ? 1 : data.length) );
-      else
-          bars.transition()
-            .delay(function(d,i) {
-                return i * delay/ data[0].values.length;
-            })
-            .attr('x', function(d,i) {
-              return d.series * x.rangeBand() / data.length
-            })
-            .attr('width', x.rangeBand() / data.length)
-            .attr('y', function(d,i) {
-                return getY(d,i) < 0 ?
-                        y(0) :
-                        y(0) - y(getY(d,i)) < 1 ?
-                          y(0) - 1 :
-                        y(getY(d,i)) || 0;
-            })
-            .attr('height', function(d,i) {
-                return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0;
-            });
-
-
-
-      //store old scales for use in transitions on update
-      x0 = x.copy();
-      y0 = y.copy();
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  chart.dispatch = dispatch;
-
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.x = function(_) {
-    if (!arguments.length) return getX;
-    getX = _;
-    return chart;
-  };
-
-  chart.y = function(_) {
-    if (!arguments.length) return getY;
-    getY = _;
-    return chart;
-  };
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.xScale = function(_) {
-    if (!arguments.length) return x;
-    x = _;
-    return chart;
-  };
-
-  chart.yScale = function(_) {
-    if (!arguments.length) return y;
-    y = _;
-    return chart;
-  };
-
-  chart.xDomain = function(_) {
-    if (!arguments.length) return xDomain;
-    xDomain = _;
-    return chart;
-  };
-
-  chart.yDomain = function(_) {
-    if (!arguments.length) return yDomain;
-    yDomain = _;
-    return chart;
-  };
-
-  chart.xRange = function(_) {
-    if (!arguments.length) return xRange;
-    xRange = _;
-    return chart;
-  };
-
-  chart.yRange = function(_) {
-    if (!arguments.length) return yRange;
-    yRange = _;
-    return chart;
-  };
-
-  chart.forceY = function(_) {
-    if (!arguments.length) return forceY;
-    forceY = _;
-    return chart;
-  };
-
-  chart.stacked = function(_) {
-    if (!arguments.length) return stacked;
-    stacked = _;
-    return chart;
-  };
-
-  chart.stackOffset = function(_) {
-    if (!arguments.length) return stackOffset;
-    stackOffset = _;
-    return chart;
-  };
-
-  chart.clipEdge = function(_) {
-    if (!arguments.length) return clipEdge;
-    clipEdge = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    return chart;
-  };
-
-  chart.barColor = function(_) {
-    if (!arguments.length) return barColor;
-    barColor = nv.utils.getColor(_);
-    return chart;
-  };
-
-  chart.disabled = function(_) {
-    if (!arguments.length) return disabled;
-    disabled = _;
-    return chart;
-  };
-
-  chart.id = function(_) {
-    if (!arguments.length) return id;
-    id = _;
-    return chart;
-  };
-
-  chart.hideable = function(_) {
-    if (!arguments.length) return hideable;
-    hideable = _;
-    return chart;
-  };
-
-  chart.delay = function(_) {
-    if (!arguments.length) return delay;
-    delay = _;
-    return chart;
-  };
-
-  chart.groupSpacing = function(_) {
-    if (!arguments.length) return groupSpacing;
-    groupSpacing = _;
-    return chart;
-  };
-
-  chart.selectBars = function(args) {
-    if (!arguments.length) return selectBars;
-    selectBars(args);
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 569
desktop/core/src/desktop/static/desktop/js/nv.d3.growingMultiBarChart.js

@@ -1,569 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-nv.models.growingMultiBarChart = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var multibar = nv.models.growingMultiBar()
-    , xAxis = nv.models.axis()
-    , yAxis = nv.models.axis()
-    , legend = nv.models.legend()
-    , controls = nv.models.legend()
-    ;
-
-  var margin = {top: 30, right: 20, bottom: 50, left: 60}
-    , width = null
-    , height = null
-    , color = nv.utils.defaultColor()
-    , showControls = true
-    , showLegend = true
-    , showXAxis = true
-    , showYAxis = true
-    , rightAlignYAxis = false
-    , reduceXTicks = true // if false a tick will show for every data point
-    , staggerLabels = false
-    , rotateLabels = 0
-    , tooltips = true
-    , tooltip = function(key, x, y, e, graph) {
-        return '<h3>' + key + '</h3>' +
-               '<p>' +  y + ' on ' + x + '</p>'
-      }
-    , x //can be accessed via chart.xScale()
-    , y //can be accessed via chart.yScale()
-    , state = { stacked: false }
-    , defaultState = null
-    , noData = "No Data Available."
-    , dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState')
-    , controlWidth = function() { return showControls ? 180 : 0 }
-    , transitionDuration = 250
-    , selectBars = null
-    , onStateChange = null
-    ;
-
-  multibar
-    .stacked(false)
-    ;
-  xAxis
-    .orient('bottom')
-    .tickPadding(7)
-    .highlightZero(true)
-    .showMaxMin(false)
-    .tickFormat(function(d) { return d })
-    ;
-  yAxis
-    .orient((rightAlignYAxis) ? 'right' : 'left')
-    .tickFormat(d3v3.format(',.1f'))
-    ;
-
-  controls.updateState(false);
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var showTooltip = function(e, offsetElement) {
-    var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
-        top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
-        y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex)),
-        content = tooltip(e.point.seriesKey, x, y, e, chart);
-
-    nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
-  };
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var container = d3v3.select(this),
-          that = this;
-
-      var availableWidth = (width  || parseInt(container.style('width')) || 960)
-                             - margin.left - margin.right,
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-
-      chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
-      chart.container = this;
-
-      //set state.disabled
-      state.disabled = data.map(function(d) { return !!d.disabled });
-
-      if (!defaultState) {
-        var key;
-        defaultState = {};
-        for (key in state) {
-          if (state[key] instanceof Array)
-            defaultState[key] = state[key].slice(0);
-          else
-            defaultState[key] = state[key];
-        }
-      }
-      //------------------------------------------------------------
-      // Display noData message if there's nothing to show.
-
-      if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
-        var noDataText = container.selectAll('.nv-noData').data([noData]);
-
-        noDataText.enter().append('text')
-          .attr('class', 'nvd3 nv-noData')
-          .attr('dy', '-.7em')
-          .style('text-anchor', 'middle');
-
-        noDataText
-          .attr('x', margin.left + availableWidth / 2)
-          .attr('y', margin.top + availableHeight / 2)
-          .text(function(d) { return d });
-
-        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'hidden');
-        container.selectAll('.nv-noData').style('visibility', 'visible');
-
-        return chart;
-      } else {
-        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'visible');
-        container.selectAll('.nv-noData').style('visibility', 'hidden');
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      x = multibar.xScale();
-      y = multibar.yScale();
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]);
-      var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend').append('g');
-      var g = wrap.select('g');
-
-      gEnter.append('g').attr('class', 'nv-x nv-axis');
-      gEnter.append('g').attr('class', 'nv-y nv-axis');
-      gEnter.append('g').attr('class', 'nv-barsWrap');
-      gEnter.append('g').attr('class', 'nv-legendWrap');
-      gEnter.append('g').attr('class', 'nv-controlsWrap');
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Legend
-
-      if (showLegend) {
-        legend.width(availableWidth - controlWidth());
-
-        if (multibar.barColor())
-          data.forEach(function(series,i) {
-            series.color = d3v3.rgb('#ccc').darker(i * 1.5).toString();
-          })
-
-        g.select('.nv-legendWrap')
-            .datum(data)
-            .call(legend);
-
-        if (legend.height() > 50) {
-          g.select('.nv-legendWrap').style('visibility', 'hidden');
-        }
-        else {
-          g.select('.nv-legendWrap').style('visibility', 'visible');
-          if (margin.top != legend.height()) {
-            margin.top = legend.height();
-            availableHeight = (height || parseInt(container.style('height')) || 400)
-              - margin.top - margin.bottom;
-          }
-        }
-
-        g.select('.nv-legendWrap')
-            .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')');
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Controls
-
-      if (showControls) {
-        var controlsData = [
-          { key: 'Grouped', disabled: multibar.stacked() },
-          { key: 'Stacked', disabled: !multibar.stacked() }
-        ];
-
-        controls.width(controlWidth()).color(['#444', '#444', '#444']);
-        g.select('.nv-controlsWrap')
-            .datum(controlsData)
-            .attr('transform', 'translate(0,' + (-margin.top) +')')
-            .call(controls);
-      }
-
-      //------------------------------------------------------------
-
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      if (rightAlignYAxis) {
-          g.select(".nv-y.nv-axis")
-              .attr("transform", "translate(" + availableWidth + ",0)");
-      }
-
-      //------------------------------------------------------------
-      // Main Chart Component(s)
-
-      multibar
-        .disabled(data.map(function(series) { return series.disabled }))
-        .width(availableWidth)
-        .height(availableHeight)
-        .color(data.map(function(d,i) {
-          return d.color || color(d, i);
-        }).filter(function(d,i) { return !data[i].disabled }))
-
-      selectBars = multibar.selectBars;
-
-
-      var barsWrap = g.select('.nv-barsWrap')
-          .datum(data.filter(function(d) { return !d.disabled }))
-
-      barsWrap.transition().call(multibar);
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Axes
-
-      if (showXAxis) {
-          xAxis
-            .scale(x)
-            .ticks( availableWidth / 100 )
-            .tickSize(-availableHeight, 0);
-
-          g.select('.nv-x.nv-axis')
-              .attr('transform', 'translate(0,' + y.range()[0] + ')');
-          g.select('.nv-x.nv-axis').transition()
-              .call(xAxis);
-
-          var xTicks = g.select('.nv-x.nv-axis > g').selectAll('g');
-
-          xTicks
-              .selectAll('line, text')
-              .style('opacity', 1)
-
-          if (staggerLabels) {
-              var getTranslate = function(x,y) {
-                  return "translate(" + x + "," + y + ")";
-              };
-
-              var staggerUp = 5, staggerDown = 17;  //pixels to stagger by
-              // Issue #140
-              xTicks
-                .selectAll("text")
-                .attr('transform', function(d,i,j) {
-                    return  getTranslate(0, (j % 2 == 0 ? staggerUp : staggerDown));
-                  });
-
-              var totalInBetweenTicks = d3v3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;
-              g.selectAll(".nv-x.nv-axis .nv-axisMaxMin text")
-                .attr("transform", function(d,i) {
-                    return getTranslate(0, (i === 0 || totalInBetweenTicks % 2 !== 0) ? staggerDown : staggerUp);
-                });
-          }
-
-          if (reduceXTicks)
-            xTicks
-              .filter(function(d,i) {
-                  return i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0;
-                })
-              .selectAll('text, line')
-              .style('opacity', 0);
-
-          if(rotateLabels)
-            xTicks
-              .selectAll('.tick text')
-              .attr('transform', 'rotate(' + rotateLabels + ' 0,0)')
-              .style('text-anchor', rotateLabels > 0 ? 'start' : 'end');
-
-          g.select('.nv-x.nv-axis').selectAll('g.nv-axisMaxMin text')
-              .style('opacity', 1);
-      }
-
-
-      if (showYAxis) {
-          yAxis
-            .scale(y)
-            .ticks( availableHeight / 36 )
-            .tickSize( -availableWidth, 0);
-
-          g.select('.nv-y.nv-axis').transition()
-              .call(yAxis);
-      }
-
-
-      //------------------------------------------------------------
-
-
-
-      //============================================================
-      // Event Handling/Dispatching (in chart's scope)
-      //------------------------------------------------------------
-
-      legend.dispatch.on('stateChange', function(newState) {
-        state = newState;
-        dispatch.stateChange(state);
-        chart.update();
-      });
-
-      controls.dispatch.on('legendClick', function(d,i) {
-        if (!d.disabled) return;
-        controlsData = controlsData.map(function(s) {
-          s.disabled = true;
-          return s;
-        });
-        d.disabled = false;
-
-        switch (d.key) {
-          case 'Grouped':
-            multibar.stacked(false);
-            break;
-          case 'Stacked':
-            multibar.stacked(true);
-            break;
-        }
-
-        state.stacked = multibar.stacked();
-        dispatch.stateChange(state);
-        if (onStateChange != null) {
-          onStateChange(state);
-        }
-
-        chart.update();
-      });
-
-      dispatch.on('tooltipShow', function(e) {
-        if (tooltips) showTooltip(e, that.parentNode)
-      });
-
-      // Update chart from a state object passed to event handler
-      dispatch.on('changeState', function(e) {
-
-        if (typeof e.disabled !== 'undefined') {
-          data.forEach(function(series,i) {
-            series.disabled = e.disabled[i];
-          });
-
-          state.disabled = e.disabled;
-        }
-
-        if (typeof e.stacked !== 'undefined') {
-          multibar.stacked(e.stacked);
-          state.stacked = e.stacked;
-        }
-
-        chart.update();
-      });
-
-      //============================================================
-
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-
-  multibar.dispatch.on('elementMouseover.tooltip', function(e) {
-    e.pos = [e.pos[0] +  margin.left, e.pos[1] + margin.top];
-    dispatch.tooltipShow(e);
-  });
-
-  multibar.dispatch.on('elementMouseout.tooltip', function(e) {
-    dispatch.tooltipHide(e);
-  });
-  dispatch.on('tooltipHide', function() {
-    if (tooltips) nv.tooltip.cleanup();
-  });
-
-  //============================================================
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  // expose chart's sub-components
-  chart.dispatch = dispatch;
-  chart.multibar = multibar;
-  chart.legend = legend;
-  chart.xAxis = xAxis;
-  chart.yAxis = yAxis;
-
-  d3v3.rebind(chart, multibar, 'x', 'y', 'xDomain', 'yDomain', 'xRange', 'yRange', 'forceX', 'forceY', 'clipEdge',
-   'id', 'stacked', 'stackOffset', 'delay', 'barColor','groupSpacing');
-
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    legend.color(color);
-    return chart;
-  };
-
-  chart.showControls = function(_) {
-    if (!arguments.length) return showControls;
-    showControls = _;
-    return chart;
-  };
-
-  chart.showLegend = function(_) {
-    if (!arguments.length) return showLegend;
-    showLegend = _;
-    return chart;
-  };
-
-  chart.showXAxis = function(_) {
-    if (!arguments.length) return showXAxis;
-    showXAxis = _;
-    return chart;
-  };
-
-  chart.showYAxis = function(_) {
-    if (!arguments.length) return showYAxis;
-    showYAxis = _;
-    return chart;
-  };
-
-  chart.rightAlignYAxis = function(_) {
-    if(!arguments.length) return rightAlignYAxis;
-    rightAlignYAxis = _;
-    yAxis.orient( (_) ? 'right' : 'left');
-    return chart;
-  };
-
-  chart.reduceXTicks= function(_) {
-    if (!arguments.length) return reduceXTicks;
-    reduceXTicks = _;
-    return chart;
-  };
-
-  chart.rotateLabels = function(_) {
-    if (!arguments.length) return rotateLabels;
-    rotateLabels = _;
-    return chart;
-  }
-
-  chart.staggerLabels = function(_) {
-    if (!arguments.length) return staggerLabels;
-    staggerLabels = _;
-    return chart;
-  };
-
-  chart.tooltip = function(_) {
-    if (!arguments.length) return tooltip;
-    tooltip = _;
-    return chart;
-  };
-
-  chart.tooltips = function(_) {
-    if (!arguments.length) return tooltips;
-    tooltips = _;
-    return chart;
-  };
-
-  chart.tooltipContent = function(_) {
-    if (!arguments.length) return tooltip;
-    tooltip = _;
-    return chart;
-  };
-
-  chart.state = function(_) {
-    if (!arguments.length) return state;
-    state = _;
-    return chart;
-  };
-
-  chart.defaultState = function(_) {
-    if (!arguments.length) return defaultState;
-    defaultState = _;
-    return chart;
-  };
-
-  chart.noData = function(_) {
-    if (!arguments.length) return noData;
-    noData = _;
-    return chart;
-  };
-
-  chart.transitionDuration = function(_) {
-    if (!arguments.length) return transitionDuration;
-    transitionDuration = _;
-    return chart;
-  };
-
-  chart.selectBars = function(args) {
-    if (!arguments.length) return selectBars;
-    if (selectBars) selectBars(args);
-    return chart;
-  };
-
-  chart.onStateChange = function(_) {
-    if (!arguments.length) return onStateChange;
-    onStateChange = _;
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 481
desktop/core/src/desktop/static/desktop/js/nv.d3.growingPie.js

@@ -1,481 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-nv.models.growingPie = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var margin = {top: 0, right: 0, bottom: 0, left: 0}
-    , width = 500
-    , height = 500
-    , getX = function(d) { return d.x }
-    , getY = function(d) { return d.y }
-    , getDescription = function(d) { return d.description }
-    , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
-    , color = nv.utils.defaultColor()
-    , valueFormat = d3v3.format(',.2f')
-    , showLabels = true
-    , pieLabelsOutside = true
-    , donutLabelsOutside = false
-    , labelType = "key"
-    , labelThreshold = .02 //if slice percentage is under this, don't show label
-    , donut = false
-    , labelSunbeamLayout = false
-    , startAngle = false
-    , endAngle = false
-    , donutRatio = 0.5
-    , selectSlices = null
-    , dispatch = d3v3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
-    ;
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var availableWidth = width - margin.left - margin.right,
-          availableHeight = height - margin.top - margin.bottom,
-          radius = Math.min(availableWidth, availableHeight) / 2,
-          arcRadius = radius-(radius / 5),
-          container = d3v3.select(this);
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      //var wrap = container.selectAll('.nv-wrap.nv-pie').data([data]);
-      var wrap = container.selectAll('.nv-wrap.nv-pie').data(data);
-      var wrapEnter = wrap.enter().append('g').attr('class','nvd3 nv-wrap nv-pie nv-chart-' + id);
-      var gEnter = wrapEnter.append('g');
-      var g = wrap.select('g');
-
-      gEnter.append('g').attr('class', 'nv-pie');
-      gEnter.append('g').attr('class', 'nv-pieLabels');
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-      g.select('.nv-pie').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
-      g.select('.nv-pieLabels').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
-
-      //------------------------------------------------------------
-
-
-      container
-          .on('click', function(d,i) {
-              dispatch.chartClick({
-                  data: d,
-                  index: i,
-                  pos: d3v3.event,
-                  id: id
-              });
-          });
-
-      function updateVariables() {
-        availableWidth = width - margin.left - margin.right;
-        availableHeight = height - margin.top - margin.bottom;
-        radius = Math.min(availableWidth, availableHeight) / 2;
-        arcRadius = radius-(radius / 5);
-      }
-
-      var arcNormal = function() {
-        updateVariables();
-        return d3v3.svg.arc().outerRadius(arcRadius);
-      }
-
-      var arcOver = function() {
-        updateVariables();
-        return d3v3.svg.arc().outerRadius(arcRadius + 10);
-      }
-
-      if (startAngle) arcNormal().startAngle(startAngle)
-      if (endAngle) arcNormal().endAngle(endAngle);
-      if (donut) arcNormal().innerRadius(radius * donutRatio);
-
-      // Setup the Pie chart and choose the data element
-      var pie = d3v3.layout.pie()
-          .sort(null)
-          .value(function(d) { return d.disabled ? 0 : getY(d) });
-
-      var slices = wrap.select('.nv-pie').selectAll('.nv-slice')
-          .data(pie).classed('selected', false);
-
-      var pieLabels = wrap.select('.nv-pieLabels').selectAll('.nv-label')
-          .data(pie);
-
-      slices.exit().remove();
-      pieLabels.exit().remove();
-
-
-      selectSlices = function(selected) {
-        $(selected).each(function(cnt, item){
-          slices.each(function(d, i) {
-            if ((typeof d.data.obj.from != "undefined" && d.data.obj.from == item) || d.data.obj.value == item) {
-              d3v3.select(this).classed('selected', true);
-              d3v3.select(this).select("path").transition().duration(100).attr("d", arcOver());
-            }
-          });
-        });
-      };
-
-      var ae = slices.enter().append('g')
-              .attr('class', 'nv-slice')
-              .on('mouseover', function(d,i){
-                d3v3.select(this).select("path").transition().duration(100).attr("d", arcOver());
-                d3v3.select(this).classed('hover', true);
-                dispatch.elementMouseover({
-                    label: getX(d.data),
-                    value: getY(d.data),
-                    point: d.data,
-                    pointIndex: i,
-                    pos: [d3v3.event.pageX, d3v3.event.pageY],
-                    id: id
-                });
-              })
-              .on('mouseout', function(d,i){
-                if (!d3v3.select(this).classed('selected')){
-                  d3v3.select(this).select("path").transition().duration(100).attr("d", arcNormal());
-                }
-                d3v3.select(this).classed('hover', false);
-                dispatch.elementMouseout({
-                    label: getX(d.data),
-                    value: getY(d.data),
-                    point: d.data,
-                    index: i,
-                    id: id
-                });
-              })
-              .on('click', function(d,i) {
-                d3v3.select(this).select("path").transition().duration(100).attr("d", arcOver());
-                dispatch.elementClick({
-                    label: getX(d.data),
-                    value: getY(d.data),
-                    point: d.data,
-                    index: i,
-                    pos: d3v3.event,
-                    id: id
-                });
-                d3v3.event.stopPropagation();
-              })
-              .on('dblclick', function(d,i) {
-                d3v3.select(this).select("path").transition().duration(100).attr("d", arcNormal());
-                dispatch.elementDblClick({
-                    label: getX(d.data),
-                    value: getY(d.data),
-                    point: d.data,
-                    index: i,
-                    pos: d3v3.event,
-                    id: id
-                });
-                d3v3.event.stopPropagation();
-              });
-
-        slices
-            .attr('fill', function(d,i) { return d.data.color || color(d,i) })
-            .attr('stroke', function(d,i) { return d.data.color || color(d,i) });
-
-        var paths = ae.append('path')
-            .each(function(d) { this._current = d; });
-            //.attr('d', arc);
-
-        slices.select('path')
-          .transition()
-            .attr('d', arcNormal())
-            .attrTween('d', arcTween);
-
-        if (showLabels) {
-          // This does the normal label
-          var labelsArc = d3v3.svg.arc().innerRadius(0);
-
-          if (pieLabelsOutside){ labelsArc = arcNormal(); }
-
-          if (donutLabelsOutside) { labelsArc = d3v3.svg.arc().outerRadius(arc().outerRadius()); }
-
-          pieLabels.enter().append("g").classed("nv-label",true)
-            .each(function(d,i) {
-                if (d.value > 0) {
-                  var group = d3v3.select(this);
-
-                  group
-                    .attr('transform', function(d) {
-                         if (labelSunbeamLayout) {
-                           d.outerRadius = arcRadius + 10; // Set Outer Coordinate
-                           d.innerRadius = arcRadius + 15; // Set Inner Coordinate
-                           var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI);
-                           if ((d.startAngle+d.endAngle)/2 < Math.PI) {
-                             rotateAngle -= 90;
-                           } else {
-                             rotateAngle += 90;
-                           }
-                           return 'translate(' + labelsArc.centroid(d) + ') rotate(' + rotateAngle + ')';
-                         } else {
-                           d.outerRadius = radius + 10; // Set Outer Coordinate
-                           d.innerRadius = radius + 15; // Set Inner Coordinate
-                           return 'translate(' + labelsArc.centroid(d) + ')'
-                         }
-                    });
-
-                  group.append('rect')
-                      .style('stroke', '#fff')
-                      .style('fill', '#fff')
-                      .attr("rx", 3)
-                      .attr("ry", 3);
-
-                  group.append('text')
-                      .style('text-anchor', labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle') //center the text on it's origin or begin/end if orthogonal aligned
-                      .style('fill', '#000')
-                }
-
-            });
-
-          var labelLocationHash = {};
-          var avgHeight = 14;
-          var avgWidth = 140;
-          var createHashKey = function(coordinates) {
-
-              return Math.floor(coordinates[0]/avgWidth) * avgWidth + ',' + Math.floor(coordinates[1]/avgHeight) * avgHeight;
-          };
-          pieLabels.transition()
-                .attr('transform', function(d) {
-                if (d.value > 0) {
-                  if (labelSunbeamLayout) {
-                      d.outerRadius = arcRadius + 10; // Set Outer Coordinate
-                      d.innerRadius = arcRadius + 15; // Set Inner Coordinate
-                      var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI);
-                      if ((d.startAngle+d.endAngle)/2 < Math.PI) {
-                        rotateAngle -= 90;
-                      } else {
-                        rotateAngle += 90;
-                      }
-                      return 'translate(' + labelsArc.centroid(d) + ') rotate(' + rotateAngle + ')';
-                    } else {
-                      d.outerRadius = radius + 10; // Set Outer Coordinate
-                      d.innerRadius = radius + 15; // Set Inner Coordinate
-
-                      /*
-                      Overlapping pie labels are not good. What this attempts to do is, prevent overlapping.
-                      Each label location is hashed, and if a hash collision occurs, we assume an overlap.
-                      Adjust the label's y-position to remove the overlap.
-                      */
-                      var center = labelsArc.centroid(d);
-                      var hashKey = createHashKey(center);
-                      if (labelLocationHash[hashKey]) {
-                        center[1] -= avgHeight;
-                      }
-                      labelLocationHash[createHashKey(center)] = true;
-                      return 'translate(' + center + ')'
-                    }
-                  }
-                });
-          pieLabels.select(".nv-label text")
-                .style('text-anchor', function(d){
-                  if (d.value > 0) {
-                    if (labelSunbeamLayout) {
-                      return ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end'); //center the text on it's origin or begin/end if orthogonal aligned
-                    }
-                    else {
-                       return 'middle';
-                    }
-                  }
-                })
-                .text(function(d, i) {
-                  if (d.value > 0) {
-                    var percent = (d.endAngle - d.startAngle) / (2 * Math.PI);
-                    var labelTypes = {
-                      "key": getX(d.data),
-                      "value": getY(d.data),
-                      "percent": d3v3.format('%')(percent)
-                    };
-                    return (d.value && percent > labelThreshold) ? labelTypes[labelType] : '';
-                  }
-                  else {
-                    return '';
-                  }
-                });
-        }
-
-
-        // Computes the angle of an arc, converting from radians to degrees.
-        function angle(d) {
-          var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
-          return a > 90 ? a - 180 : a;
-        }
-
-        function arcTween(a) {
-          a.endAngle = isNaN(a.endAngle) ? 0 : a.endAngle;
-          a.startAngle = isNaN(a.startAngle) ? 0 : a.startAngle;
-          if (!donut) a.innerRadius = 0;
-          var i = d3v3.interpolate(this._current, a);
-          this._current = i(0);
-          return function(t) {
-            return arcNormal()(i(t));
-          };
-        }
-
-        function tweenPie(b) {
-          b.innerRadius = 0;
-          var i = d3v3.interpolate({startAngle: 0, endAngle: 0}, b);
-          return function(t) {
-              return arcNormal()(i(t));
-          };
-        }
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  chart.dispatch = dispatch;
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.values = function(_) {
-    nv.log("pie.values() is no longer supported.");
-    return chart;
-  };
-
-  chart.x = function(_) {
-    if (!arguments.length) return getX;
-    getX = _;
-    return chart;
-  };
-
-  chart.y = function(_) {
-    if (!arguments.length) return getY;
-    getY = d3v3.functor(_);
-    return chart;
-  };
-
-  chart.description = function(_) {
-    if (!arguments.length) return getDescription;
-    getDescription = _;
-    return chart;
-  };
-
-  chart.showLabels = function(_) {
-    if (!arguments.length) return showLabels;
-    showLabels = _;
-    return chart;
-  };
-
-  chart.labelSunbeamLayout = function(_) {
-    if (!arguments.length) return labelSunbeamLayout;
-    labelSunbeamLayout = _;
-    return chart;
-  };
-
-  chart.donutLabelsOutside = function(_) {
-    if (!arguments.length) return donutLabelsOutside;
-    donutLabelsOutside = _;
-    return chart;
-  };
-
-  chart.pieLabelsOutside = function(_) {
-    if (!arguments.length) return pieLabelsOutside;
-    pieLabelsOutside = _;
-    return chart;
-  };
-
-  chart.labelType = function(_) {
-    if (!arguments.length) return labelType;
-    labelType = _;
-    labelType = labelType || "key";
-    return chart;
-  };
-
-  chart.donut = function(_) {
-    if (!arguments.length) return donut;
-    donut = _;
-    return chart;
-  };
-
-  chart.donutRatio = function(_) {
-    if (!arguments.length) return donutRatio;
-    donutRatio = _;
-    return chart;
-  };
-
-  chart.startAngle = function(_) {
-    if (!arguments.length) return startAngle;
-    startAngle = _;
-    return chart;
-  };
-
-  chart.endAngle = function(_) {
-    if (!arguments.length) return endAngle;
-    endAngle = _;
-    return chart;
-  };
-
-  chart.id = function(_) {
-    if (!arguments.length) return id;
-    id = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    return chart;
-  };
-
-  chart.valueFormat = function(_) {
-    if (!arguments.length) return valueFormat;
-    valueFormat = _;
-    return chart;
-  };
-
-  chart.labelThreshold = function(_) {
-    if (!arguments.length) return labelThreshold;
-    labelThreshold = _;
-    return chart;
-  };
-
-  chart.selectSlices = function(args) {
-    if (!arguments.length) return selectSlices;
-    selectSlices(args);
-    return chart;
-  };
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 300
desktop/core/src/desktop/static/desktop/js/nv.d3.legend.js

@@ -1,300 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-nv.models.legend = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var margin = {top: 5, right: 0, bottom: 5, left: 0}
-    , width = 400
-    , height = 20
-    , getKey = function(d) { return d.key }
-    , color = nv.utils.defaultColor()
-    , align = true
-    , rightAlign = true
-    , updateState = true   //If true, legend will update data.disabled and trigger a 'stateChange' dispatch.
-    , radioButtonMode = false   //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time)
-    , dispatch = d3v3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange')
-    ;
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var availableWidth = width - margin.left - margin.right,
-          container = d3v3.select(this);
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-legend').data([data]);
-      var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g');
-      var g = wrap.select('g');
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      //------------------------------------------------------------
-
-
-      var series = g.selectAll('.nv-series')
-          .data(function(d) { return d });
-      var seriesEnter = series.enter().append('g').attr('class', 'nv-series')
-          .on('mouseover', function(d,i) {
-            dispatch.legendMouseover(d,i);  //TODO: Make consistent with other event objects
-          })
-          .on('mouseout', function(d,i) {
-            dispatch.legendMouseout(d,i);
-          })
-          .on('click', function(d,i) {
-            dispatch.legendClick(d,i);
-            if (updateState) {
-               if (radioButtonMode) {
-                   //Radio button mode: set every series to disabled,
-                   //  and enable the clicked series.
-                   data.forEach(function(series) { series.disabled = true});
-                   d.disabled = false;
-               }
-               else {
-                   d.disabled = !d.disabled;
-                   if (data.every(function(series) { return series.disabled})) {
-                       //the default behavior of NVD3 legends is, if every single series
-                       // is disabled, turn all series' back on.
-                       data.forEach(function(series) { series.disabled = false});
-                   }
-               }
-               dispatch.stateChange({
-                  disabled: data.map(function(d) { return !!d.disabled })
-               });
-            }
-          })
-          .on('dblclick', function(d,i) {
-            dispatch.legendDblclick(d,i);
-            if (updateState) {
-                //the default behavior of NVD3 legends, when double clicking one,
-                // is to set all other series' to false, and make the double clicked series enabled.
-                data.forEach(function(series) {
-                   series.disabled = true;
-                });
-                d.disabled = false;
-                dispatch.stateChange({
-                    disabled: data.map(function(d) { return !!d.disabled })
-                });
-            }
-          });
-      seriesEnter.append('circle')
-          .style('stroke-width', 2)
-          .attr('class','nv-legend-symbol')
-          .attr('r', 5)
-          .style('display', function(d){return d.checkbox?'none':'inline'});
-
-      seriesEnter.append('rect')
-          .style('stroke-width', 2)
-          .attr('class','nv-legend-symbol')
-          .attr('width', 10)
-          .attr('height', 10)
-          .attr('transform', 'translate(-5,-5)')
-          .style('display', function(d){return d.checkbox?'inline':'none'});
-
-      seriesEnter.append('text')
-          .attr('text-anchor', 'start')
-          .attr('class','nv-legend-text')
-          .attr('dy', '.32em')
-          .attr('dx', '8');
-      series.classed('disabled', function(d) { return d.disabled });
-      series.exit().remove();
-      series.select('circle')
-          .style('fill', function(d,i) { return d.color || color(d,i)})
-          .style('stroke', function(d,i) { return d.color || color(d, i) });
-      series.select('rect')
-          .style('fill', function(d,i) { return d.color || color(d,i)})
-          .style('stroke', function(d,i) { return d.color || color(d, i) });
-      series.select('text').text(getKey);
-
-
-      //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option)
-
-      // NEW ALIGNING CODE, TODO: clean up
-      if (align) {
-
-        var seriesWidths = [];
-        series.each(function(d,i) {
-              var legendText = d3v3.select(this).select('text');
-              var nodeTextLength;
-              try {
-                nodeTextLength = legendText.getComputedTextLength();
-                // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead
-                if(nodeTextLength <= 0) throw Error();
-              }
-              catch(e) {
-                nodeTextLength = nv.utils.calcApproxTextWidth(legendText);
-              }
-
-              seriesWidths.push(nodeTextLength + 28); // 28 is ~ the width of the circle plus some padding
-            });
-
-        var seriesPerRow = 0;
-        var legendWidth = 0;
-        var columnWidths = [];
-
-        while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) {
-          columnWidths[seriesPerRow] = seriesWidths[seriesPerRow];
-          legendWidth += seriesWidths[seriesPerRow++];
-        }
-        if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row
-
-
-        while ( legendWidth > availableWidth && seriesPerRow > 1 ) {
-          columnWidths = [];
-          seriesPerRow--;
-
-          for (var k = 0; k < seriesWidths.length; k++) {
-            if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) )
-              columnWidths[k % seriesPerRow] = seriesWidths[k];
-          }
-
-          legendWidth = columnWidths.reduce(function(prev, cur, index, array) {
-                          return prev + cur;
-                        });
-        }
-
-        var xPositions = [];
-        for (var i = 0, curX = 0; i < seriesPerRow; i++) {
-            xPositions[i] = curX;
-            curX += columnWidths[i];
-        }
-
-        series
-            .attr('transform', function(d, i) {
-              return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * 20) + ')';
-            });
-
-        //position legend as far right as possible within the total width
-        if (rightAlign) {
-           g.attr('transform', 'translate(' + nv.utils.NaNtoZero(width - margin.right - legendWidth) + ',' + margin.top + ')');
-        }
-        else {
-           g.attr('transform', 'translate(0' + ',' + margin.top + ')');
-        }
-
-        height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * 20);
-
-      } else {
-
-        var ypos = 5,
-            newxpos = 5,
-            maxwidth = 0,
-            xpos;
-        series
-            .attr('transform', function(d, i) {
-              var length = d3v3.select(this).select('text').node().getComputedTextLength() + 28;
-              xpos = newxpos;
-
-              if (width < margin.left + margin.right + xpos + length) {
-                newxpos = xpos = 5;
-                ypos += 20;
-              }
-
-              newxpos += length;
-              if (newxpos > maxwidth) maxwidth = newxpos;
-
-              return 'translate(' + xpos + ',' + ypos + ')';
-            });
-
-        //position legend as far right as possible within the total width
-        g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')');
-
-        height = margin.top + margin.bottom + ypos + 15;
-
-      }
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  chart.dispatch = dispatch;
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.key = function(_) {
-    if (!arguments.length) return getKey;
-    getKey = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    return chart;
-  };
-
-  chart.align = function(_) {
-    if (!arguments.length) return align;
-    align = _;
-    return chart;
-  };
-
-  chart.rightAlign = function(_) {
-    if (!arguments.length) return rightAlign;
-    rightAlign = _;
-    return chart;
-  };
-
-  chart.updateState = function(_) {
-    if (!arguments.length) return updateState;
-    updateState = _;
-    return chart;
-  };
-
-  chart.radioButtonMode = function(_) {
-    if (!arguments.length) return radioButtonMode;
-    radioButtonMode = _;
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 974
desktop/core/src/desktop/static/desktop/js/nv.d3.lineWithBrushChart.js

@@ -1,974 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-nv.models.lineWithBrushChart = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var LABELS = {
-    SELECT: "Enable selection"
-  }
-
-
-  var lines = nv.models.line()
-    , xAxis = nv.models.axis()
-    , yAxis = nv.models.axis()
-    , legend = nv.models.legend()
-    , controls = nv.models.legend()
-    , interactiveLayer = nv.interactiveGuideline()
-    , brush = d3v3.svg.brush()
-    ;
-
-  var margin = {top: 30, right: 20, bottom: 50, left: 60}
-    , color = nv.utils.defaultColor()
-    , width = null
-    , height = null
-    , showLegend = true
-    , showControls = true
-    , showXAxis = true
-    , showYAxis = true
-    , rightAlignYAxis = false
-    , useInteractiveGuideline = false
-    , tooltips = true
-    , tooltip = null
-    , displayValuesInLegend = false
-    , tooltipSimple = function(value) {
-      return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
-        '<p>' + hueUtils.htmlEncode(value.x) + '</p>';
-    }
-    , tooltipSingle = function(value) {
-      return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
-        '<p>' + hueUtils.htmlEncode(value.y) + ' on ' + hueUtils.htmlEncode(value.x) + '</p>';
-    }
-    , tooltipMultiple = function (values) {
-      return '<h3>' + hueUtils.htmlEncode(values[0] && values[0].x) + '</h3>' + values.map(function (value) {
-          return '<p><span class="circle" style="background-color:'+value.color+'"></span><b>' + hueUtils.htmlEncode(value.key) + '</b> ' +  hueUtils.htmlEncode(value.y) + '</p>';
-        }).join("");
-    }
-    , x
-    , y
-    , getX = function(d) { return d.x } // accessor to get the x value
-    , getY = function(d) { return d.y } // accessor to get the y value
-    , state = {}
-    , defaultState = null
-    , noData = 'No Data Available.'
-    , dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'brush')
-    , controlWidth = function() { return showControls ? (selectionHidden ? 240 : 300) : 0 }
-    , legendWidth = 175
-    , transitionDuration = 250
-    , extent
-    , brushExtent = null
-    , selectionEnabled = false
-    , selectionHidden = false
-    , onSelectRange = null
-    , onStateChange = null
-    , onLegendChange = null
-    , onChartUpdate = null
-    ;
-
-  xAxis
-    .orient('bottom')
-    .tickPadding(7)
-    ;
-  yAxis
-    .orient((rightAlignYAxis) ? 'right' : 'left')
-    ;
-
-  controls.updateState(false);
-
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var showTooltip = function(e, offsetElement) {
-    var values;
-    if (!tooltip) {
-      values = (e.list || [e]).map(function (e) {
-        var x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
-        y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex));
-        return {x: x, y: y, key: displayValuesInLegend && (e.point.obj.field || e.point.obj.fq_fields && e.point.obj.fq_fields[0]) || e.series.key, color: e.series.color || color(e.series, e.point.series)};
-      });
-    } else {
-      values = tooltip((e.list || [e]).map(function (e) {
-        var x = lines.x()(e.point, e.pointIndex),
-        y = lines.y()(e.point, e.pointIndex);
-        return {x: x, y: y, key: displayValuesInLegend && (e.point.obj.field || e.point.obj.fq_fields && e.point.obj.fq_fields[0]) || e.series.key, color: e.series.color || color(e.series, e.point.series)};
-      }));
-    }
-
-
-    var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
-        top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        content = displayValuesInLegend ? tooltipSimple(values[0]) : tooltipMultiple(values);
-
-    nv.tooltip.show([left, top], content, null, null, offsetElement);
-  };
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var container = d3v3.select(this),
-          that = this;
-
-      var availableWidth = (width  || parseInt(container.style('width')) || 960)
-                             - margin.left - margin.right,
-          availableChartWidth = Math.max(availableWidth - showLegend * legendWidth, 0),
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-
-
-      chart.update = function() {
-        container.transition().duration(transitionDuration).each("end", onChartUpdate).call(chart);
-        filteredData = data.filter(function(series) { return !series.disabled; });
-        if (selectionEnabled){
-          enableBrush();
-        }
-        else {
-          disableBrush();
-        }
-      };
-      chart.container = this;
-
-      //set state.disabled
-      state.disabled = data.map(function(d) { return !!d.disabled });
-
-
-      if (!defaultState) {
-        var key;
-        defaultState = {};
-        for (key in state) {
-          if (state[key] instanceof Array)
-            defaultState[key] = state[key].slice(0);
-          else
-            defaultState[key] = state[key];
-        }
-      }
-
-      //------------------------------------------------------------
-      // Display noData message if there's nothing to show.
-
-      if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
-        var noDataText = container.selectAll('.nv-noData').data([noData]);
-
-        noDataText.enter().append('text')
-          .attr('class', 'nvd3 nv-noData')
-          .attr('dy', '-.7em')
-          .style('text-anchor', 'middle');
-
-        noDataText
-          .attr('x', margin.left + availableWidth / 2)
-          .attr('y', margin.top + availableHeight / 2)
-          .text(function(d) { return d; });
-
-        return chart;
-      } else {
-        container.selectAll('.nv-noData').remove();
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      x = lines.xScale();
-      y = lines.yScale();
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]);
-      var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineChart').append('g');
-      var g = wrap.select('g');
-
-      gEnter.append("rect").style("opacity",0);
-      gEnter.append('g').attr('class', 'nv-x nv-axis');
-      gEnter.append('g').attr('class', 'nv-y nv-axis');
-      gEnter.append('g').attr('class', 'nv-linesWrap');
-      // We put the legend in an another SVG to support scrolling
-      var legendDiv = d3.select(container.node().parentNode).select('div');
-      var legendSvg = legendDiv.select('svg').size() === 0 ? legendDiv.append('svg') : legendDiv.select('svg');
-      legendSvg.style('height', (data.length * 20 + 6) + 'px').selectAll('g').remove();
-      var legendG = legendSvg.append('g').attr('class', 'nvd3 nv-wrap nv-legendWrap');
-      gEnter.append('g').attr('class', 'nv-interactive');
-      gEnter.append('g').attr('class', 'nv-controlsWrap');
-
-      g.select("rect")
-        .attr("width",availableChartWidth)
-        .attr("height",(availableHeight > 0) ? availableHeight : 0);
-      //------------------------------------------------------------
-      // Legend
-
-      if (showLegend) {
-        legend.width(legendWidth / 2);
-        legend.height(availableHeight);
-        legend.rightAlign(false);
-        legend.margin({top: 5, right: 0, left: 10, bottom: 0});
-        data.forEach(function(series,i) {
-          series.color = color(series, i);
-        });
-
-        try {
-          legendG
-            .datum(data)
-            .call(legend)
-          .selectAll('text')
-          .text(function (d) {
-            if (displayValuesInLegend) {
-              var addEllipsis = d.key && d.key.length > 12;
-              return d.key && d.key.substring(0, 12) + (addEllipsis ? '...' : '');
-            } else {
-              return d.key;
-            }
-          })
-          .append('title')
-          .text(function(d){
-            return d.key;
-          });
-          if (displayValuesInLegend) {
-            legendG.selectAll('g.nv-series')
-            .append('text')
-            .classed('nv-series-value', true)
-            .text(function (d, i) {
-              return '';
-            })
-            .attr('dx', 125)
-            .attr('dy', '.32em')
-            .attr('text-anchor', 'end')
-            .append('title')
-            .classed('nv-series-value', true)
-            .text(function (d, i) {
-              return '';
-            });
-          }
-        }
-        catch (e){}
-      }
-
-      if (showControls) {
-        var controlsData = [];
-        if (! selectionHidden) {
-          controlsData.push({ key: LABELS.SELECT, disabled: !selectionEnabled, checkbox: true });
-        }
-
-        controls.width(controlWidth()).color(['#444', '#444', '#444']);
-        g.select('.nv-controlsWrap')
-            .datum(controlsData)
-            .attr('transform', 'translate(0,' + (-margin.top) +')')
-            .call(controls);
-      }
-
-
-      //------------------------------------------------------------
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      if (rightAlignYAxis) {
-          g.select(".nv-y.nv-axis")
-              .attr("transform", "translate(" + availableChartWidth + ",0)");
-      }
-
-      //------------------------------------------------------------
-      // Main Chart Component(s)
-
-
-      //------------------------------------------------------------
-      //Set up interactive layer
-      if (useInteractiveGuideline) {
-        interactiveLayer
-           .width(availableChartWidth)
-           .height(availableHeight)
-           .margin({left:margin.left, top:margin.top})
-           .svgContainer(container)
-           .xScale(x);
-        wrap.select(".nv-interactive").call(interactiveLayer);
-      }
-
-      var filteredData = data.filter(function(series) { return !series.disabled; });
-      lines
-        .width(availableChartWidth)
-        .height(availableHeight)
-        .color(data.map(function(d,i) {
-          return d.color || color(d, i);
-        }).filter(function(d,i) { return !data[i].disabled; }));
-
-
-      var linesWrap = g.select('.nv-linesWrap')
-          .datum(data.filter(function(d) { return !d.disabled; }));
-
-      linesWrap.transition().call(lines);
-
-      //------------------------------------------------------------
-
-      //------------------------------------------------------------
-      // Setup Brush
-      var overlay;
-      if (selectionEnabled){
-        enableBrush();
-        overlay = g.select('rect');
-        overlay.style('display', 'none');
-      } else {
-        disableBrush();
-        overlay = g.select('rect');
-        overlay
-        .style('display', 'inherit')
-        .attr('height', availableHeight)
-        .attr('width', availableWidth)
-        .on('mousemove', onMouseMove)
-        .on('mouseout', onMouseOut)
-        .on('click', onClick);
-      }
-
-
-      function enableBrush() {
-        if (!g) { // Can happen if the state change before the charts has been created.
-          return;
-        }
-        brush
-          .x(x)
-          .on('brush', onBrush)
-          .on('brushend', onBrushEnd);
-        if (chart.brushDomain) {
-          var brushExtent = [fGetNumericValue(chart.brushDomain[0]), fGetNumericValue(chart.brushDomain[1])];
-          var isWholeDomain =  xAxis.scale()(chart.brushDomain[0]) < 10 && xAxis.scale()(chart.brushDomain[1]) >= xAxis.range()[1];
-          if (!isWholeDomain) { // If brush is the whole domain, don't display brush
-            brush.extent(brushExtent);
-          } else {
-            brush.clear();
-          }
-        } else {
-          brush.clear();
-        }
-        var gBrush;
-        if (g.selectAll('.nv-brush')[0].length == 0) {
-          g.append('g').attr('class', 'nv-brushBackground');
-          g.append('g').attr('class', 'nv-x nv-brush');
-
-          var brushBG = g.select('.nv-brushBackground').selectAll('g')
-              .data([chart.brushExtent || brush.extent()])
-          var brushBGenter = brushBG.enter()
-              .append('g');
-
-          brushBGenter.append('rect')
-              .attr('class', 'left')
-              .attr('x', 0)
-              .attr('y', 0)
-              .attr('height', availableHeight);
-
-          brushBGenter.append('rect')
-              .attr('class', 'right')
-              .attr('x', 0)
-              .attr('y', 0)
-              .attr('height', availableHeight);
-
-          gBrush = g.select('.nv-x.nv-brush').call(brush);
-        }
-        else {
-          g.selectAll('.nv-brush').attr('display', 'inline');
-          gBrush = g.select('.nv-x.nv-brush').call(brush);
-        }
-        gBrush.selectAll('rect')
-          .attr('height', availableHeight)
-          .on('mousemove', onMouseMove)
-          .on('mouseout', onMouseOut);
-      }
-
-      function disableBrush() {
-        if (g) g.selectAll('.nv-brush').attr('display', 'none');
-      }
-
-
-      //------------------------------------------------------------
-      // Setup Axes
-
-      if (showXAxis) {
-        xAxis
-          .scale(x)
-          .ticks( availableChartWidth / 100 )
-          .tickSize(-availableHeight, 0);
-
-        g.select('.nv-x.nv-axis')
-            .attr('transform', 'translate(0,' + y.range()[0] + ')');
-        g.select('.nv-x.nv-axis')
-            .transition()
-            .call(xAxis);
-      }
-
-      if (showYAxis) {
-        yAxis
-          .scale(y)
-          .ticks( availableHeight / 36 )
-          .tickSize( -availableChartWidth, 0);
-
-        g.select('.nv-y.nv-axis')
-            .transition()
-            .call(yAxis);
-      }
-      //------------------------------------------------------------
-
-
-      //============================================================
-      // Event Handling/Dispatching (in chart's scope)
-      //------------------------------------------------------------
-
-      legend.dispatch.on('stateChange', function(newState) {
-          state = newState;
-          dispatch.stateChange(state);
-          if (onLegendChange) {
-            onLegendChange(state);
-          }
-          chart.update();
-      });
-
-      controls.dispatch.on('legendClick', function(d,i) {
-        if (typeof d.checkbox == "undefined"){
-          if (!d.disabled) return;
-          controlsData = controlsData.map(function(s) {
-            s.disabled = true;
-            return s;
-          });
-          d.disabled = false;
-        }
-
-        switch (d.key) {
-          case LABELS.SELECT:
-            selectionEnabled = !selectionEnabled;
-            break;
-        }
-        chart.update();
-      });
-
-      interactiveLayer.dispatch.on('elementMousemove', function(e) {
-          lines.clearHighlights();
-          var singlePoint, pointIndex, pointXLocation, allData = [];
-          data
-          .filter(function(series, i) {
-            series.seriesIndex = i;
-            return !series.disabled;
-          })
-          .forEach(function(series,i) {
-              pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
-              lines.highlightPoint(i, pointIndex, true);
-              var point = series.values[pointIndex];
-              if (typeof point === 'undefined') return;
-              if (typeof singlePoint === 'undefined') singlePoint = point;
-              if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
-              allData.push({
-                  key: series.key,
-                  value: chart.y()(point, pointIndex),
-                  color: color(series,series.seriesIndex)
-              });
-          });
-          //Highlight the tooltip entry based on which point the mouse is closest to.
-          if (allData.length > 2) {
-            var yValue = chart.yScale().invert(e.mouseY);
-            var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
-            var threshold = 0.03 * domainExtent;
-            var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value;}),yValue,threshold);
-            if (indexToHighlight !== null)
-              allData[indexToHighlight].highlight = true;
-          }
-
-          var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
-          interactiveLayer.tooltip
-                  .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
-                  .chartContainer(that.parentNode)
-                  .enabled(tooltips)
-                  .valueFormatter(function(d,i) {
-                     return yAxis.tickFormat()(d);
-                  })
-                  .data(
-                      {
-                        value: xValue,
-                        series: allData
-                      }
-                  )();
-
-          interactiveLayer.renderGuideLine(pointXLocation);
-
-      });
-
-      interactiveLayer.dispatch.on("elementMouseout",function(e) {
-          dispatch.tooltipHide();
-          lines.clearHighlights();
-      });
-
-      dispatch.on('tooltipShow', function(e) {
-        if (tooltips) showTooltip(e, that.parentNode);
-      });
-
-
-      dispatch.on('changeState', function(e) {
-
-        if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) {
-          data.forEach(function(series,i) {
-            series.disabled = e.disabled[i];
-          });
-
-          state.disabled = e.disabled;
-        }
-
-        chart.update();
-      });
-
-      //============================================================
-
-      function onBrush(){
-        chart.brushExtent = brush.empty() ? null : brush.extent();
-        extent = brush.empty() ? x.domain() : brush.extent();
-
-        dispatch.brush({extent: extent, brush: brush});
-      }
-      function fGetNumericValue (o) {
-        return o instanceof Date ? o.getTime() : o;
-      }
-
-      function onBrushEnd(){
-        var closest = function () {
-          if (!data[0].values.length) {
-            return [];
-          }
-          var xDate = x.invert(d3v3.mouse(this)[0]);
-
-          var distances = {};
-          var min = Number.MAX_VALUE;
-          var next = -Number.MAX_VALUE;
-          var diff;
-          var i, j;
-          for (j = 0; j < data.length; j++) {
-            for (i = 0; i < data[j].values.length; i++) {
-              diff = xDate - fGetNumericValue(data[j].values[i].x);
-              if (diff >= 0 && diff < min) {
-                min = diff;
-              } else if (diff < 0 && diff > next) {
-                next = diff;
-              }
-              if (!distances[diff]) {
-                distances[diff] = [];
-              }
-              distances[diff].push(data[j].values[i]);
-            }
-          }
-          if (distances[min][0].x_end) {
-            return [distances[min][0].x, distances[min][0].x_end];
-          } else if (distances[min] !== undefined && distances[next] !== undefined) {
-            var _from = distances[min][0].x < distances[next][0].x ? distances[min][0].x : distances[next][0].x;
-            var _to = distances[min][0].x < distances[next][0].x ? distances[next][0].x : distances[min][0].x;
-            return [_from, _to];
-          } else {
-            return [];
-          }
-        };
-
-        chart.brushExtent = extent = brush.empty() ? closest.call(this) : brush.extent();
-
-        if (onSelectRange) {
-          onSelectRange(fGetNumericValue(extent[0]), fGetNumericValue(extent[1]));
-        }
-      }
-
-      function getElByMouse () {
-        var xy = d3v3.mouse(this);
-        var px = x.invert(xy[0]);
-        if (!filteredData.length || !filteredData[0].values.length) {
-          return null;
-        }
-        var minx = Math.abs(filteredData[0].values[0].x - px);
-        var distances = {};
-        var py = y.invert(xy[1]);
-        var i, j, diff;
-        // Find closest on x axis
-        for (j = 0; j < filteredData.length; j++) {
-          for (i = 0; i < filteredData[j].values.length; i++) {
-            diff = Math.abs(fGetNumericValue(filteredData[j].values[i].x) - px);
-            if (!distances[diff]) {
-              distances[diff] = [];
-            }
-            filteredData[j].values[i].seriesKey = filteredData[j].key;
-            distances[diff].push(filteredData[j].values[i]);
-            if (diff < minx) {
-              minx = diff;
-            }
-          }
-        }
-        // Find series with y axis
-        var miny = Number.MAX_VALUE;
-        var distancesy = {};
-        for (i = 0; i < distances[minx].length; i++) {
-          diff = Math.abs(distances[minx][i].y - py);
-          if (!distancesy[diff]) {
-            distancesy[diff] = [];
-          }
-          distancesy[diff].push(distances[minx][i]);
-          if (diff < miny) {
-            miny = diff;
-          }
-        };
-
-        return distancesy[miny];
-      }
-      function onMouseMove () {
-        var el = getElByMouse.call(this);
-        // If we're mousing over a circle that doesn't have class hover, set class and dispatch mouseover
-        var target = container.selectAll('g.nv-wrap.nv-lineChart circle:not(.hover)').filter(function(rect) {
-          return el && el.some(function(d) {
-            return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
-          });
-        });
-
-        if (el && el.length && displayValuesInLegend) {
-          var legendG = legendSvg.select('.nvd3.nv-wrap.nv-legendWrap');
-          var elBySerie = el.reduce(function (elBySerie, el) {
-            elBySerie[el.seriesKey] = el;
-            return elBySerie;
-          }, {});
-          legendG.selectAll('g.nv-series text.nv-series-value')
-          .text(function (d, i) {
-            if (elBySerie[d.key]) {
-              var value = yAxis.tickFormat()(d.values[elBySerie[d.key].index].y)+'';
-              var addEllipsis = value.length > 5;
-              return value && (addEllipsis ? '...' : '') + value.substring(value.length - 5);
-            } else {
-              return '';
-            }
-          })
-          .append('title')
-          .text(function (d, i) {
-            if (elBySerie[d.key]) {
-              return yAxis.tickFormat()(d.values[elBySerie[d.key].index].y);
-            } else {
-              return '';
-            }
-          });
-        }
-        // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
-        var others = container.selectAll('g.nv-wrap.nv-lineChart circle.hover').filter(function(rect) {
-          return !el || !el.some(function(d) {
-            return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
-          });
-        });
-        if (others.size()) {
-          others.classed('hover', false)
-          .each(function (d, i) {
-            lines.dispatch.elementMouseout({
-              value: getY(d),
-              point: d,
-              series: filteredData[d.series],
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          });
-        }
-        if (target.size()) {
-          var e = d3v3.event; // Keep reference to event for setTimeout
-          setTimeout(function(){ // Delayed to conteract conflict with elementMouseout.
-            target.classed('hover', true);
-            var max, maxi;
-            target.each(function (d, i) {
-              if (isNaN(max) || max < getY(d)) {
-                max = getY(d);
-                maxi = i;
-              }
-            });
-            d3v3.select(target[0][maxi])
-            .each(function(d, i){
-              lines.dispatch.elementMouseover({
-                value: getY(d),
-                point: d,
-                series: filteredData[d.series],
-                pos: [x(getX(d)), y(getY(d))],
-                pointIndex: -1,
-                seriesIndex: d.series,
-                list: el.map(function (d) {
-                  return {
-                    value: getY(d),
-                    point: d,
-                    series: filteredData[d.series],
-                    pos: [x(getX(d)), y(getY(d))],
-                    pointIndex: -1,
-                    seriesIndex: d.series,
-                  };
-                }),
-                e: e,
-              });
-            });
-          });
-        }
-      }
-      function onMouseOut () {
-        var others = container.selectAll('g.nv-wrap.nv-lineChart circle.hover');
-        if (others.size()) {
-           others.classed('hover', false)
-          .each(function (d) {
-            lines.dispatch.elementMouseout({
-              value: getY(d),
-              point: d,
-              series: filteredData[d.series],
-              pointIndex: d.index,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          });
-        }
-      }
-      function onClick () {
-        var el = getElByMouse.call(this);
-        var d = el[0];
-        lines.dispatch.elementClick({
-          value: getY(d),
-          point: d,
-          series: filteredData[d.series],
-          pointIndex: d.index,
-          seriesIndex: d.series,
-          e: d3v3.event
-        });
-      }
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-
-  lines.dispatch.on('elementMouseover.tooltip', function(e) {
-    e.pos = [e.pos[0] +  margin.left, e.pos[1] + margin.top];
-    dispatch.tooltipShow(e);
-  });
-
-  lines.dispatch.on('elementMouseout.tooltip', function(e) {
-    dispatch.tooltipHide(e);
-  });
-
-  dispatch.on('tooltipHide', function() {
-    if (tooltips) nv.tooltip.cleanup();
-  });
-
-  //============================================================
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  // expose chart's sub-components
-  chart.dispatch = dispatch;
-  chart.lines = lines;
-  chart.legend = legend;
-  chart.xAxis = xAxis;
-  chart.yAxis = yAxis;
-  chart.xScale = lines.xScale;
-  chart.interactiveLayer = interactiveLayer;
-
-  d3v3.rebind(chart, lines, 'defined', 'isArea', 'x', 'y', 'size', 'xScale', 'yScale', 'xDomain', 'yDomain', 'xRange', 'yRange'
-    , 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'useVoronoi','id', 'interpolate');
-
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    legend.color(color);
-    return chart;
-  };
-
-  chart.showControls = function(_) {
-    if (!arguments.length) return showControls;
-    showControls = _;
-    return chart;
-  };
-
-  chart.showLegend = function(_) {
-    if (!arguments.length) return showLegend;
-    showLegend = _;
-    return chart;
-  };
-
-  chart.showXAxis = function(_) {
-    if (!arguments.length) return showXAxis;
-    showXAxis = _;
-    return chart;
-  };
-
-  chart.showYAxis = function(_) {
-    if (!arguments.length) return showYAxis;
-    showYAxis = _;
-    return chart;
-  };
-
-  chart.rightAlignYAxis = function(_) {
-    if(!arguments.length) return rightAlignYAxis;
-    rightAlignYAxis = _;
-    yAxis.orient( (_) ? 'right' : 'left');
-    return chart;
-  };
-
-  chart.useInteractiveGuideline = function(_) {
-    if(!arguments.length) return useInteractiveGuideline;
-    useInteractiveGuideline = _;
-    if (_ === true) {
-       chart.interactive(false);
-       chart.useVoronoi(false);
-    }
-    return chart;
-  };
-
-  chart.tooltips = function(_) {
-    if (!arguments.length) return tooltips;
-    tooltips = _;
-    return chart;
-  };
-
-  chart.tooltipContent = function(_) {
-    if (!arguments.length) return tooltip;
-    tooltip = _;
-    return chart;
-  };
-
-  chart.state = function(_) {
-    if (!arguments.length) return state;
-    state = _;
-    return chart;
-  };
-
-  chart.defaultState = function(_) {
-    if (!arguments.length) return defaultState;
-    defaultState = _;
-    return chart;
-  };
-
-  chart.noData = function(_) {
-    if (!arguments.length) return noData;
-    noData = _;
-    return chart;
-  };
-
-  chart.transitionDuration = function(_) {
-    if (!arguments.length) return transitionDuration;
-    transitionDuration = _;
-    return chart;
-  };
-
-  chart.enableSelection = function() {
-    selectionEnabled = true;
-    return chart;
-  };
-
-  chart.disableSelection = function() {
-    selectionEnabled = false;
-    return chart;
-  };
-
-  chart.isSelectionEnabled = function() {
-    return selectionEnabled;
-  };
-
-  chart.hideSelection = function() {
-    selectionHidden = true;
-    return chart;
-  };
-
-  chart.showSelection = function() {
-    selectionHidden = false;
-    return chart;
-  };
-
-  chart.onSelectRange = function(_) {
-    if (!arguments.length) return onSelectRange;
-    onSelectRange = _;
-    return chart;
-  };
-
-  chart.onChartUpdate = function(_) {
-    if (!arguments.length) return onChartUpdate;
-    onChartUpdate = _;
-    return chart;
-  };
-
-  chart.onStateChange = function(_) {
-    if (!arguments.length) return onStateChange;
-    onStateChange = _;
-    return chart;
-  };
-
-  chart.onLegendChange = function(_) {
-    if (!arguments.length) return onLegendChange;
-    onLegendChange = _;
-    return chart;
-  };
-
-  chart.displayValuesInLegend = function(_) {
-    if (!arguments.length) return displayValuesInLegend;
-    displayValuesInLegend = _;
-    return chart;
-  };
-
-  chart.brush = function(_) {
-    if (!arguments.length) return brush;
-    brush = _;
-    return chart;
-  };
-
-  chart.selectBars = function(args) {
-    if (!arguments.length) return selectBars;
-    if (args && args.rangeValues) {
-      chart.brushDomain = [args.rangeValues[0].from, args.rangeValues[0].to];
-    } else {
-      chart.brushDomain = null;
-    }
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 1092
desktop/core/src/desktop/static/desktop/js/nv.d3.multiBarWithBrushChart.js

@@ -1,1092 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-nv.models.multiBarWithBrushChart = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var LABELS = {
-    STACKED: "Stacked",
-    GROUPED: "Grouped",
-    SELECT: "Enable selection"
-  }
-
-  var multibar = nv.models.growingMultiBar()
-    , xAxis = nv.models.axis()
-    , yAxis = nv.models.axis()
-    , legend = nv.models.legend()
-    , controls = nv.models.legend()
-    , brush = d3v3.svg.brush()
-    ;
-
-  var margin = {top: 30, right: 20, bottom: 50, left: 60}
-    , width = null
-    , height = null
-    , color = nv.utils.defaultColor()
-    , showControls = true
-    , showLegend = true
-    , showXAxis = true
-    , showYAxis = true
-    , rightAlignYAxis = false
-    , reduceXTicks = true // if false a tick will show for every data point
-    , staggerLabels = false
-    , rotateLabels = 0
-    , tooltips = true
-    , tooltip = null
-    , minTickWidth = 60
-    , displayValuesInLegend = false
-    , tooltipContent = null
-    , tooltipSimple = function(value) {
-      return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
-        '<p>' + hueUtils.htmlEncode(value.x) + '</p>';
-    }
-    , tooltipSingle = function(value) {
-      return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
-        '<p>' + hueUtils.htmlEncode(value.y) + ' on ' + hueUtils.htmlEncode(value.x) + '</p>';
-    }
-    , tooltipMultiple = function (values) {
-      return '<h3>' + hueUtils.htmlEncode(values[0] && values[0].x) + '</h3>' + values.map(function (value) {
-          return '<p><span class="circle" style="background-color:'+value.color+'"></span><b>' + hueUtils.htmlEncode(value.key) + '</b> ' +  hueUtils.htmlEncode(value.y) + '</p>';
-        }).join("");
-    }
-    , x //can be accessed via chart.xScale()
-    , y //can be accessed via chart.yScale()
-    , getX = function(d) { return d.x } // accessor to get the x value
-    , getY = function(d) { return d.y } // accessor to get the y value
-    , state = { stacked: false, selectionEnabled: false }
-    , defaultState = null
-    , noData = "No Data Available."
-    , dispatch = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'brush')
-    , controlWidth = function() { return showControls ? (selectionHidden ? 240 : 300) : 0 }
-    , legendWidth = 175
-    , transitionDuration = 250
-    , extent
-    , brushExtent = null
-    , selectionEnabled = false
-    , selectionHidden = false
-    , stackedHidden = false
-    , onSelectRange = null
-    , onStateChange = null
-    , onLegendChange = null
-    , onChartUpdate = null
-    , selectedBars = null
-    , selectBars = null
-    ;
-
-  multibar
-    .stacked(false)
-    ;
-  xAxis
-    .orient('bottom')
-    .tickPadding(7)
-    .highlightZero(true)
-    .showMaxMin(false)
-    .tickFormat(function(d) { return d; })
-    ;
-  yAxis
-    .orient((rightAlignYAxis) ? 'right' : 'left')
-    .tickFormat(d3v3.format(',.1f'))
-    ;
-
-  controls.updateState(false);
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var showTooltip = function(e, offsetElement) {
-    var values;
-    if (!tooltipContent) {
-      values = (e.list || [e]).map(function (e) {
-        var x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
-        y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex));
-        return {x: x, y: y, key: displayValuesInLegend && (e.point.obj.field || e.point.obj.fq_fields && e.point.obj.fq_fields[0]) || e.series.key, color: e.series.color || color(e.series, e.point.series)};
-      });
-    } else {
-      values = tooltipContent((e.list || [e]).map(function (e) {
-        var x = multibar.x()(e.point, e.pointIndex),
-        y = multibar.y()(e.point, e.pointIndex);
-        return {x: x, y: y, key: displayValuesInLegend && (e.point.obj.field || e.point.obj.fq_fields && e.point.obj.fq_fields[0]) || e.series.key, color: e.series.color || color(e.series, e.point.series)};
-      }));
-    }
-
-
-    var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
-        top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        content = displayValuesInLegend ? tooltipSimple(values[0]) : tooltipMultiple(values);
-
-    nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
-  };
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var container = d3v3.select(this),
-          that = this;
-
-      var availableWidth = (width  || parseInt(container.style('width')) || 960)
-                             - margin.left - margin.right,
-          availableChartWidth = Math.max(availableWidth - showLegend * legendWidth, 0),
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-
-      chart.recommendedTicks = function() {
-        return Math.floor(availableWidth / minTickWidth);
-      };
-      chart.update = function() {
-        container
-            .transition()
-            .duration(transitionDuration)
-            .each("end", onChartUpdate)
-            .call(chart);
-        filteredData = data.filter(function(series) { return !series.disabled; });
-        if (selectionEnabled){
-          enableBrush();
-        }
-        else {
-          disableBrush();
-        }
-      };
-      chart.container = this;
-
-      //set state.disabled
-      state.disabled = data.map(function(d) { return !!d.disabled });
-
-      if (!defaultState) {
-        var key;
-        defaultState = {};
-        for (key in state) {
-          if (state[key] instanceof Array)
-            defaultState[key] = state[key].slice(0);
-          else
-            defaultState[key] = state[key];
-        }
-      }
-      //------------------------------------------------------------
-      // Display noData message if there's nothing to show.
-
-      if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
-        var noDataText = container.selectAll('.nv-noData').data([noData]);
-
-        noDataText.enter().append('text')
-          .attr('class', 'nvd3 nv-noData')
-          .attr('dy', '-.7em')
-          .style('text-anchor', 'middle');
-
-        noDataText
-          .attr('x', margin.left + availableWidth / 2)
-          .attr('y', margin.top + availableHeight / 2)
-          .text(function(d) { return d });
-
-        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'hidden');
-        container.selectAll('.nv-noData').style('visibility', 'visible');
-
-        return chart;
-      } else {
-        container.selectAll('.nv-multiBarWithLegend').style('visibility', 'visible');
-        container.selectAll('.nv-noData').style('visibility', 'hidden');
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      x = multibar.xScale();
-      y = multibar.yScale();
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]);
-      var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend').append('g');
-      var g = wrap.select('g');
-
-      gEnter.append("rect").style("opacity",0);
-      gEnter.append('g').attr('class', 'nv-x nv-axis');
-      gEnter.append('g').attr('class', 'nv-y nv-axis');
-      gEnter.append('g').attr('class', 'nv-barsWrap');
-      // We put the legend in an another SVG to support scrolling
-      var legendDiv = d3.select(container.node().parentNode).select('div');
-      var legendSvg = legendDiv.select('svg').size() === 0 ? legendDiv.append('svg') : legendDiv.select('svg');
-      legendSvg.style('height', (data.length * 20 + 6) + 'px').selectAll('g').remove();
-      var legendG = legendSvg.append('g').attr('class', 'nvd3 nv-wrap nv-legendWrap');
-      gEnter.append('g').attr('class', 'nv-controlsWrap');
-
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Legend
-
-      if (showLegend) {
-        legend.width(legendWidth / 2);
-        legend.height(availableHeight);
-        legend.rightAlign(false);
-        legend.margin({top: 5, right: 0, left: 10, bottom: 0});
-        if (multibar.barColor()) {
-          data.forEach(function(series,i) {
-            series.color = d3v3.rgb('#ccc').darker(i * 1.5).toString();
-          });
-        } else {
-          data.forEach(function(series,i) {
-            series.color = color(series, i);
-          });
-        }
-
-        try {
-          legendG
-            .datum(data)
-            .call(legend)
-          .selectAll('text')
-          .text(function (d) {
-            var value = d.key && d.key + '';
-            if (displayValuesInLegend) {
-              var addEllipsis = value && value.length > 12;
-              return value && value.substring(0, 12) + (addEllipsis ? '...' : '');
-            } else {
-              return value;
-            }
-          })
-          .append('title')
-          .text(function(d){
-            return d.key;
-          });
-          if (displayValuesInLegend) {
-            legendG.selectAll('g.nv-series')
-            .append('text')
-              .classed('nv-series-value', true)
-              .text(function (d, i) {
-                return '';
-              })
-              .attr('dx', 125)
-              .attr('dy', '.32em')
-              .attr('text-anchor', 'end')
-            .append('title')
-              .text(function (d, i) {
-                return '';
-            });
-          }
-        }
-        catch (e){}
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Controls
-
-      if (showControls) {
-        var controlsData = [];
-        if (!stackedHidden) {
-          controlsData.push({ key: LABELS.GROUPED, disabled: multibar.stacked() });
-          controlsData.push({ key: LABELS.STACKED, disabled: !multibar.stacked() });
-        }
-
-        if (! selectionHidden) {
-          controlsData.push({ key: LABELS.SELECT, disabled: !selectionEnabled, checkbox: selectionEnabled });
-        }
-
-        controls.width(controlWidth()).color(['#444', '#444', '#444']);
-        g.select('.nv-controlsWrap')
-            .datum(controlsData)
-            .attr('transform', 'translate(0,' + (-margin.top) +')')
-            .call(controls);
-      }
-
-      //------------------------------------------------------------
-
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      if (rightAlignYAxis) {
-          g.select(".nv-y.nv-axis")
-              .attr("transform", "translate(" + availableChartWidth + ",0)");
-      }
-
-      //------------------------------------------------------------
-      // Main Chart Component(s)
-      var filteredData = data.filter(function(series) { return !series.disabled; });
-      multibar
-        .disabled(data.map(function(series) { return series.disabled; }))
-        .width(availableChartWidth)
-        .height(availableHeight)
-        .color(data.map(function(d,i) {
-          return d.color || color(d, i);
-        }).filter(function(d,i) { return !data[i].disabled; }));
-
-      selectBars = multibar.selectBars;
-
-      var dataBars = data.filter(function(d) { return !d.disabled && d.bar; });
-      var barsWrap = g.select('.nv-barsWrap')
-          .datum(data.filter(function(d) { return !d.disabled; }));
-
-      barsWrap.transition().call(multibar);
-
-      //------------------------------------------------------------
-
-      //------------------------------------------------------------
-      // Setup Brush
-      var overlay;
-      if (selectionEnabled){
-        enableBrush();
-        overlay = g.select('rect');
-        overlay.style('display', 'none');
-      } else {
-        disableBrush();
-        overlay = g.select('rect');
-        overlay
-        .style('display', 'inherit')
-        .attr('height', availableHeight)
-        .attr('width', availableWidth)
-        .on('mousemove', onMouseMove)
-        .on('mouseout', onMouseOut)
-        .on('click', onClick);
-      }
-      if (selectBars && selectedBars) {
-        selectBars(selectedBars);
-      }
-
-
-      function enableBrush() {
-        if (!g) { // Can happen if the state change before the charts has been created.
-          return;
-        }
-        brush
-          .x(x)
-          .on('brush', onBrush)
-          .on('brushstart', onBrushStart)
-          .on('brushend', onBrushEnd);
-        if (chart.brushDomain) {
-          var selection = fromSelection(chart.brushDomain);
-          if (!selection.isWholeDomain) { // If brush is the whole domain, don't display brush
-            brush.extent(fromSelection(chart.brushDomain).range);
-          } else {
-            brush.clear();
-          }
-        } else {
-          brush.clear();
-        }
-        var gBrush;
-
-        if (g.selectAll('.nv-brush')[0].length == 0) {
-          g.append('g').attr('class', 'nv-brushBackground');
-          g.append('g').attr('class', 'nv-x nv-brush');
-
-          var brushBG = g.select('.nv-brushBackground').selectAll('g')
-              .data([chart.brushExtent || brush.extent()])
-          var brushBGenter = brushBG.enter()
-              .append('g');
-
-          brushBGenter.append('rect')
-              .attr('class', 'left')
-              .attr('x', 0)
-              .attr('y', 0)
-              .attr('height', availableHeight);
-
-          brushBGenter.append('rect')
-              .attr('class', 'right')
-              .attr('x', 0)
-              .attr('y', 0)
-              .attr('height', availableHeight);
-
-          gBrush = g.select('.nv-x.nv-brush')
-              .call(brush);
-        }
-        else {
-          g.selectAll('.nv-brush').attr('display', 'inline');
-          gBrush = g.select('.nv-x.nv-brush').call(brush);
-        }
-        gBrush.selectAll('rect')
-          .attr('height', availableHeight)
-          .on('mousemove', onMouseMove)
-          .on('mouseout', onMouseOut);
-      }
-
-      function disableBrush() {
-        try {
-          g.selectAll('.nv-brush').attr('display', 'none');
-        }
-        catch (e){}
-      }
-
-
-      //------------------------------------------------------------
-      // Setup Axes
-
-      if (showXAxis) {
-          function tickSkip () {
-            return Math.ceil(minTickWidth / xAxis.rangeBand());
-          }
-          xAxis
-            .scale(x)
-            .tickValues(x.domain().filter(function(d, i) { return reduceXTicks && !(i % tickSkip()); }))
-            .tickSize(-availableHeight, 0);
-
-          g.select('.nv-x.nv-axis')
-              .attr('transform', 'translate(0,' + y.range()[0] + ')');
-          g.select('.nv-x.nv-axis').transition()
-              .call(xAxis);
-
-          var xTicks = g.selectAll('.nv-x.nv-axis g.tick');
-
-          xTicks
-              .selectAll('line, text')
-              .style('opacity', 1)
-
-          if (staggerLabels) {
-              var getTranslate = function(x,y) {
-                  return "translate(" + x + "," + y + ")";
-              };
-
-              var rangeBand = x.rangeBand();
-
-              var staggerUp = 5, staggerDown = 17;  //pixels to stagger by
-              // Issue #140
-              xTicks
-                .selectAll("text")
-                .attr('transform', function(d,i,j) {
-                    var self = d3v3.select(this),
-                      textLength = self.node().getComputedTextLength(),
-                      text = self.text();
-                    while (textLength > rangeBand && text.length > 0) {
-                      text = text.slice(0, -1);
-                      self.text(text + '...');
-                      textLength = self.node().getComputedTextLength();
-                    }
-                    return  getTranslate(0, (j % 2 == 0 ? staggerUp : staggerDown));
-                  });
-
-              var totalInBetweenTicks = d3v3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;
-              g.selectAll(".nv-x.nv-axis .nv-axisMaxMin text")
-                .attr("transform", function(d,i) {
-                    return getTranslate(0, (i === 0 || totalInBetweenTicks % 2 !== 0) ? staggerDown : staggerUp);
-                });
-          }
-          if(rotateLabels)
-            xTicks
-              .selectAll('.tick text')
-              .attr('transform', 'rotate(' + rotateLabels + ' 0,0)')
-              .style('text-anchor', rotateLabels > 0 ? 'start' : 'end');
-
-          g.select('.nv-x.nv-axis').selectAll('g.nv-axisMaxMin text')
-              .style('opacity', 1);
-      }
-
-
-      if (showYAxis) {
-          yAxis
-            .scale(y)
-            .ticks( availableHeight / 36 )
-            .tickSize( -availableChartWidth, 0);
-
-          g.select('.nv-y.nv-axis').transition()
-              .call(yAxis);
-      }
-
-
-      //------------------------------------------------------------
-
-
-
-      //============================================================
-      // Event Handling/Dispatching (in chart's scope)
-      //------------------------------------------------------------
-
-      legend.dispatch.on('stateChange', function(newState) {
-        state = newState;
-        dispatch.stateChange(state);
-        if (onLegendChange != null) {
-          onLegendChange(state);
-        }
-        chart.update();
-      });
-
-      controls.dispatch.on('legendClick', function(d,i) {
-        if (typeof d.checkbox == "undefined"){
-          if (!d.disabled) return;
-          controlsData = controlsData.map(function(s) {
-            s.disabled = true;
-            return s;
-          });
-          d.disabled = false;
-        }
-
-        switch (d.key) {
-          case LABELS.GROUPED:
-            multibar.stacked(false);
-            break;
-          case LABELS.STACKED:
-            multibar.stacked(true);
-            break;
-          case LABELS.SELECT:
-            selectionEnabled = !selectionEnabled;
-            break;
-        }
-
-        state.stacked = multibar.stacked();
-        state.selectionEnabled = selectionEnabled;
-        if (onStateChange != null) {
-          onStateChange(state);
-        }
-        dispatch.stateChange(state);
-        chart.update();
-      });
-
-      dispatch.on('tooltipShow', function(e) {
-        showTooltip(e, that.parentNode)
-      });
-
-      // Update chart from a state object passed to event handler
-      dispatch.on('changeState', function(e) {
-
-        if (typeof e.disabled !== 'undefined') {
-          data.forEach(function(series,i) {
-            series.disabled = e.disabled[i];
-          });
-
-          state.disabled = e.disabled;
-        }
-
-        if (typeof e.stacked !== 'undefined') {
-          multibar.stacked(e.stacked);
-          state.stacked = e.stacked;
-        }
-
-        chart.update();
-      });
-
-      //============================================================
-      function fGetNumericValue(o) {
-        return o instanceof Date ? o.getTime() : o;
-      };
-
-
-      function onBrush(){
-        chart.brushExtent = brush.empty() ? null : brush.extent();
-        extent = brush.empty() ? x.domain() : brush.extent();
-
-        dispatch.brush({extent: extent, brush: brush});
-      }
-
-      function onBrushStart(){
-        gEnter.select(".nv-brush").select(".extent").style("display", "block");
-      }
-
-      function onBrushEnd(){
-        extent = brush.empty() ? [d3v3.mouse(this)[0], d3v3.mouse(this)[0]] : brush.extent();
-        var _leftEdges = x.range();
-        var _width = x.rangeBand() + multibar.groupSpacing() * x.rangeBand();
-        var _l, _j;
-        for(_l=0; extent[0] > (_leftEdges[_l] + _width); _l++) {}
-        _l = x.domain()[_l] != undefined ? _l : 0;
-        var _from = x.domain()[_l];
-
-        for(_j=0; extent[1] > (_leftEdges[_j] + _width); _j++) {}
-        var _to = x.domain()[_j + 1] != undefined ? x.domain()[_j + 1]: filteredData[0].values[filteredData[0].values.length - 1].x_end;
-        var range  = [x.range()[_l], x.range()[_j + 1] != undefined ? x.range()[_j + 1] : x.range()[_j] + _width];
-        brush.extent(chart.brushExtent = range);
-        g.select('.nv-x.nv-brush').call(brush);
-        if (onSelectRange != null){
-          if (_from > _to) {
-            onSelectRange(_to, _from);
-          } else {
-            onSelectRange(_from, _to);
-          }
-        }
-      }
-      function getElByMouse (coords, allSeries) {
-        var xy = d3v3.mouse(this);
-        var extent = coords || xy[0];
-        var _l, _j;
-        var _width = x.rangeBand();
-        var _leftEdges = x.range();
-        for(_l=0; extent >= _leftEdges[_l]; _l++) {}
-        _l = Math.max(_l - 1, 0);
-        var value = fGetNumericValue(x.domain()[_l]);
-        var values = [];
-        var i,j;
-        if (allSeries) {
-          for (j = 0; j < filteredData.length; j++) {
-            for (i = 0; i < filteredData[j].values.length; i++) {
-              if (fGetNumericValue(getX(filteredData[j].values[i])) == value) {
-                values.push(filteredData[j].values[i]);
-              }
-            }
-          }
-        } else if (!multibar.stacked()) {
-          var serieIndex = Math.floor(Math.min(extent - _leftEdges[_l], _width - 0.001) / (_width / filteredData.length)); // Math.min(extent - _leftEdges[_l], _width - 0.001) to handle the padding at the end. Would it make sense to remove the padding?
-          var i;
-          if (serieIndex < 0) return null;
-          for (i = 0; i < filteredData[serieIndex].values.length; i++) {
-            if (fGetNumericValue(getX(filteredData[serieIndex].values[i])) == value) {
-              values.push(filteredData[serieIndex].values[i]);
-              break;
-            }
-          }
-        } else {
-          // serieIndex depends on the y position of the bar
-          // y(getY(d) + (multibar.stacked() ? d.y0 : 0)
-          // get all series for the x value
-          var py = Math.round(y.invert(xy[1]));
-          var mindy = Number.MAX_VALUE;
-          var distances = {};
-          for (j = 0; j < filteredData.length; j++) {
-            for (i = 0; i < filteredData[j].values.length; i++) {
-              if (fGetNumericValue(getX(filteredData[j].values[i])) == value) {
-                if (py >= filteredData[j].values[i].y0 && py <= filteredData[j].values[i].y1) {
-                  values.push(filteredData[j].values[i]);
-                } else {
-                  var ym = filteredData[j].values[i].y0 + (filteredData[j].values[i].y1 - filteredData[j].values[i].y0) / 2;
-                  var dy = Math.abs(py - ym);
-                  if (!distances[dy]) {
-                    distances[dy] = [];
-                  }
-                  distances[dy].push(filteredData[j].values[i]);
-                  if (dy < mindy) {
-                    mindy = dy;
-                  }
-                }
-              }
-            }
-          }
-          if (!values.length) {
-            values = distances[mindy];
-          }
-        }
-        return values;
-      }
-      function fromSelection (selection) {
-        var _width = x.rangeBand() + multibar.groupSpacing() * x.rangeBand();
-        var _leftEdges = x.domain();
-        if (!_leftEdges.length) {
-          return null;
-        }
-        var _l, _j;
-        var isDescending = _leftEdges[0] < _leftEdges[1];
-        if (!isDescending) {
-          selection = [Math.max(selection[0], selection[1]), Math.min(selection[0], selection[1])]
-        }
-        if (isDescending) {
-          for(_l= 0; selection[0] >= _leftEdges[_l]; _l++) {}
-        } else {
-          for(_l= _leftEdges.length - 1; selection[0] > _leftEdges[_l]; _l--) {}
-        }
-
-        _l = x.range()[_l + (isDescending ? -1 : 0)] != undefined ? _l + (isDescending ? -1 : 0) : isDescending ? _leftEdges.length - 1 : 0;
-        var _fromRange = x.range()[_l] != undefined ? x.range()[_l] : 0;
-
-        if (isDescending) {
-          for(_j = 0; selection[1] > _leftEdges[_j]; _j++) {}
-        } else {
-          for(_j = _leftEdges.length - 1; selection[1] > _leftEdges[_j]; _j--) {}
-        }
-        var _toRange = x.range()[_j] != undefined ? x.range()[_j] : x.range()[_leftEdges.length - 1] + _width;
-        return {
-          range: [_fromRange, _fromRange === _toRange ? _fromRange + x.rangeBand() : _toRange],
-          isWholeDomain: selection[0] <= _leftEdges[0] && selection[1] >= _leftEdges[_leftEdges.length - 1]
-        };
-      }
-      function onMouseMove () {
-        var el = getElByMouse.call(this);
-        // If we're mousing over a rectangle that doesn't have class hover, set class and dispatch mouseover
-        var target = container.selectAll('g.nv-wrap.nv-multiBarWithLegend rect:not(.hover)').filter(function(rect) {
-          return el && el.some(function(d) {
-            return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
-          });
-        });
-
-        if (el && el.length && displayValuesInLegend) {
-          var legendG = legendSvg.select('.nvd3.nv-wrap.nv-legendWrap');
-          var elBySerie = el.reduce(function (elBySerie, el) {
-            elBySerie[el.seriesKey] = el;
-            return elBySerie;
-          }, {});
-          legendG.selectAll('g.nv-series text.nv-series-value')
-          .text(function (d, i) {
-            if (elBySerie[d.key]) {
-              var value = yAxis.tickFormat()(d.values[elBySerie[d.key].index].y)+'';
-              var addEllipsis = value.length > 5;
-              return value && (addEllipsis ? '...' : '') + value.substring(value.length - 5);
-            } else {
-              return '';
-            }
-          })
-          .append('title')
-          .text(function (d, i) {
-            if (elBySerie[d.key]) {
-              return yAxis.tickFormat()(d.values[elBySerie[d.key].index].y);
-            } else {
-              return '';
-            }
-          });
-        }
-
-        // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
-        var others = container.selectAll('g.nv-wrap.nv-multiBarWithLegend rect.hover').filter(function(rect) {
-          return !el || !el.some(function(d) {
-            return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
-          });
-        })
-        if (others.size()) {
-          others.classed('hover', false)
-          .each(function (d, i) {
-            multibar.dispatch.elementMouseout({
-              value: getY(d,i),
-              point: d,
-              series: filteredData[d.series],
-              pointIndex: i,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          });
-        }
-        if (target.size()) {
-          var e = d3v3.event; // Keep reference to event for setTimeout
-          setTimeout(function(){ // Delayed to conteract conflict with elementMouseout.
-            target.classed('hover', true);
-            var max, maxi;
-            target.each(function (d, i) {
-              if (isNaN(max) || max < getY(d)) {
-                max = getY(d);
-                maxi = i;
-              }
-            });
-            var width = x.rangeBand();
-            d3v3.select(target[0][maxi])
-            .each(function(d, i){
-              multibar.dispatch.elementMouseover({
-                value: getY(d),
-                point: d,
-                series: filteredData[d.series],
-                pos: [x(getX(d)) + width * 0.5, y(getY(d) + (multibar.stacked() ? d.y0 : 0))],
-                pointIndex: i,
-                seriesIndex: d.series,
-                list: el.map(function (d) {
-                  return {
-                    value: getY(d),
-                    point: d,
-                    series: filteredData[d.series],
-                    pos: [x(getX(d)) + width * 0.5, y(getY(d) + (multibar.stacked() ? d.y0 : 0))],
-                    pointIndex: -1,
-                    seriesIndex: d.series,
-                  };
-                }),
-                e: e
-              });
-            });
-          },0);
-        }
-      }
-      function onMouseOut () {
-        var others = container.selectAll('g.nv-wrap.nv-multiBarWithLegend rect.hover')
-        if (others.size()) {
-           others.classed('hover', false)
-          .each(function (d, i) {
-            multibar.dispatch.elementMouseout({
-              value: getY(d,i),
-              point: d,
-              series: filteredData[d.series],
-              pointIndex: d.index,
-              seriesIndex: d.series,
-              e: d3v3.event
-            });
-          });
-        }
-      }
-      function onClick () {
-        var el = getElByMouse.call(this);
-        var d = el[0];
-        multibar.dispatch.elementClick({
-          value: getY(d),
-          point: d,
-          series: filteredData[d.series],
-          pointIndex: d.index,
-          seriesIndex: d.series,
-          e: d3v3.event
-        });
-      }
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-
-  multibar.dispatch.on('elementMouseover.tooltip', function(e) {
-    e.pos = [e.pos[0] +  margin.left, e.pos[1] + margin.top];
-    dispatch.tooltipShow(e);
-  });
-
-  multibar.dispatch.on('elementMouseout.tooltip', function(e) {
-    dispatch.tooltipHide(e);
-  });
-  dispatch.on('tooltipHide', function() {
-    if (tooltips) nv.tooltip.cleanup();
-  });
-
-  //============================================================
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  // expose chart's sub-components
-  chart.dispatch = dispatch;
-  chart.multibar = multibar;
-  chart.legend = legend;
-  chart.xAxis = xAxis;
-  chart.yAxis = yAxis;
-  chart.xScale = multibar.xScale;
-  chart.LABELS = LABELS;
-
-  d3v3.rebind(chart, multibar, 'x', 'y', 'xDomain', 'yDomain', 'xRange', 'yRange', 'forceX', 'forceY', 'clipEdge',
-   'id', 'stacked', 'stackOffset', 'delay', 'barColor','groupSpacing');
-
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    legend.color(color);
-    return chart;
-  };
-
-  chart.showControls = function(_) {
-    if (!arguments.length) return showControls;
-    showControls = _;
-    return chart;
-  };
-
-  chart.showLegend = function(_) {
-    if (!arguments.length) return showLegend;
-    showLegend = _;
-    return chart;
-  };
-
-  chart.showXAxis = function(_) {
-    if (!arguments.length) return showXAxis;
-    showXAxis = _;
-    return chart;
-  };
-
-  chart.showYAxis = function(_) {
-    if (!arguments.length) return showYAxis;
-    showYAxis = _;
-    return chart;
-  };
-
-  chart.rightAlignYAxis = function(_) {
-    if(!arguments.length) return rightAlignYAxis;
-    rightAlignYAxis = _;
-    yAxis.orient( (_) ? 'right' : 'left');
-    return chart;
-  };
-
-  chart.reduceXTicks= function(_) {
-    if (!arguments.length) return reduceXTicks;
-    reduceXTicks = _;
-    return chart;
-  };
-
-  chart.rotateLabels = function(_) {
-    if (!arguments.length) return rotateLabels;
-    rotateLabels = _;
-    return chart;
-  }
-
-  chart.staggerLabels = function(_) {
-    if (!arguments.length) return staggerLabels;
-    staggerLabels = _;
-    return chart;
-  };
-
-  chart.tooltip = function(_) {
-    if (!arguments.length) return tooltip;
-    tooltip = _;
-    return chart;
-  };
-
-  chart.tooltips = function(_) {
-    if (!arguments.length) return tooltips;
-    tooltips = _;
-    return chart;
-  };
-
-  chart.tooltipContent = function(_) {
-    if (!arguments.length) return tooltipContent;
-    tooltipContent = _;
-    return chart;
-  };
-
-  chart.state = function(_) {
-    if (!arguments.length) return state;
-    state = _;
-    return chart;
-  };
-
-  chart.defaultState = function(_) {
-    if (!arguments.length) return defaultState;
-    defaultState = _;
-    return chart;
-  };
-
-  chart.noData = function(_) {
-    if (!arguments.length) return noData;
-    noData = _;
-    return chart;
-  };
-
-  chart.transitionDuration = function(_) {
-    if (!arguments.length) return transitionDuration;
-    transitionDuration = _;
-    return chart;
-  };
-
-  chart.enableSelection = function() {
-    selectionEnabled = true;
-    return chart;
-  };
-
-  chart.disableSelection = function() {
-    selectionEnabled = false;
-    return chart;
-  };
-
-  chart.isSelectionEnabled = function() {
-    return selectionEnabled;
-  };
-
-  chart.hideSelection = function() {
-    selectionHidden = true;
-    return chart;
-  };
-
-  chart.showSelection = function() {
-    selectionHidden = false;
-    return chart;
-  };
-
-  chart.showStacked = function() {
-    stackedHidden = false;
-  };
-
-  chart.hideStacked = function() {
-    stackedHidden = true;
-  };
-
-  chart.onSelectRange = function(_) {
-    if (!arguments.length) return onSelectRange;
-    onSelectRange = _;
-    return chart;
-  };
-
-  chart.onStateChange = function(_) {
-    if (!arguments.length) return onStateChange;
-    onStateChange = _;
-    return chart;
-  };
-
-  chart.onLegendChange = function(_) {
-    if (!arguments.length) return onLegendChange;
-    onLegendChange = _;
-    return chart;
-  };
-
-  chart.onChartUpdate = function(_) {
-    if (!arguments.length) return onChartUpdate;
-    onChartUpdate = _;
-    return chart;
-  };
-
-  chart.minTickWidth = function() {
-    if (!arguments.length) return minTickWidth;
-    minTickWidth = _;
-    return chart;
-  };
-
-  chart.selectBars = function(args) {
-    if (!arguments.length) return selectBars;
-    if (args && args.rangeValues) {
-      chart.brushDomain = [args.rangeValues[0].from, args.rangeValues[0].to];
-    } else {
-      chart.brushDomain = null;
-    }
-    selectedBars = args;
-    if (selectBars) {
-      selectBars(args);
-    }
-    return chart;
-  };
-
-  chart.displayValuesInLegend = function(_) {
-    if (!arguments.length) return displayValuesInLegend;
-    displayValuesInLegend = _;
-    return chart;
-  };
-
-  chart.brush = function(_) {
-    if (!arguments.length) return brush;
-    brush = _;
-    return chart;
-  };
-
-
-  //============================================================
-
-
-  return chart;
-}
-
-

+ 0 - 689
desktop/core/src/desktop/static/desktop/js/nv.d3.scatter.js

@@ -1,689 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-nv.models.scatter = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var margin       = {top: 0, right: 0, bottom: 0, left: 0}
-    , width        = 960
-    , height       = 500
-    , color        = nv.utils.defaultColor() // chooses color
-    , id           = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't select one
-    , x            = d3v3.scale.linear()
-    , y            = d3v3.scale.linear()
-    , z            = d3v3.scale.linear() //linear because d3v3.svg.shape.size is treated as area
-    , getX         = function(d) { return d.x } // accessor to get the x value
-    , getY         = function(d) { return d.y } // accessor to get the y value
-    , getSize      = function(d) { return d.size || 1} // accessor to get the point size
-    , getShape     = function(d) { return d.shape || 'circle' } // accessor to get point shape
-    , onlyCircles  = true // Set to false to use shapes
-    , forceX       = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
-    , forceY       = [] // List of numbers to Force into the Y scale
-    , forceSize    = [] // List of numbers to Force into the Size scale
-    , interactive  = true // If true, plots a voronoi overlay for advanced point intersection
-    , pointKey     = null
-    , pointActive  = function(d) { return !d.notActive } // any points that return false will be filtered out
-    , padData      = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
-    , padDataOuter = .1 //outerPadding to imitate ordinal scale outer padding
-    , clipEdge     = false // if true, masks points within x and y scale
-    , clipVoronoi  = true // if true, masks each point with a circle... can turn off to slightly increase performance
-    , clipRadius   = function() { return 25 } // function to get the radius for voronoi point clips
-    , xDomain      = null // Override x domain (skips the calculation from data)
-    , yDomain      = null // Override y domain
-    , xRange       = null // Override x range
-    , yRange       = null // Override y range
-    , sizeDomain   = null // Override point size domain
-    , sizeRange    = null
-    , singlePoint  = false
-    , dispatch     = d3v3.dispatch('elementClick', 'elementMouseover', 'elementMouseout')
-    , useVoronoi   = true
-    ;
-
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var x0, y0, z0 // used to store previous scales
-    , timeoutID
-    , needsUpdate = false // Flag for when the points are visually updating, but the interactive layer is behind, to disable tooltips
-    ;
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var availableWidth = width - margin.left - margin.right,
-          availableHeight = height - margin.top - margin.bottom,
-          container = d3v3.select(this);
-
-      //add series index to each data point for reference
-      data.forEach(function(series, i) {
-        series.values.forEach(function(point) {
-          point.series = i;
-        });
-      });
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      // remap and flatten the data for use in calculating the scales' domains
-      var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
-            d3v3.merge(
-              data.map(function(d) {
-                return d.values.map(function(d,i) {
-                  return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
-                })
-              })
-            );
-
-      x   .domain(xDomain || d3v3.extent(seriesData.map(function(d) { return d.x; }).concat(forceX)))
-
-      if (padData && data[0])
-        x.range(xRange || [(availableWidth * padDataOuter +  availableWidth) / (2 *data[0].values.length), availableWidth - availableWidth * (1 + padDataOuter) / (2 * data[0].values.length)  ]);
-        //x.range([availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
-      else
-        x.range(xRange || [0, availableWidth]);
-
-      y   .domain(yDomain || d3v3.extent(seriesData.map(function(d) { return d.y }).concat(forceY)))
-          .range(yRange || [availableHeight, 0]);
-
-      z   .domain(sizeDomain || d3v3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize)))
-          .range(sizeRange || [16, 256]);
-
-      // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
-      if (x.domain()[0] === x.domain()[1] || y.domain()[0] === y.domain()[1]) singlePoint = true;
-      if (x.domain()[0] === x.domain()[1])
-        x.domain()[0] ?
-            x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
-          : x.domain([-1,1]);
-
-      if (y.domain()[0] === y.domain()[1])
-        y.domain()[0] ?
-            y.domain([y.domain()[0] - y.domain()[0] * 0.01, y.domain()[1] + y.domain()[1] * 0.01])
-          : y.domain([-1,1]);
-
-      if ( isNaN(x.domain()[0])) {
-          x.domain([-1,1]);
-      }
-
-      if ( isNaN(y.domain()[0])) {
-          y.domain([-1,1]);
-      }
-
-
-      x0 = x0 || x;
-      y0 = y0 || y;
-      z0 = z0 || z;
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-scatter').data([data]);
-      var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatter nv-chart-' + id + (singlePoint ? ' nv-single-point' : ''));
-      var defsEnter = wrapEnter.append('defs');
-      var gEnter = wrapEnter.append('g');
-      var g = wrap.select('g');
-
-      gEnter.append('g').attr('class', 'nv-groups');
-      gEnter.append('g').attr('class', 'nv-point-paths');
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      //------------------------------------------------------------
-
-
-      defsEnter.append('clipPath')
-          .attr('id', 'nv-edge-clip-' + id)
-        .append('rect');
-
-      wrap.select('#nv-edge-clip-' + id + ' rect')
-          .attr('width', availableWidth)
-          .attr('height', (availableHeight > 0) ? availableHeight : 0);
-
-      g   .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
-
-
-      function updateInteractiveLayer() {
-
-        if (!interactive) return false;
-
-        var eventElements;
-
-        var vertices = d3v3.merge(data.map(function(group, groupIndex) {
-            return group.values
-              .map(function(point, pointIndex) {
-                // *Adding noise to make duplicates very unlikely
-                // *Injecting series and point index for reference
-                /* *Adding a 'jitter' to the points, because there's an issue in d3v3.geom.voronoi.
-                */
-                var pX = getX(point,pointIndex);
-                var pY = getY(point,pointIndex);
-
-                return [x(pX)+ Math.random() * 1e-7,
-                        y(pY)+ Math.random() * 1e-7,
-                        groupIndex,
-                        pointIndex, point]; //temp hack to add noise untill I think of a better way so there are no duplicates
-              })
-              .filter(function(pointArray, pointIndex) {
-                return pointActive(pointArray[4], pointIndex); // Issue #237.. move filter to after map, so pointIndex is correct!
-              })
-          })
-        );
-
-
-
-        //inject series and point index for reference into voronoi
-        if (useVoronoi === true) {
-
-          if (clipVoronoi) {
-            var pointClipsEnter = wrap.select('defs').selectAll('.nv-point-clips')
-                .data([id])
-              .enter();
-
-            pointClipsEnter.append('clipPath')
-                  .attr('class', 'nv-point-clips')
-                  .attr('id', 'nv-points-clip-' + id);
-
-            var pointClips = wrap.select('#nv-points-clip-' + id).selectAll('circle')
-                .data(vertices);
-            pointClips.enter().append('circle')
-                .attr('r', clipRadius);
-            pointClips.exit().remove();
-            pointClips
-                .attr('cx', function(d) { return isNaN(d[0]) ? 0 : d[0] })
-                .attr('cy', function(d) { return isNaN(d[1]) ? 0 : d[1] });
-
-            wrap.select('.nv-point-paths')
-                .attr('clip-path', 'url(#nv-points-clip-' + id + ')');
-          }
-
-
-          if(vertices.length) {
-            // Issue #283 - Adding 2 dummy points to the voronoi b/c voronoi requires min 3 points to work
-            vertices.push([x.range()[0] - 20, y.range()[0] - 20, null, null]);
-            vertices.push([x.range()[1] + 20, y.range()[1] + 20, null, null]);
-            vertices.push([x.range()[0] - 20, y.range()[0] + 20, null, null]);
-            vertices.push([x.range()[1] + 20, y.range()[1] - 20, null, null]);
-          }
-
-          var bounds = d3v3.geom.polygon([
-              [-10,-10],
-              [-10,height + 10],
-              [width + 10,height + 10],
-              [width + 10,-10]
-          ]);
-
-          var voronoi = d3v3.geom.voronoi(vertices).map(function(d, i) {
-              return {
-                'data': bounds.clip(d),
-                'series': vertices[i][2],
-                'point': vertices[i][3]
-              }
-            });
-
-
-          var pointPaths = wrap.select('.nv-point-paths').selectAll('path')
-              .data(voronoi);
-          pointPaths.enter().append('path')
-              .attr('class', function(d,i) { return 'nv-path-'+i; });
-          pointPaths.exit().remove();
-          pointPaths
-              .attr('d', function(d) {
-                if (d.data.length === 0)
-                    return 'M 0 0'
-                else
-                    return 'M' + d.data.join('L') + 'Z';
-              });
-
-          var mouseEventCallback = function(d,mDispatch) {
-                if (needsUpdate) return 0;
-                var series = data[d.series];
-                if (typeof series === 'undefined') return;
-
-                var point  = series.values[d.point];
-
-                mDispatch({
-                  point: point,
-                  series: series,
-                  pos: [x(getX(point, d.point)) + margin.left, y(getY(point, d.point)) + margin.top],
-                  seriesIndex: d.series,
-                  pointIndex: d.point
-                });
-          };
-
-          pointPaths
-              .on('click', function(d) {
-                mouseEventCallback(d, dispatch.elementClick);
-              })
-              .on('mouseover', function(d) {
-                mouseEventCallback(d, dispatch.elementMouseover);
-              })
-              .on('mouseout', function(d, i) {
-                mouseEventCallback(d, dispatch.elementMouseout);
-              });
-
-
-        } else {
-          /*
-          // bring data in form needed for click handlers
-          var dataWithPoints = vertices.map(function(d, i) {
-              return {
-                'data': d,
-                'series': vertices[i][2],
-                'point': vertices[i][3]
-              }
-            });
-           */
-
-          // add event handlers to points instead voronoi paths
-          wrap.select('.nv-groups').selectAll('.nv-group')
-            .selectAll('.nv-point')
-              //.data(dataWithPoints)
-              //.style('pointer-events', 'auto') // recativate events, disabled by css
-              .on('click', function(d,i) {
-                //nv.log('test', d, i);
-                if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
-                var series = data[d.series],
-                    point  = series.values[i];
-
-                dispatch.elementClick({
-                  point: point,
-                  series: series,
-                  pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
-                  seriesIndex: d.series,
-                  pointIndex: i
-                });
-              })
-              .on('mouseover', function(d,i) {
-                if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
-                var series = data[d.series],
-                    point  = series.values[i];
-
-                dispatch.elementMouseover({
-                  point: point,
-                  series: series,
-                  pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
-                  seriesIndex: d.series,
-                  pointIndex: i
-                });
-              })
-              .on('mouseout', function(d,i) {
-                if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
-                var series = data[d.series],
-                    point  = series.values[i];
-
-                dispatch.elementMouseout({
-                  point: point,
-                  series: series,
-                  seriesIndex: d.series,
-                  pointIndex: i
-                });
-              });
-          }
-
-          needsUpdate = false;
-      }
-
-      needsUpdate = true;
-
-      var groups = wrap.select('.nv-groups').selectAll('.nv-group')
-          .data(function(d) { return d }, function(d) { return d.key });
-      groups.enter().append('g')
-          .style('stroke-opacity', 1e-6)
-          .style('fill-opacity', 1e-6);
-      groups.exit()
-          .remove();
-      groups
-          .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
-          .classed('hover', function(d) { return d.hover });
-      groups
-          .transition()
-          .style('fill', function(d,i) { return color(d, i) })
-          .style('stroke', function(d,i) { return color(d, i) })
-          .style('stroke-opacity', 1)
-          .style('fill-opacity', .5);
-
-
-      if (onlyCircles) {
-
-        var points = groups.selectAll('circle.nv-point')
-            .data(function(d) { return d.values }, pointKey);
-        points.enter().append('circle')
-            .style('fill', function (d,i) { return d.color })
-            .style('stroke', function (d,i) { return d.color })
-            .attr('cx', function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
-            .attr('cy', function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
-            .attr('r', function(d,i) { return Math.sqrt(z(getSize(d,i))/Math.PI) });
-        points.exit().remove();
-        groups.exit().selectAll('path.nv-point').transition()
-            .attr('cx', function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
-            .attr('cy', function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
-            .remove();
-        points.each(function(d,i) {
-          d3v3.select(this)
-            .classed('nv-point', true)
-            .classed('nv-point-' + i, true)
-            .classed('hover',false)
-            ;
-        });
-        points.transition()
-            .attr('cx', function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
-            .attr('cy', function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
-            .attr('r', function(d,i) { return Math.sqrt(z(getSize(d,i))/Math.PI) });
-
-      } else {
-
-        var points = groups.selectAll('path.nv-point')
-            .data(function(d) { return d.values });
-        points.enter().append('path')
-            .style('fill', function (d,i) { return d.color })
-            .style('stroke', function (d,i) { return d.color })
-            .attr('transform', function(d,i) {
-              return 'translate(' + x0(getX(d,i)) + ',' + y0(getY(d,i)) + ')'
-            })
-            .attr('d',
-              d3v3.svg.symbol()
-                .type(getShape)
-                .size(function(d,i) { return z(getSize(d,i)) })
-            );
-        points.exit().remove();
-        groups.exit().selectAll('path.nv-point')
-            .transition()
-            .attr('transform', function(d,i) {
-              return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
-            })
-            .remove();
-        points.each(function(d,i) {
-          d3v3.select(this)
-            .classed('nv-point', true)
-            .classed('nv-point-' + i, true)
-            .classed('hover',false)
-            ;
-        });
-        points.transition()
-            .attr('transform', function(d,i) {
-              //nv.log(d,i,getX(d,i), x(getX(d,i)));
-              return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
-            })
-            .attr('d',
-              d3v3.svg.symbol()
-                .type(getShape)
-                .size(function(d,i) { return z(getSize(d,i)) })
-            );
-      }
-
-
-      // Delay updating the invisible interactive layer for smoother animation
-      clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer
-      timeoutID = setTimeout(updateInteractiveLayer, 300);
-      //updateInteractiveLayer();
-
-      //store old scales for use in transitions on update
-      x0 = x.copy();
-      y0 = y.copy();
-      z0 = z.copy();
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-  chart.clearHighlights = function() {
-      //Remove the 'hover' class from all highlighted points.
-      d3v3.selectAll(".nv-chart-" + id + " .nv-point.hover").classed("hover",false);
-  };
-
-  chart.highlightPoint = function(seriesIndex,pointIndex,isHoverOver) {
-      d3v3.select(".nv-chart-" + id + " .nv-series-" + seriesIndex + " .nv-point-" + pointIndex)
-          .classed("hover",isHoverOver);
-  };
-
-
-  dispatch.on('elementMouseover.point', function(d) {
-     if (interactive) chart.highlightPoint(d.seriesIndex,d.pointIndex,true);
-  });
-
-  dispatch.on('elementMouseout.point', function(d) {
-     if (interactive) chart.highlightPoint(d.seriesIndex,d.pointIndex,false);
-  });
-
-  //============================================================
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  chart.dispatch = dispatch;
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart.x = function(_) {
-    if (!arguments.length) return getX;
-    getX = d3v3.functor(_);
-    return chart;
-  };
-
-  chart.y = function(_) {
-    if (!arguments.length) return getY;
-    getY = d3v3.functor(_);
-    return chart;
-  };
-
-  chart.size = function(_) {
-    if (!arguments.length) return getSize;
-    getSize = d3v3.functor(_);
-    return chart;
-  };
-
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.xScale = function(_) {
-    if (!arguments.length) return x;
-    x = _;
-    return chart;
-  };
-
-  chart.yScale = function(_) {
-    if (!arguments.length) return y;
-    y = _;
-    return chart;
-  };
-
-  chart.zScale = function(_) {
-    if (!arguments.length) return z;
-    z = _;
-    return chart;
-  };
-
-  chart.xDomain = function(_) {
-    if (!arguments.length) return xDomain;
-    xDomain = _;
-    return chart;
-  };
-
-  chart.yDomain = function(_) {
-    if (!arguments.length) return yDomain;
-    yDomain = _;
-    return chart;
-  };
-
-  chart.sizeDomain = function(_) {
-    if (!arguments.length) return sizeDomain;
-    sizeDomain = _;
-    return chart;
-  };
-
-  chart.xRange = function(_) {
-    if (!arguments.length) return xRange;
-    xRange = _;
-    return chart;
-  };
-
-  chart.yRange = function(_) {
-    if (!arguments.length) return yRange;
-    yRange = _;
-    return chart;
-  };
-
-  chart.sizeRange = function(_) {
-    if (!arguments.length) return sizeRange;
-    sizeRange = _;
-    return chart;
-  };
-
-  chart.forceX = function(_) {
-    if (!arguments.length) return forceX;
-    forceX = _;
-    return chart;
-  };
-
-  chart.forceY = function(_) {
-    if (!arguments.length) return forceY;
-    forceY = _;
-    return chart;
-  };
-
-  chart.forceSize = function(_) {
-    if (!arguments.length) return forceSize;
-    forceSize = _;
-    return chart;
-  };
-
-  chart.interactive = function(_) {
-    if (!arguments.length) return interactive;
-    interactive = _;
-    return chart;
-  };
-
-  chart.pointKey = function(_) {
-    if (!arguments.length) return pointKey;
-    pointKey = _;
-    return chart;
-  };
-
-  chart.pointActive = function(_) {
-    if (!arguments.length) return pointActive;
-    pointActive = _;
-    return chart;
-  };
-
-  chart.padData = function(_) {
-    if (!arguments.length) return padData;
-    padData = _;
-    return chart;
-  };
-
-  chart.padDataOuter = function(_) {
-    if (!arguments.length) return padDataOuter;
-    padDataOuter = _;
-    return chart;
-  };
-
-  chart.clipEdge = function(_) {
-    if (!arguments.length) return clipEdge;
-    clipEdge = _;
-    return chart;
-  };
-
-  chart.clipVoronoi= function(_) {
-    if (!arguments.length) return clipVoronoi;
-    clipVoronoi = _;
-    return chart;
-  };
-
-  chart.useVoronoi= function(_) {
-    if (!arguments.length) return useVoronoi;
-    useVoronoi = _;
-    if (useVoronoi === false) {
-        clipVoronoi = false;
-    }
-    return chart;
-  };
-
-  chart.clipRadius = function(_) {
-    if (!arguments.length) return clipRadius;
-    clipRadius = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    return chart;
-  };
-
-  chart.shape = function(_) {
-    if (!arguments.length) return getShape;
-    getShape = _;
-    return chart;
-  };
-
-  chart.onlyCircles = function(_) {
-    if (!arguments.length) return onlyCircles;
-    onlyCircles = _;
-    return chart;
-  };
-
-  chart.id = function(_) {
-    if (!arguments.length) return id;
-    id = _;
-    return chart;
-  };
-
-  chart.singlePoint = function(_) {
-    if (!arguments.length) return singlePoint;
-    singlePoint = _;
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 644
desktop/core/src/desktop/static/desktop/js/nv.d3.scatterChart.js

@@ -1,644 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-nv.models.scatterChart = function() {
-  "use strict";
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var scatter      = nv.models.scatter()
-    , xAxis        = nv.models.axis()
-    , yAxis        = nv.models.axis()
-    , legend       = nv.models.legend()
-    , controls     = nv.models.legend()
-    , distX        = nv.models.distribution()
-    , distY        = nv.models.distribution()
-    ;
-
-  var margin       = {top: 30, right: 20, bottom: 50, left: 75}
-    , width        = null
-    , height       = null
-    , color        = nv.utils.defaultColor()
-    , x            = d3v3.fisheye ? d3v3.fisheye.scale(d3v3.scale.linear).distortion(0) : scatter.xScale()
-    , y            = d3v3.fisheye ? d3v3.fisheye.scale(d3v3.scale.linear).distortion(0) : scatter.yScale()
-    , xPadding     = 0
-    , yPadding     = 0
-    , showDistX    = false
-    , showDistY    = false
-    , showLegend   = true
-    , showXAxis    = true
-    , showYAxis    = true
-    , rightAlignYAxis = false
-    , showControls = !!d3v3.fisheye
-    , fisheye      = 0
-    , pauseFisheye = false
-    , tooltips     = true
-    , tooltipX     = function(key, x, y) { return '<strong>' + x + '</strong>' }
-    , tooltipY     = function(key, x, y) { return '<strong>' + y + '</strong>' }
-    , tooltip      = null
-    , state = {}
-    , defaultState = null
-    , dispatch     = d3v3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState')
-    , noData       = "No Data Available."
-    , transitionDuration = 250
-    ;
-
-  scatter
-    .xScale(x)
-    .yScale(y)
-    ;
-  xAxis
-    .orient('bottom')
-    .tickPadding(10)
-    ;
-  yAxis
-    .orient((rightAlignYAxis) ? 'right' : 'left')
-    .tickPadding(10)
-    ;
-  distX
-    .axis('x')
-    ;
-  distY
-    .axis('y')
-    ;
-
-  controls.updateState(false);
-
-  //============================================================
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var x0, y0;
-
-  var showTooltip = function(e, offsetElement) {
-    //TODO: make tooltip style an option between single or dual on axes (maybe on all charts with axes?)
-
-    var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
-        top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        leftX = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
-        topX = y.range()[0] + margin.top + ( offsetElement.offsetTop || 0),
-        leftY = x.range()[0] + margin.left + ( offsetElement.offsetLeft || 0 ),
-        topY = e.pos[1] + ( offsetElement.offsetTop || 0),
-        xVal = xAxis.tickFormat()(scatter.x()(e.point, e.pointIndex)),
-        yVal = yAxis.tickFormat()(scatter.y()(e.point, e.pointIndex));
-
-      if( tooltipX != null )
-          nv.tooltip.show([leftX, topX], tooltipX(e.series.key, xVal, yVal, e, chart), 'n', 1, offsetElement, 'x-nvtooltip');
-      if( tooltipY != null )
-          nv.tooltip.show([leftY, topY], tooltipY(e.series.key, xVal, yVal, e, chart), 'e', 1, offsetElement, 'y-nvtooltip');
-      if( tooltip != null )
-          nv.tooltip.show([left, top], tooltip(e.series.key, xVal, yVal, e, chart), e.value < 0 ? 'n' : 's', null, offsetElement);
-  };
-
-  var controlsData = [
-    { key: 'Magnify', disabled: true }
-  ];
-
-  //============================================================
-
-
-  function chart(selection) {
-    selection.each(function(data) {
-      var container = d3v3.select(this),
-          that = this;
-
-      var availableWidth = (width  || parseInt(container.style('width')) || 960)
-                             - margin.left - margin.right,
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-
-      chart.update = function() { container.transition().duration(transitionDuration).call(chart); };
-      chart.container = this;
-
-      //set state.disabled
-      state.disabled = data.map(function(d) { return !!d.disabled });
-
-      if (!defaultState) {
-        var key;
-        defaultState = {};
-        for (key in state) {
-          if (state[key] instanceof Array)
-            defaultState[key] = state[key].slice(0);
-          else
-            defaultState[key] = state[key];
-        }
-      }
-
-      //------------------------------------------------------------
-      // Display noData message if there's nothing to show.
-
-      if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
-        var noDataText = container.selectAll('.nv-noData').data([noData]);
-
-        noDataText.enter().append('text')
-          .attr('class', 'nvd3 nv-noData')
-          .attr('dy', '-.7em')
-          .style('text-anchor', 'middle');
-
-        noDataText
-          .attr('x', margin.left + availableWidth / 2)
-          .attr('y', margin.top + availableHeight / 2)
-          .text(function(d) { return d });
-
-        return chart;
-      } else {
-        container.selectAll('.nv-noData').remove();
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Scales
-
-      x0 = x0 || x;
-      y0 = y0 || y;
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup containers and skeleton of chart
-
-      var wrap = container.selectAll('g.nv-wrap.nv-scatterChart').data([data]);
-      var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatterChart nv-chart-' + scatter.id());
-      var gEnter = wrapEnter.append('g');
-      var g = wrap.select('g');
-
-      // background for pointer events
-      gEnter.append('rect').attr('class', 'nvd3 nv-background');
-
-      gEnter.append('g').attr('class', 'nv-x nv-axis');
-      gEnter.append('g').attr('class', 'nv-y nv-axis');
-      gEnter.append('g').attr('class', 'nv-scatterWrap');
-      gEnter.append('g').attr('class', 'nv-distWrap');
-      gEnter.append('g').attr('class', 'nv-legendWrap');
-      gEnter.append('g').attr('class', 'nv-controlsWrap');
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Legend
-
-      if (showLegend) {
-        var legendWidth = (showControls) ? availableWidth / 2 : availableWidth;
-        legend.width(legendWidth);
-
-        wrap.select('.nv-legendWrap')
-            .datum(data)
-            .call(legend);
-
-        if ( margin.top != legend.height()) {
-          margin.top = legend.height();
-          availableHeight = (height || parseInt(container.style('height')) || 400)
-                             - margin.top - margin.bottom;
-        }
-
-        wrap.select('.nv-legendWrap')
-            .attr('transform', 'translate(' + (availableWidth - legendWidth) + ',' + (-margin.top) +')');
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Controls
-
-      if (showControls) {
-        controls.width(180).color(['#444']);
-        g.select('.nv-controlsWrap')
-            .datum(controlsData)
-            .attr('transform', 'translate(0,' + (-margin.top) +')')
-            .call(controls);
-      }
-
-      //------------------------------------------------------------
-
-
-      wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-
-      if (rightAlignYAxis) {
-          g.select(".nv-y.nv-axis")
-              .attr("transform", "translate(" + availableWidth + ",0)");
-      }
-
-      //------------------------------------------------------------
-      // Main Chart Component(s)
-
-      scatter
-          .width(availableWidth)
-          .height(availableHeight)
-          .color(data.map(function(d,i) {
-            return d.color || color(d, i);
-          }).filter(function(d,i) { return !data[i].disabled }));
-
-      if (xPadding !== 0)
-        scatter.xDomain(null);
-
-      if (yPadding !== 0)
-        scatter.yDomain(null);
-
-      wrap.select('.nv-scatterWrap')
-          .datum(data.filter(function(d) { return !d.disabled }))
-          .call(scatter);
-
-      //Adjust for x and y padding
-      if (xPadding !== 0) {
-        var xRange = x.domain()[1] - x.domain()[0];
-        scatter.xDomain([x.domain()[0] - (xPadding * xRange), x.domain()[1] + (xPadding * xRange)]);
-      }
-
-      if (yPadding !== 0) {
-        var yRange = y.domain()[1] - y.domain()[0];
-        scatter.yDomain([y.domain()[0] - (yPadding * yRange), y.domain()[1] + (yPadding * yRange)]);
-      }
-
-      //Only need to update the scatter again if x/yPadding changed the domain.
-      if (yPadding !== 0 || xPadding !== 0) {
-        wrap.select('.nv-scatterWrap')
-            .datum(data.filter(function(d) { return !d.disabled }))
-            .call(scatter);
-      }
-
-      //------------------------------------------------------------
-
-
-      //------------------------------------------------------------
-      // Setup Axes
-      if (showXAxis) {
-        xAxis
-            .scale(x)
-            .ticks( xAxis.ticks() && xAxis.ticks().length ? xAxis.ticks() : availableWidth / 100 )
-            .tickSize( -availableHeight , 0);
-
-        g.select('.nv-x.nv-axis')
-            .attr('transform', 'translate(0,' + y.range()[0] + ')')
-            .call(xAxis);
-
-      }
-
-      if (showYAxis) {
-        yAxis
-            .scale(y)
-            .ticks( yAxis.ticks() && yAxis.ticks().length ? yAxis.ticks() : availableHeight / 36 )
-            .tickSize( -availableWidth, 0);
-
-        g.select('.nv-y.nv-axis')
-            .call(yAxis);
-      }
-
-
-      if (showDistX) {
-        distX
-            .getData(scatter.x())
-            .scale(x)
-            .width(availableWidth)
-            .color(data.map(function(d,i) {
-              return d.color || color(d, i);
-            }).filter(function(d,i) { return !data[i].disabled }));
-        gEnter.select('.nv-distWrap').append('g')
-            .attr('class', 'nv-distributionX');
-        g.select('.nv-distributionX')
-            .attr('transform', 'translate(0,' + y.range()[0] + ')')
-            .datum(data.filter(function(d) { return !d.disabled }))
-            .call(distX);
-      }
-
-      if (showDistY) {
-        distY
-            .getData(scatter.y())
-            .scale(y)
-            .width(availableHeight)
-            .color(data.map(function(d,i) {
-              return d.color || color(d, i);
-            }).filter(function(d,i) { return !data[i].disabled }));
-        gEnter.select('.nv-distWrap').append('g')
-            .attr('class', 'nv-distributionY');
-        g.select('.nv-distributionY')
-            .attr('transform', 
-              'translate(' + (rightAlignYAxis ? availableWidth : -distY.size() ) + ',0)')
-            .datum(data.filter(function(d) { return !d.disabled }))
-            .call(distY);
-      }
-
-      //------------------------------------------------------------
-
-
-
-
-      if (d3v3.fisheye) {
-        g.select('.nv-background')
-            .attr('width', availableWidth)
-            .attr('height', availableHeight);
-
-        g.select('.nv-background').on('mousemove', updateFisheye);
-        g.select('.nv-background').on('click', function() { pauseFisheye = !pauseFisheye;});
-        scatter.dispatch.on('elementClick.freezeFisheye', function() {
-          pauseFisheye = !pauseFisheye;
-        });
-      }
-
-
-      function updateFisheye() {
-        if (pauseFisheye) {
-          g.select('.nv-point-paths').style('pointer-events', 'all');
-          return false;
-        }
-
-        g.select('.nv-point-paths').style('pointer-events', 'none' );
-
-        var mouse = d3v3.mouse(this);
-        x.distortion(fisheye).focus(mouse[0]);
-        y.distortion(fisheye).focus(mouse[1]);
-
-        g.select('.nv-scatterWrap')
-            .call(scatter);
-
-        if (showXAxis)
-          g.select('.nv-x.nv-axis').call(xAxis);
-        
-        if (showYAxis)
-          g.select('.nv-y.nv-axis').call(yAxis);
-        
-        g.select('.nv-distributionX')
-            .datum(data.filter(function(d) { return !d.disabled }))
-            .call(distX);
-        g.select('.nv-distributionY')
-            .datum(data.filter(function(d) { return !d.disabled }))
-            .call(distY);
-      }
-
-
-
-      //============================================================
-      // Event Handling/Dispatching (in chart's scope)
-      //------------------------------------------------------------
-
-      controls.dispatch.on('legendClick', function(d,i) {
-        d.disabled = !d.disabled;
-
-        fisheye = d.disabled ? 0 : 2.5;
-        g.select('.nv-background') .style('pointer-events', d.disabled ? 'none' : 'all');
-        g.select('.nv-point-paths').style('pointer-events', d.disabled ? 'all' : 'none' );
-
-        if (d.disabled) {
-          x.distortion(fisheye).focus(0);
-          y.distortion(fisheye).focus(0);
-
-          g.select('.nv-scatterWrap').call(scatter);
-          g.select('.nv-x.nv-axis').call(xAxis);
-          g.select('.nv-y.nv-axis').call(yAxis);
-        } else {
-          pauseFisheye = false;
-        }
-
-        chart.update();
-      });
-
-      legend.dispatch.on('stateChange', function(newState) {
-        state.disabled = newState.disabled;
-        dispatch.stateChange(state);
-        chart.update();
-      });
-
-      scatter.dispatch.on('elementMouseover.tooltip', function(e) {
-        d3v3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-distx-' + e.pointIndex)
-            .attr('y1', function(d,i) { return e.pos[1] - availableHeight;});
-        d3v3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-disty-' + e.pointIndex)
-            .attr('x2', e.pos[0] + distX.size());
-
-        e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
-        dispatch.tooltipShow(e);
-      });
-
-      dispatch.on('tooltipShow', function(e) {
-        if (tooltips) showTooltip(e, that.parentNode);
-      });
-
-      // Update chart from a state object passed to event handler
-      dispatch.on('changeState', function(e) {
-
-        if (typeof e.disabled !== 'undefined') {
-          data.forEach(function(series,i) {
-            series.disabled = e.disabled[i];
-          });
-
-          state.disabled = e.disabled;
-        }
-
-        chart.update();
-      });
-
-      //============================================================
-
-
-      //store old scales for use in transitions on update
-      x0 = x.copy();
-      y0 = y.copy();
-
-
-    });
-
-    return chart;
-  }
-
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-
-  scatter.dispatch.on('elementMouseout.tooltip', function(e) {
-    dispatch.tooltipHide(e);
-
-    d3v3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-distx-' + e.pointIndex)
-        .attr('y1', 0);
-    d3v3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-disty-' + e.pointIndex)
-        .attr('x2', distY.size());
-  });
-  dispatch.on('tooltipHide', function() {
-    if (tooltips) nv.tooltip.cleanup();
-  });
-
-  //============================================================
-
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  // expose chart's sub-components
-  chart.dispatch = dispatch;
-  chart.scatter = scatter;
-  chart.legend = legend;
-  chart.controls = controls;
-  chart.xAxis = xAxis;
-  chart.yAxis = yAxis;
-  chart.distX = distX;
-  chart.distY = distY;
-
-  d3v3.rebind(chart, scatter, 'id', 'interactive', 'pointActive', 'x', 'y', 'shape', 'size', 'xScale', 'yScale', 'zScale', 'xDomain', 'yDomain', 'xRange', 'yRange', 'sizeDomain', 'sizeRange', 'forceX', 'forceY', 'forceSize', 'clipVoronoi', 'clipRadius', 'useVoronoi');
-  chart.options = nv.utils.optionsFunc.bind(chart);
-  
-  chart.margin = function(_) {
-    if (!arguments.length) return margin;
-    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
-    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
-    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
-    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
-    return chart;
-  };
-
-  chart.width = function(_) {
-    if (!arguments.length) return width;
-    width = _;
-    return chart;
-  };
-
-  chart.height = function(_) {
-    if (!arguments.length) return height;
-    height = _;
-    return chart;
-  };
-
-  chart.color = function(_) {
-    if (!arguments.length) return color;
-    color = nv.utils.getColor(_);
-    legend.color(color);
-    distX.color(color);
-    distY.color(color);
-    return chart;
-  };
-
-  chart.showDistX = function(_) {
-    if (!arguments.length) return showDistX;
-    showDistX = _;
-    return chart;
-  };
-
-  chart.showDistY = function(_) {
-    if (!arguments.length) return showDistY;
-    showDistY = _;
-    return chart;
-  };
-
-  chart.showControls = function(_) {
-    if (!arguments.length) return showControls;
-    showControls = _;
-    return chart;
-  };
-
-  chart.showLegend = function(_) {
-    if (!arguments.length) return showLegend;
-    showLegend = _;
-    return chart;
-  };
-
-  chart.showXAxis = function(_) {
-    if (!arguments.length) return showXAxis;
-    showXAxis = _;
-    return chart;
-  };
-
-  chart.showYAxis = function(_) {
-    if (!arguments.length) return showYAxis;
-    showYAxis = _;
-    return chart;
-  };
-
-  chart.rightAlignYAxis = function(_) {
-    if(!arguments.length) return rightAlignYAxis;
-    rightAlignYAxis = _;
-    yAxis.orient( (_) ? 'right' : 'left');
-    return chart;
-  };
-
-
-  chart.fisheye = function(_) {
-    if (!arguments.length) return fisheye;
-    fisheye = _;
-    return chart;
-  };
-
-  chart.xPadding = function(_) {
-    if (!arguments.length) return xPadding;
-    xPadding = _;
-    return chart;
-  };
-
-  chart.yPadding = function(_) {
-    if (!arguments.length) return yPadding;
-    yPadding = _;
-    return chart;
-  };
-
-  chart.tooltips = function(_) {
-    if (!arguments.length) return tooltips;
-    tooltips = _;
-    return chart;
-  };
-
-  chart.tooltipContent = function(_) {
-    if (!arguments.length) return tooltip;
-    tooltip = _;
-    return chart;
-  };
-
-  chart.tooltipXContent = function(_) {
-    if (!arguments.length) return tooltipX;
-    tooltipX = _;
-    return chart;
-  };
-
-  chart.tooltipYContent = function(_) {
-    if (!arguments.length) return tooltipY;
-    tooltipY = _;
-    return chart;
-  };
-
-  chart.state = function(_) {
-    if (!arguments.length) return state;
-    state = _;
-    return chart;
-  };
-
-  chart.defaultState = function(_) {
-    if (!arguments.length) return defaultState;
-    defaultState = _;
-    return chart;
-  };
-  
-  chart.noData = function(_) {
-    if (!arguments.length) return noData;
-    noData = _;
-    return chart;
-  };
-
-  chart.transitionDuration = function(_) {
-    if (!arguments.length) return transitionDuration;
-    transitionDuration = _;
-    return chart;
-  };
-
-  //============================================================
-
-
-  return chart;
-}

+ 0 - 508
desktop/core/src/desktop/static/desktop/js/nv.d3.sunburst.js

@@ -1,508 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-// based on http://bl.ocks.org/kerryrodden/477c1bfb081b783f80ad
-nv.models.sunburst = function () {
-  "use strict";
-
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var margin = {top: 0, right: 0, bottom: 0, left: 0}
-    , width = 600
-    , height = 600
-    , mode = "count"
-    , modes = {
-    count: function (d) {
-      return 1;
-    }, value: function (d) {
-      return d.value || d.size
-    }, size: function (d) {
-      return d.value || d.size
-    }
-  }
-    , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
-    , container = null
-    , color = nv.utils.defaultColor()
-    , showLabels = false
-    , labelFormat = function (d) {
-    if (mode === 'count') {
-      return d.name + ' #' + d.value
-    } else {
-      return d.name + ' ' + (d.value || d.size)
-    }
-  }
-    , labelThreshold = 0.02
-    , sort = function (d1, d2) {
-    return d1.name > d2.name;
-  }
-    , key = function (d, i) {
-    return d.name;
-  }
-    , groupColorByParent = true
-    , duration = 500
-    , dispatch = d3v3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMousemove', 'elementMouseover', 'elementMouseout', 'renderEnd');
-
-  //============================================================
-  // aux functions and setup
-  //------------------------------------------------------------
-
-  var x = d3v3.scale.linear().range([0, 2 * Math.PI]);
-  var y = d3v3.scale.sqrt();
-
-  var partition = d3v3.layout.partition().sort(sort);
-
-  var node, availableWidth, availableHeight, radius;
-  var prevPositions = {};
-
-  var arc = d3v3.svg.arc()
-    .startAngle(function (d) {
-      return Math.max(0, Math.min(2 * Math.PI, x(d.x)))
-    })
-    .endAngle(function (d) {
-      return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)))
-    })
-    .innerRadius(function (d) {
-      return Math.max(0, y(d.y))
-    })
-    .outerRadius(function (d) {
-      return Math.max(0, y(d.y + d.dy))
-    });
-
-  function rotationToAvoidUpsideDown(d) {
-    var centerAngle = computeCenterAngle(d);
-    if (centerAngle > 90) {
-      return 180;
-    }
-    else {
-      return 0;
-    }
-  }
-
-  function computeCenterAngle(d) {
-    var startAngle = Math.max(0, Math.min(2 * Math.PI, x(d.x)));
-    var endAngle = Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
-    var centerAngle = (((startAngle + endAngle) / 2) * (180 / Math.PI)) - 90;
-    return centerAngle;
-  }
-
-  function computeNodePercentage(d) {
-    var startAngle = Math.max(0, Math.min(2 * Math.PI, x(d.x)));
-    var endAngle = Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
-    return (endAngle - startAngle) / (2 * Math.PI);
-  }
-
-  function labelThresholdMatched(d) {
-    var startAngle = Math.max(0, Math.min(2 * Math.PI, x(d.x)));
-    var endAngle = Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
-
-    var size = endAngle - startAngle;
-    return size > labelThreshold;
-  }
-
-  // When zooming: interpolate the scales.
-  function arcTweenZoom(e, i) {
-    var xd = d3v3.interpolate(x.domain(), [node.x, node.x + node.dx]),
-      yd = d3v3.interpolate(y.domain(), [node.y, 1]),
-      yr = d3v3.interpolate(y.range(), [node.y ? 20 : 0, radius]);
-
-    if (i === 0) {
-      return function () {
-        return arc(e);
-      }
-    }
-    else {
-      return function (t) {
-        x.domain(xd(t));
-        y.domain(yd(t)).range(yr(t));
-        return arc(e);
-      }
-    }
-    ;
-  }
-
-  function arcTweenUpdate(d) {
-    var ipo = d3v3.interpolate({x: d.x0, dx: d.dx0, y: d.y0, dy: d.dy0}, d);
-
-    return function (t) {
-      var b = ipo(t);
-
-      d.x0 = b.x;
-      d.dx0 = b.dx;
-      d.y0 = b.y;
-      d.dy0 = b.dy;
-
-      return arc(b);
-    };
-  }
-
-  function updatePrevPosition(node) {
-    var k = key(node);
-    if (!prevPositions[k]) prevPositions[k] = {};
-    var pP = prevPositions[k];
-    pP.dx = node.dx;
-    pP.x = node.x;
-    pP.dy = node.dy;
-    pP.y = node.y;
-  }
-
-  function storeRetrievePrevPositions(nodes) {
-    nodes.forEach(function (n) {
-      var k = key(n);
-      var pP = prevPositions[k];
-      //console.log(k,n,pP);
-      if (pP) {
-        n.dx0 = pP.dx;
-        n.x0 = pP.x;
-        n.dy0 = pP.dy;
-        n.y0 = pP.y;
-      }
-      else {
-        n.dx0 = n.dx;
-        n.x0 = n.x;
-        n.dy0 = n.dy;
-        n.y0 = n.y;
-      }
-      updatePrevPosition(n);
-    });
-  }
-
-  function zoomClick(d) {
-    var labels = container.selectAll('text')
-    var path = container.selectAll('path')
-
-    // fade out all text elements
-    labels.transition().attr("opacity", 0);
-
-    // to allow reference to the new center node
-    node = d;
-
-    path.transition()
-      .duration(duration)
-      .attrTween("d", arcTweenZoom)
-      .each('end', function (e) {
-        // partially taken from here: http://bl.ocks.org/metmajer/5480307
-        // check if the animated element's data e lies within the visible angle span given in d
-        if (e.x >= d.x && e.x < (d.x + d.dx)) {
-          if (e.depth >= d.depth) {
-            // get a selection of the associated text element
-            var parentNode = d3v3.select(this.parentNode);
-            var arcText = parentNode.select('text');
-
-            // fade in the text element and recalculate positions
-            arcText.transition().duration(duration)
-              .text(function (e) {
-                return labelFormat(e)
-              })
-              .attr("opacity", function (d) {
-                if (labelThresholdMatched(d)) {
-                  return 1;
-                }
-                else {
-                  return 0;
-                }
-              })
-              .attr("transform", function () {
-                var width = this.getBBox().width;
-                if (e.depth === 0)
-                  return "translate(" + (width / 2 * -1) + ",0)";
-                else if (e.depth === d.depth) {
-                  return "translate(" + (y(e.y) + 5) + ",0)";
-                }
-                else {
-                  var centerAngle = computeCenterAngle(e);
-                  var rotation = rotationToAvoidUpsideDown(e);
-                  if (rotation === 0) {
-                    return 'rotate(' + centerAngle + ')translate(' + (y(e.y) + 5) + ',0)';
-                  }
-                  else {
-                    return 'rotate(' + centerAngle + ')translate(' + (y(e.y) + width + 5) + ',0)rotate(' + rotation + ')';
-                  }
-                }
-              });
-          }
-        }
-      })
-  }
-
-  //============================================================
-  // chart function
-  //------------------------------------------------------------
-  var renderWatch = nv.utils.renderWatch(dispatch);
-
-  function chart(selection) {
-    renderWatch.reset();
-
-    selection.each(function (data) {
-      container = d3v3.select(this);
-      availableWidth = nv.utils.availableWidth(width, container, margin);
-      availableHeight = nv.utils.availableHeight(height, container, margin);
-      radius = Math.min(availableWidth, availableHeight) / 2;
-
-      y.range([0, radius]);
-
-      // Setup containers and skeleton of chart
-      var wrap = container.select('g.nvd3v3.nv-wrap.nv-sunburst');
-      if (!wrap[0][0]) {
-        wrap = container.append('g')
-          .attr('class', 'nvd3 nv-wrap nv-sunburst nv-chart-' + id)
-          .attr('transform', 'translate(' + ((availableWidth / 2) + margin.left + margin.right) + ',' + ((availableHeight / 2) + margin.top + margin.bottom) + ')');
-      } else {
-        wrap.attr('transform', 'translate(' + ((availableWidth / 2) + margin.left + margin.right) + ',' + ((availableHeight / 2) + margin.top + margin.bottom) + ')');
-      }
-
-      container.on('click', function (d, i) {
-        dispatch.chartClick({
-          data: d,
-          index: i,
-          pos: d3v3.event,
-          id: id
-        });
-      });
-
-      partition.value(modes[mode] || modes["count"]);
-
-      //reverse the drawing order so that the labels of inner
-      //arcs are drawn on top of the outer arcs.
-      var nodes = partition.nodes(data[0]).reverse()
-
-      storeRetrievePrevPositions(nodes);
-      var cG = wrap.selectAll('.arc-container').data(nodes, key)
-
-      //handle new datapoints
-      var cGE = cG.enter()
-        .append("g")
-        .attr("class", 'arc-container')
-
-      cGE.append("path")
-        .attr("d", arc)
-        .style("fill", function (d) {
-          if (d.color) {
-            return d.color;
-          }
-          else if (groupColorByParent) {
-            return color((d.children ? d : d.parent).name);
-          }
-          else {
-            return color(d.name);
-          }
-        })
-        .style("stroke", "#FFF")
-        .on("click", function (d, i) {
-          zoomClick(d);
-          dispatch.elementClick({
-            data: d,
-            index: i
-          })
-        })
-        .on('mouseover', function (d, i) {
-          d3v3.select(this).classed('hover', true).style('opacity', 0.8);
-          dispatch.elementMouseover({
-            data: d,
-            color: d3v3.select(this).style("fill"),
-            percent: computeNodePercentage(d)
-          });
-        })
-        .on('mouseout', function (d, i) {
-          d3v3.select(this).classed('hover', false).style('opacity', 1);
-          dispatch.elementMouseout({
-            data: d
-          });
-        })
-        .on('mousemove', function (d, i) {
-          dispatch.elementMousemove({
-            data: d
-          });
-        });
-
-      ///Iterating via each and selecting based on the this
-      ///makes it work ... a cG.selectAll('path') doesn't.
-      ///Without iteration the data (in the element) didn't update.
-      cG.each(function (d) {
-        d3v3.select(this).select('path')
-          .transition()
-          .duration(duration)
-          .attrTween('d', arcTweenUpdate);
-      });
-
-      if (showLabels) {
-        //remove labels first and add them back
-        cG.selectAll('text').remove();
-
-        //this way labels are on top of newly added arcs
-        cG.append('text')
-          .text(function (e) {
-            return labelFormat(e)
-          })
-          .transition()
-          .duration(duration)
-          .attr("opacity", function (d) {
-            if (labelThresholdMatched(d)) {
-              return 1;
-            }
-            else {
-              return 0;
-            }
-          })
-          .attr("transform", function (d) {
-            var width = this.getBBox().width;
-            if (d.depth === 0) {
-              return "rotate(0)translate(" + (width / 2 * -1) + ",0)";
-            }
-            else {
-              var centerAngle = computeCenterAngle(d);
-              var rotation = rotationToAvoidUpsideDown(d);
-              if (rotation === 0) {
-                return 'rotate(' + centerAngle + ')translate(' + (y(d.y) + 5) + ',0)';
-              }
-              else {
-                return 'rotate(' + centerAngle + ')translate(' + (y(d.y) + width + 5) + ',0)rotate(' + rotation + ')';
-              }
-            }
-          });
-      }
-
-      //zoom out to the center when the data is updated.
-      zoomClick(nodes[nodes.length - 1])
-
-
-      //remove unmatched elements ...
-      cG.exit()
-        .transition()
-        .duration(duration)
-        .attr('opacity', 0)
-        .each('end', function (d) {
-          var k = key(d);
-          prevPositions[k] = undefined;
-        })
-        .remove();
-    });
-
-
-    renderWatch.renderEnd('sunburst immediate');
-    return chart;
-  }
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  chart.dispatch = dispatch;
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  chart._options = Object.create({}, {
-    // simple options, just get/set the necessary values
-    width: {
-      get: function () {
-        return width;
-      }, set: function (_) {
-        width = _;
-      }
-    },
-    height: {
-      get: function () {
-        return height;
-      }, set: function (_) {
-        height = _;
-      }
-    },
-    mode: {
-      get: function () {
-        return mode;
-      }, set: function (_) {
-        mode = _;
-      }
-    },
-    id: {
-      get: function () {
-        return id;
-      }, set: function (_) {
-        id = _;
-      }
-    },
-    duration: {
-      get: function () {
-        return duration;
-      }, set: function (_) {
-        duration = _;
-      }
-    },
-    groupColorByParent: {
-      get: function () {
-        return groupColorByParent;
-      }, set: function (_) {
-        groupColorByParent = !!_;
-      }
-    },
-    showLabels: {
-      get: function () {
-        return showLabels;
-      }, set: function (_) {
-        showLabels = !!_
-      }
-    },
-    labelFormat: {
-      get: function () {
-        return labelFormat;
-      }, set: function (_) {
-        labelFormat = _
-      }
-    },
-    labelThreshold: {
-      get: function () {
-        return labelThreshold;
-      }, set: function (_) {
-        labelThreshold = _
-      }
-    },
-    sort: {
-      get: function () {
-        return sort;
-      }, set: function (_) {
-        sort = _
-      }
-    },
-    key: {
-      get: function () {
-        return key;
-      }, set: function (_) {
-        key = _
-      }
-    },
-    // options that require extra logic in the setter
-    margin: {
-      get: function () {
-        return margin;
-      }, set: function (_) {
-        margin.top = _.top != undefined ? _.top : margin.top;
-        margin.right = _.right != undefined ? _.right : margin.right;
-        margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom;
-        margin.left = _.left != undefined ? _.left : margin.left;
-      }
-    },
-    color: {
-      get: function () {
-        return color;
-      }, set: function (_) {
-        color = nv.utils.getColor(_);
-      }
-    }
-  });
-
-  nv.utils.initOptions(chart);
-  return chart;
-};

+ 0 - 188
desktop/core/src/desktop/static/desktop/js/nv.d3.sunburstChart.js

@@ -1,188 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-nv.models.sunburstChart = function () {
-  "use strict";
-
-  //============================================================
-  // Public Variables with Default Settings
-  //------------------------------------------------------------
-
-  var sunburst = nv.models.sunburst();
-  var tooltip = nv.models.tooltip();
-
-  var margin = {top: 30, right: 20, bottom: 20, left: 20}
-    , width = null
-    , height = null
-    , color = nv.utils.defaultColor()
-    , showTooltipPercent = false
-    , id = Math.round(Math.random() * 100000)
-    , defaultState = null
-    , noData = null
-    , duration = 250
-    , dispatch = d3v3.dispatch('stateChange', 'changeState', 'renderEnd');
-
-
-  //============================================================
-  // Private Variables
-  //------------------------------------------------------------
-
-  var renderWatch = nv.utils.renderWatch(dispatch);
-
-  tooltip
-    .duration(0)
-    .headerEnabled(false)
-    .valueFormatter(function (d) {
-      return d;
-    });
-
-  //============================================================
-  // Chart function
-  //------------------------------------------------------------
-
-  function chart(selection) {
-    renderWatch.reset();
-    renderWatch.models(sunburst);
-
-    selection.each(function (data) {
-      var container = d3v3.select(this);
-
-      nv.utils.initSVG(container);
-
-      var availableWidth = nv.utils.availableWidth(width, container, margin);
-      var availableHeight = nv.utils.availableHeight(height, container, margin);
-
-      chart.update = function () {
-        if (duration === 0) {
-          container.call(chart);
-        } else {
-          container.transition().duration(duration).call(chart);
-        }
-      };
-      chart.container = container;
-
-      // Display No Data message if there's nothing to show.
-      if (!data || !data.length) {
-        nv.utils.noData(chart, container);
-        return chart;
-      } else {
-        container.selectAll('.nv-noData').remove();
-      }
-
-      sunburst.width(availableWidth).height(availableHeight).margin(margin);
-      container.call(sunburst);
-    });
-
-    renderWatch.renderEnd('sunburstChart immediate');
-    return chart;
-  }
-
-  //============================================================
-  // Event Handling/Dispatching (out of chart's scope)
-  //------------------------------------------------------------
-
-  sunburst.dispatch.on('elementMouseover.tooltip', function (evt) {
-    evt.series = {
-      key: evt.data.name,
-      value: (evt.data.value || evt.data.size),
-      color: evt.color,
-      percent: evt.percent
-    };
-    if (!showTooltipPercent) {
-      delete evt.percent;
-      delete evt.series.percent;
-    }
-    tooltip.data(evt).hidden(false);
-  });
-
-  sunburst.dispatch.on('elementMouseout.tooltip', function (evt) {
-    tooltip.hidden(true);
-  });
-
-  sunburst.dispatch.on('elementMousemove.tooltip', function (evt) {
-    tooltip();
-  });
-
-  //============================================================
-  // Expose Public Variables
-  //------------------------------------------------------------
-
-  // expose chart's sub-components
-  chart.dispatch = dispatch;
-  chart.sunburst = sunburst;
-  chart.tooltip = tooltip;
-  chart.options = nv.utils.optionsFunc.bind(chart);
-
-  // use Object get/set functionality to map between vars and chart functions
-  chart._options = Object.create({}, {
-    // simple options, just get/set the necessary values
-    noData: {
-      get: function () {
-        return noData;
-      }, set: function (_) {
-        noData = _;
-      }
-    },
-    defaultState: {
-      get: function () {
-        return defaultState;
-      }, set: function (_) {
-        defaultState = _;
-      }
-    },
-    showTooltipPercent: {
-      get: function () {
-        return showTooltipPercent;
-      }, set: function (_) {
-        showTooltipPercent = _;
-      }
-    },
-
-    // options that require extra logic in the setter
-    color: {
-      get: function () {
-        return color;
-      }, set: function (_) {
-        color = _;
-        sunburst.color(color);
-      }
-    },
-    duration: {
-      get: function () {
-        return duration;
-      }, set: function (_) {
-        duration = _;
-        renderWatch.reset(duration);
-        sunburst.duration(duration);
-      }
-    },
-    margin: {
-      get: function () {
-        return margin;
-      }, set: function (_) {
-        margin.top = _.top !== undefined ? _.top : margin.top;
-        margin.right = _.right !== undefined ? _.right : margin.right;
-        margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
-        margin.left = _.left !== undefined ? _.left : margin.left;
-        sunburst.margin(margin);
-      }
-    }
-  });
-  nv.utils.inheritOptions(chart, sunburst);
-  nv.utils.initOptions(chart);
-  return chart;
-
-};

+ 0 - 498
desktop/core/src/desktop/static/desktop/js/nv.d3.tooltip.js

@@ -1,498 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-/* Model which can be instantiated to handle tooltip rendering.
- Example usage:
- var tip = nv.models.tooltip().gravity('w').distance(23)
- .data(myDataObject);
-
- tip();    //just invoke the returned function to render tooltip.
- */
-nv.models.tooltip = function () {
-  "use strict";
-
-  /*
-   Tooltip data. If data is given in the proper format, a consistent tooltip is generated.
-   Example Format of data:
-   {
-   key: "Date",
-   value: "August 2009",
-   series: [
-   {key: "Series 1", value: "Value 1", color: "#000"},
-   {key: "Series 2", value: "Value 2", color: "#00f"}
-   ]
-   }
-   */
-  var id = "nvtooltip-" + Math.floor(Math.random() * 100000) // Generates a unique id when you create a new tooltip() object.
-    , data = null
-    , gravity = 'w'   // Can be 'n','s','e','w'. Determines how tooltip is positioned.
-    , distance = 25 // Distance to offset tooltip from the mouse location.
-    , snapDistance = 0   // Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect)
-    , classes = null  // Attaches additional CSS classes to the tooltip DIV that is created.
-    , hidden = true  // Start off hidden, toggle with hide/show functions below.
-    , hideDelay = 200  // Delay (in ms) before the tooltip hides after calling hide().
-    , tooltip = null // d3 select of the tooltip div.
-    , lastPosition = {left: null, top: null} // Last position the tooltip was in.
-    , enabled = true  // True -> tooltips are rendered. False -> don't render tooltips.
-    , duration = 100 // Tooltip movement duration, in ms.
-    , headerEnabled = true // If is to show the tooltip header.
-    , nvPointerEventsClass = "nv-pointer-events-none" // CSS class to specify whether element should not have mouse events.
-    ;
-
-  // Format function for the tooltip values column.
-  var valueFormatter = function (d, i) {
-    return d;
-  };
-
-  // Format function for the tooltip header value.
-  var headerFormatter = function (d) {
-    return d;
-  };
-
-  var keyFormatter = function (d, i) {
-    return d;
-  };
-
-  // By default, the tooltip model renders a beautiful table inside a DIV.
-  // You can override this function if a custom tooltip is desired.
-  var contentGenerator = function (d) {
-    if (d === null) {
-      return '';
-    }
-
-    var table = d3v3.select(document.createElement("table"));
-    if (headerEnabled) {
-      var theadEnter = table.selectAll("thead")
-        .data([d])
-        .enter().append("thead");
-
-      theadEnter.append("tr")
-        .append("td")
-        .attr("colspan", 3)
-        .append("strong")
-        .classed("x-value", true)
-        .html(headerFormatter(d.value));
-    }
-
-    var tbodyEnter = table.selectAll("tbody")
-      .data([d])
-      .enter().append("tbody");
-
-    var trowEnter = tbodyEnter.selectAll("tr")
-      .data(function (p) {
-        return p.series
-      })
-      .enter()
-      .append("tr")
-      .classed("highlight", function (p) {
-        return p.highlight
-      });
-
-    trowEnter.append("td")
-      .classed("legend-color-guide", true)
-      .append("div")
-      .style("background-color", function (p) {
-        return p.color
-      });
-
-    trowEnter.append("td")
-      .classed("key", true)
-      .classed("total", function (p) {
-        return !!p.total
-      })
-      .html(function (p, i) {
-        return keyFormatter(p.key, i)
-      });
-
-    trowEnter.append("td")
-      .classed("value", true)
-      .html(function (p, i) {
-        return valueFormatter(p.value, i)
-      });
-
-    trowEnter.filter(function (p, i) {
-      return p.percent !== undefined
-    }).append("td")
-      .classed("percent", true)
-      .html(function (p, i) {
-        return "(" + d3v3.format('%')(p.percent) + ")"
-      });
-
-    trowEnter.selectAll("td").each(function (p) {
-      if (p.highlight) {
-        var opacityScale = d3v3.scale.linear().domain([0, 1]).range(["#fff", p.color]);
-        var opacity = 0.6;
-        d3v3.select(this)
-          .style("border-bottom-color", opacityScale(opacity))
-          .style("border-top-color", opacityScale(opacity))
-        ;
-      }
-    });
-
-    var html = table.node().outerHTML;
-    if (d.footer !== undefined)
-      html += "<div class='footer'>" + d.footer + "</div>";
-    return html;
-
-  };
-
-  /*
-   Function that returns the position (relative to the viewport/document.body)
-   the tooltip should be placed in.
-   Should return: {
-   left: <leftPos>,
-   top: <topPos>
-   }
-   */
-  var position = function () {
-    var pos = {
-      left: d3v3.event !== null ? d3v3.event.clientX : 0,
-      top: d3v3.event !== null ? d3v3.event.clientY : 0
-    };
-
-    if (getComputedStyle(document.body).transform != 'none') {
-      // Take the offset into account, as now the tooltip is relative
-      // to document.body.
-      var client = document.body.getBoundingClientRect();
-      pos.left -= client.left;
-      pos.top -= client.top;
-    }
-
-    return pos;
-  };
-
-  var dataSeriesExists = function (d) {
-    if (d && d.series) {
-      if (nv.utils.isArray(d.series)) {
-        return true;
-      }
-      // if object, it's okay just convert to array of the object
-      if (nv.utils.isObject(d.series)) {
-        d.series = [d.series];
-        return true;
-      }
-    }
-    return false;
-  };
-
-  // Calculates the gravity offset of the tooltip. Parameter is position of tooltip
-  // relative to the viewport.
-  var calcGravityOffset = function (pos) {
-    var height = tooltip.node().offsetHeight,
-      width = tooltip.node().offsetWidth,
-      clientWidth = document.documentElement.clientWidth, // Don't want scrollbars.
-      clientHeight = document.documentElement.clientHeight, // Don't want scrollbars.
-      left, top, tmp;
-
-    // calculate position based on gravity
-    switch (gravity) {
-      case 'e':
-        left = -width - distance;
-        top = -(height / 2);
-        if (pos.left + left < 0) left = distance;
-        if ((tmp = pos.top + top) < 0) top -= tmp;
-        if ((tmp = pos.top + top + height) > clientHeight) top -= tmp - clientHeight;
-        break;
-      case 'w':
-        left = distance;
-        top = -(height / 2);
-        if (pos.left + left + width > clientWidth) left = -width - distance;
-        if ((tmp = pos.top + top) < 0) top -= tmp;
-        if ((tmp = pos.top + top + height) > clientHeight) top -= tmp - clientHeight;
-        break;
-      case 'n':
-        left = -(width / 2) - 5; // - 5 is an approximation of the mouse's height.
-        top = distance;
-        if (pos.top + top + height > clientHeight) top = -height - distance;
-        if ((tmp = pos.left + left) < 0) left -= tmp;
-        if ((tmp = pos.left + left + width) > clientWidth) left -= tmp - clientWidth;
-        break;
-      case 's':
-        left = -(width / 2);
-        top = -height - distance;
-        if (pos.top + top < 0) top = distance;
-        if ((tmp = pos.left + left) < 0) left -= tmp;
-        if ((tmp = pos.left + left + width) > clientWidth) left -= tmp - clientWidth;
-        break;
-      case 'center':
-        left = -(width / 2);
-        top = -(height / 2);
-        break;
-      default:
-        left = 0;
-        top = 0;
-        break;
-    }
-
-    return {'left': left, 'top': top};
-  };
-
-  /*
-   Positions the tooltip in the correct place, as given by the position() function.
-   */
-  var positionTooltip = function () {
-    nv.dom.read(function () {
-      var pos = position(),
-        gravityOffset = calcGravityOffset(pos),
-        left = pos.left + gravityOffset.left,
-        top = pos.top + gravityOffset.top;
-
-      // delay hiding a bit to avoid flickering
-      if (hidden) {
-        tooltip
-          .interrupt()
-          .transition()
-          .delay(hideDelay)
-          .duration(0)
-          .style('opacity', 0);
-      } else {
-        // using tooltip.style('transform') returns values un-usable for tween
-        var old_translate = 'translate(' + lastPosition.left + 'px, ' + lastPosition.top + 'px)';
-        var new_translate = 'translate(' + Math.round(left) + 'px, ' + Math.round(top) + 'px)';
-        var translateInterpolator = d3v3.interpolateString(old_translate, new_translate);
-        var is_hidden = tooltip.style('opacity') < 0.1;
-
-        tooltip
-          .interrupt() // cancel running transitions
-          .transition()
-          .duration(is_hidden ? 0 : duration)
-          // using tween since some versions of d3 can't auto-tween a translate on a div
-          .styleTween('transform', function (d) {
-            return translateInterpolator;
-          }, 'important')
-          // Safari has its own `-webkit-transform` and does not support `transform`
-          .styleTween('-webkit-transform', function (d) {
-            return translateInterpolator;
-          })
-          .style('-ms-transform', new_translate)
-          .style('opacity', 1);
-      }
-
-      lastPosition.left = left;
-      lastPosition.top = top;
-    });
-  };
-
-  // Creates new tooltip container, or uses existing one on DOM.
-  function initTooltip() {
-    if (!tooltip || !tooltip.node()) {
-      // Create new tooltip div if it doesn't exist on DOM.
-
-      var data = [1];
-      tooltip = d3v3.select(document.body).select('#' + id).data(data);
-
-      tooltip.enter().append('div')
-        .attr("class", "nvtooltip " + (classes ? classes : "xy-tooltip"))
-        .attr("id", id)
-        .style("top", 0).style("left", 0)
-        .style('opacity', 0)
-        .style('position', 'fixed')
-        .selectAll("div, table, td, tr").classed(nvPointerEventsClass, true)
-        .classed(nvPointerEventsClass, true);
-
-      tooltip.exit().remove()
-    }
-  }
-
-  // Draw the tooltip onto the DOM.
-  function nvtooltip() {
-    if (!enabled) return;
-    if (!dataSeriesExists(data)) return;
-
-    nv.dom.write(function () {
-      initTooltip();
-      // Generate data and set it into tooltip.
-      // Bonus - If you override contentGenerator and return falsey you can use something like
-      //         React or Knockout to bind the data for your tooltip.
-      var newContent = contentGenerator(data);
-      if (newContent) {
-        tooltip.node().innerHTML = newContent;
-      }
-
-      positionTooltip();
-    });
-
-    return nvtooltip;
-  }
-
-  nvtooltip.nvPointerEventsClass = nvPointerEventsClass;
-  nvtooltip.options = nv.utils.optionsFunc.bind(nvtooltip);
-
-  nvtooltip._options = Object.create({}, {
-    // simple read/write options
-    duration: {
-      get: function () {
-        return duration;
-      }, set: function (_) {
-        duration = _;
-      }
-    },
-    gravity: {
-      get: function () {
-        return gravity;
-      }, set: function (_) {
-        gravity = _;
-      }
-    },
-    distance: {
-      get: function () {
-        return distance;
-      }, set: function (_) {
-        distance = _;
-      }
-    },
-    snapDistance: {
-      get: function () {
-        return snapDistance;
-      }, set: function (_) {
-        snapDistance = _;
-      }
-    },
-    classes: {
-      get: function () {
-        return classes;
-      }, set: function (_) {
-        classes = _;
-      }
-    },
-    enabled: {
-      get: function () {
-        return enabled;
-      }, set: function (_) {
-        enabled = _;
-      }
-    },
-    hideDelay: {
-      get: function () {
-        return hideDelay;
-      }, set: function (_) {
-        hideDelay = _;
-      }
-    },
-    contentGenerator: {
-      get: function () {
-        return contentGenerator;
-      }, set: function (_) {
-        contentGenerator = _;
-      }
-    },
-    valueFormatter: {
-      get: function () {
-        return valueFormatter;
-      }, set: function (_) {
-        valueFormatter = _;
-      }
-    },
-    headerFormatter: {
-      get: function () {
-        return headerFormatter;
-      }, set: function (_) {
-        headerFormatter = _;
-      }
-    },
-    keyFormatter: {
-      get: function () {
-        return keyFormatter;
-      }, set: function (_) {
-        keyFormatter = _;
-      }
-    },
-    headerEnabled: {
-      get: function () {
-        return headerEnabled;
-      }, set: function (_) {
-        headerEnabled = _;
-      }
-    },
-    position: {
-      get: function () {
-        return position;
-      }, set: function (_) {
-        position = _;
-      }
-    },
-
-    // Deprecated options
-    chartContainer: {
-      get: function () {
-        return document.body;
-      }, set: function (_) {
-        // deprecated after 1.8.3
-        nv.deprecated('chartContainer', 'feature removed after 1.8.3');
-      }
-    },
-    fixedTop: {
-      get: function () {
-        return null;
-      }, set: function (_) {
-        // deprecated after 1.8.1
-        nv.deprecated('fixedTop', 'feature removed after 1.8.1');
-      }
-    },
-    offset: {
-      get: function () {
-        return {left: 0, top: 0};
-      }, set: function (_) {
-        // deprecated after 1.8.1
-        nv.deprecated('offset', 'use chart.tooltip.distance() instead');
-      }
-    },
-
-    // options with extra logic
-    hidden: {
-      get: function () {
-        return hidden;
-      }, set: function (_) {
-        if (hidden != _) {
-          hidden = !!_;
-          nvtooltip();
-        }
-      }
-    },
-    data: {
-      get: function () {
-        return data;
-      }, set: function (_) {
-        // if showing a single data point, adjust data format with that
-        if (_.point) {
-          _.value = _.point.x;
-          _.series = _.series || {};
-          _.series.value = _.point.y;
-          _.series.color = _.point.color || _.series.color;
-        }
-        data = _;
-      }
-    },
-
-    // read only properties
-    node: {
-      get: function () {
-        return tooltip.node();
-      }, set: function (_) {
-      }
-    },
-    id: {
-      get: function () {
-        return id;
-      }, set: function (_) {
-      }
-    }
-  });
-
-  nv.utils.initOptions(nvtooltip);
-  return nvtooltip;
-};

+ 0 - 747
desktop/core/src/desktop/static/desktop/js/nv.d3.utils.js

@@ -1,747 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you 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.
-
-
-/*
- Gets the browser window size
-
- Returns object with height and width properties
- */
-nv.utils.windowSize = function () {
-  // Sane defaults
-  var size = {width: 640, height: 480};
-
-  // Most recent browsers use
-  if (window.innerWidth && window.innerHeight) {
-    size.width = window.innerWidth;
-    size.height = window.innerHeight;
-    return (size);
-  }
-
-  // IE can use depending on mode it is in
-  if (document.compatMode == 'CSS1Compat' &&
-    document.documentElement &&
-    document.documentElement.offsetWidth) {
-
-    size.width = document.documentElement.offsetWidth;
-    size.height = document.documentElement.offsetHeight;
-    return (size);
-  }
-
-  // Earlier IE uses Doc.body
-  if (document.body && document.body.offsetWidth) {
-    size.width = document.body.offsetWidth;
-    size.height = document.body.offsetHeight;
-    return (size);
-  }
-
-  return (size);
-};
-
-
-/* handle dumb browser quirks...  isinstance breaks if you use frames
- typeof returns 'object' for null, NaN is a number, etc.
- */
-nv.utils.isArray = Array.isArray;
-nv.utils.isObject = function (a) {
-  return a !== null && typeof a === 'object';
-};
-nv.utils.isFunction = function (a) {
-  return typeof a === 'function';
-};
-nv.utils.isDate = function (a) {
-  return Object.prototype.toString.call(a) === '[object Date]';
-};
-nv.utils.isNumber = function (a) {
-  return !isNaN(a) && typeof a === 'number';
-};
-
-
-/*
- Binds callback function to run when window is resized
- */
-nv.utils.windowResize = function (handler) {
-  if (window.addEventListener) {
-    window.addEventListener('resize', handler);
-  } else {
-    nv.log("ERROR: Failed to bind to window.resize with: ", handler);
-  }
-  // return object with clear function to remove the single added callback.
-  return {
-    callback: handler,
-    clear: function () {
-      window.removeEventListener('resize', handler);
-    }
-  }
-};
-
-
-/*
- Backwards compatible way to implement more d3-like coloring of graphs.
- Can take in nothing, an array, or a function/scale
- To use a normal scale, get the range and pass that because we must be able
- to take two arguments and use the index to keep backward compatibility
- */
-nv.utils.getColor = function (color) {
-  //if you pass in nothing, get default colors back
-  if (color === undefined) {
-    return nv.utils.defaultColor();
-
-    //if passed an array, turn it into a color scale
-  } else if (nv.utils.isArray(color)) {
-    var color_scale = d3v3.scale.ordinal().range(color);
-    return function (d, i) {
-      var key = i === undefined ? d : i;
-      return d.color || color_scale(key);
-    };
-
-    //if passed a function or scale, return it, or whatever it may be
-    //external libs, such as angularjs-nvd3-directives use this
-  } else {
-    //can't really help it if someone passes rubbish as color
-    return color;
-  }
-};
-
-
-/*
- Default color chooser uses a color scale of 20 colors from D3
- https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors
- */
-nv.utils.defaultColor = function () {
-  // get range of the scale so we'll turn it into our own function.
-  return nv.utils.getColor(d3v3.scale.category20().range());
-};
-
-
-/*
- Returns a color function that takes the result of 'getKey' for each series and
- looks for a corresponding color from the dictionary
- */
-nv.utils.customTheme = function (dictionary, getKey, defaultColors) {
-  // use default series.key if getKey is undefined
-  getKey = getKey || function (series) {
-      return series.key
-    };
-  defaultColors = defaultColors || d3v3.scale.category20().range();
-
-  // start at end of default color list and walk back to index 0
-  var defIndex = defaultColors.length;
-
-  return function (series, index) {
-    var key = getKey(series);
-    if (nv.utils.isFunction(dictionary[key])) {
-      return dictionary[key]();
-    } else if (dictionary[key] !== undefined) {
-      return dictionary[key];
-    } else {
-      // no match in dictionary, use a default color
-      if (!defIndex) {
-        // used all the default colors, start over
-        defIndex = defaultColors.length;
-      }
-      defIndex = defIndex - 1;
-      return defaultColors[defIndex];
-    }
-  };
-};
-
-
-/*
- From the PJAX example on d3js.org, while this is not really directly needed
- it's a very cool method for doing pjax, I may expand upon it a little bit,
- open to suggestions on anything that may be useful
- */
-nv.utils.pjax = function (links, content) {
-
-  var load = function (href) {
-    d3v3.html(href, function (fragment) {
-      var target = d3v3.select(content).node();
-      target.parentNode.replaceChild(
-        d3v3.select(fragment).select(content).node(),
-        target);
-      nv.utils.pjax(links, content);
-    });
-  };
-
-  d3v3.selectAll(links).on("click", function () {
-    history.pushState(this.href, this.textContent, this.href);
-    load(this.href);
-    d3v3.event.preventDefault();
-  });
-
-  d3v3.select(window).on("popstate", function () {
-    if (d3v3.event.state) {
-      load(d3v3.event.state);
-    }
-  });
-};
-
-
-/*
- For when we want to approximate the width in pixels for an SVG:text element.
- Most common instance is when the element is in a display:none; container.
- Forumla is : text.length * font-size * constant_factor
- */
-nv.utils.calcApproxTextWidth = function (svgTextElem) {
-  if (nv.utils.isFunction(svgTextElem.style) && nv.utils.isFunction(svgTextElem.text)) {
-    var fontSize = parseInt(svgTextElem.style("font-size").replace("px", ""), 10);
-    var textLength = svgTextElem.text().length;
-    return nv.utils.NaNtoZero(textLength * fontSize * 0.5);
-  }
-  return 0;
-};
-
-
-/*
- Numbers that are undefined, null or NaN, convert them to zeros.
- */
-nv.utils.NaNtoZero = function (n) {
-  if (!nv.utils.isNumber(n)
-    || isNaN(n)
-    || n === null
-    || n === Infinity
-    || n === -Infinity) {
-
-    return 0;
-  }
-  return n;
-};
-
-/*
- Add a way to watch for d3 transition ends to d3
- */
-d3v3.selection.prototype.watchTransition = function (renderWatch) {
-  var args = [this].concat([].slice.call(arguments, 1));
-  return renderWatch.transition.apply(renderWatch, args);
-};
-
-
-/*
- Helper object to watch when d3 has rendered something
- */
-nv.utils.renderWatch = function (dispatch, duration) {
-  if (!(this instanceof nv.utils.renderWatch)) {
-    return new nv.utils.renderWatch(dispatch, duration);
-  }
-
-  var _duration = duration !== undefined ? duration : 250;
-  var renderStack = [];
-  var self = this;
-
-  this.models = function (models) {
-    models = [].slice.call(arguments, 0);
-    models.forEach(function (model) {
-      model.__rendered = false;
-      (function (m) {
-        m.dispatch.on('renderEnd', function (arg) {
-          m.__rendered = true;
-          self.renderEnd('model');
-        });
-      })(model);
-
-      if (renderStack.indexOf(model) < 0) {
-        renderStack.push(model);
-      }
-    });
-    return this;
-  };
-
-  this.reset = function (duration) {
-    if (duration !== undefined) {
-      _duration = duration;
-    }
-    renderStack = [];
-  };
-
-  this.transition = function (selection, args, duration) {
-    args = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
-
-    if (args.length > 1) {
-      duration = args.pop();
-    } else {
-      duration = _duration !== undefined ? _duration : 250;
-    }
-    selection.__rendered = false;
-
-    if (renderStack.indexOf(selection) < 0) {
-      renderStack.push(selection);
-    }
-
-    if (duration === 0) {
-      selection.__rendered = true;
-      selection.delay = function () {
-        return this;
-      };
-      selection.duration = function () {
-        return this;
-      };
-      return selection;
-    } else {
-      if (selection.length === 0) {
-        selection.__rendered = true;
-      } else if (selection.every(function (d) {
-          return !d.length;
-        })) {
-        selection.__rendered = true;
-      } else {
-        selection.__rendered = false;
-      }
-
-      var n = 0;
-      return selection
-        .transition()
-        .duration(duration)
-        .each(function () {
-          ++n;
-        })
-        .each('end', function (d, i) {
-          if (--n === 0) {
-            selection.__rendered = true;
-            self.renderEnd.apply(this, args);
-          }
-        });
-    }
-  };
-
-  this.renderEnd = function () {
-    if (renderStack.every(function (d) {
-        return d.__rendered;
-      })) {
-      renderStack.forEach(function (d) {
-        d.__rendered = false;
-      });
-      dispatch.renderEnd.apply(this, arguments);
-    }
-  }
-
-};
-
-
-/*
- Takes multiple objects and combines them into the first one (dst)
- example:  nv.utils.deepExtend({a: 1}, {a: 2, b: 3}, {c: 4});
- gives:  {a: 2, b: 3, c: 4}
- */
-nv.utils.deepExtend = function (dst) {
-  var sources = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
-  sources.forEach(function (source) {
-    for (var key in source) {
-      var isArray = nv.utils.isArray(dst[key]);
-      var isObject = nv.utils.isObject(dst[key]);
-      var srcObj = nv.utils.isObject(source[key]);
-
-      if (isObject && !isArray && srcObj) {
-        nv.utils.deepExtend(dst[key], source[key]);
-      } else {
-        dst[key] = source[key];
-      }
-    }
-  });
-};
-
-
-/*
- state utility object, used to track d3 states in the models
- */
-nv.utils.state = function () {
-  if (!(this instanceof nv.utils.state)) {
-    return new nv.utils.state();
-  }
-  var state = {};
-  var _self = this;
-  var _setState = function () {
-  };
-  var _getState = function () {
-    return {};
-  };
-  var init = null;
-  var changed = null;
-
-  this.dispatch = d3v3.dispatch('change', 'set');
-
-  this.dispatch.on('set', function (state) {
-    _setState(state, true);
-  });
-
-  this.getter = function (fn) {
-    _getState = fn;
-    return this;
-  };
-
-  this.setter = function (fn, callback) {
-    if (!callback) {
-      callback = function () {
-      };
-    }
-    _setState = function (state, update) {
-      fn(state);
-      if (update) {
-        callback();
-      }
-    };
-    return this;
-  };
-
-  this.init = function (state) {
-    init = init || {};
-    nv.utils.deepExtend(init, state);
-  };
-
-  var _set = function () {
-    var settings = _getState();
-
-    if (JSON.stringify(settings) === JSON.stringify(state)) {
-      return false;
-    }
-
-    for (var key in settings) {
-      if (state[key] === undefined) {
-        state[key] = {};
-      }
-      state[key] = settings[key];
-      changed = true;
-    }
-    return true;
-  };
-
-  this.update = function () {
-    if (init) {
-      _setState(init, false);
-      init = null;
-    }
-    if (_set.call(this)) {
-      this.dispatch.change(state);
-    }
-  };
-
-};
-
-
-/*
- Snippet of code you can insert into each nv.models.* to give you the ability to
- do things like:
- chart.options({
- showXAxis: true,
- tooltips: true
- });
-
- To enable in the chart:
- chart.options = nv.utils.optionsFunc.bind(chart);
- */
-nv.utils.optionsFunc = function (args) {
-  if (args) {
-    d3v3.map(args).forEach((function (key, value) {
-      if (nv.utils.isFunction(this[key])) {
-        this[key](value);
-      }
-    }).bind(this));
-  }
-  return this;
-};
-
-
-/*
- numTicks:  requested number of ticks
- data:  the chart data
-
- returns the number of ticks to actually use on X axis, based on chart data
- to avoid duplicate ticks with the same value
- */
-nv.utils.calcTicksX = function (numTicks, data) {
-  // find max number of values from all data streams
-  var numValues = 1;
-  var i = 0;
-  for (i; i < data.length; i += 1) {
-    var stream_len = data[i] && data[i].values ? data[i].values.length : 0;
-    numValues = stream_len > numValues ? stream_len : numValues;
-  }
-  nv.log("Requested number of ticks: ", numTicks);
-  nv.log("Calculated max values to be: ", numValues);
-  // make sure we don't have more ticks than values to avoid duplicates
-  numTicks = numTicks > numValues ? numTicks = numValues - 1 : numTicks;
-  // make sure we have at least one tick
-  numTicks = numTicks < 1 ? 1 : numTicks;
-  // make sure it's an integer
-  numTicks = Math.floor(numTicks);
-  nv.log("Calculating tick count as: ", numTicks);
-  return numTicks;
-};
-
-
-/*
- returns number of ticks to actually use on Y axis, based on chart data
- */
-nv.utils.calcTicksY = function (numTicks, data) {
-  // currently uses the same logic but we can adjust here if needed later
-  return nv.utils.calcTicksX(numTicks, data);
-};
-
-
-/*
- Add a particular option from an options object onto chart
- Options exposed on a chart are a getter/setter function that returns chart
- on set to mimic typical d3 option chaining, e.g. svg.option1('a').option2('b');
-
- option objects should be generated via Object.create() to provide
- the option of manipulating data via get/set functions.
- */
-nv.utils.initOption = function (chart, name) {
-  // if it's a call option, just call it directly, otherwise do get/set
-  if (chart._calls && chart._calls[name]) {
-    chart[name] = chart._calls[name];
-  } else {
-    chart[name] = function (_) {
-      if (!arguments.length) return chart._options[name];
-      chart._overrides[name] = true;
-      chart._options[name] = _;
-      return chart;
-    };
-    // calling the option as _option will ignore if set by option already
-    // so nvd3 can set options internally but the stop if set manually
-    chart['_' + name] = function (_) {
-      if (!arguments.length) return chart._options[name];
-      if (!chart._overrides[name]) {
-        chart._options[name] = _;
-      }
-      return chart;
-    }
-  }
-};
-
-
-/*
- Add all options in an options object to the chart
- */
-nv.utils.initOptions = function (chart) {
-  chart._overrides = chart._overrides || {};
-  var ops = Object.getOwnPropertyNames(chart._options || {});
-  var calls = Object.getOwnPropertyNames(chart._calls || {});
-  ops = ops.concat(calls);
-  for (var i in ops) {
-    nv.utils.initOption(chart, ops[i]);
-  }
-};
-
-
-/*
- Inherit options from a D3 object
- d3v3.rebind makes calling the function on target actually call it on source
- Also use _d3options so we can track what we inherit for documentation and chained inheritance
- */
-nv.utils.inheritOptionsD3 = function (target, d3_source, oplist) {
-  target._d3options = oplist.concat(target._d3options || []);
-  oplist.unshift(d3_source);
-  oplist.unshift(target);
-  d3v3.rebind.apply(this, oplist);
-};
-
-
-/*
- Remove duplicates from an array
- */
-nv.utils.arrayUnique = function (a) {
-  return a.sort().filter(function (item, pos) {
-    return !pos || item != a[pos - 1];
-  });
-};
-
-
-/*
- Keeps a list of custom symbols to draw from in addition to d3v3.svg.symbol
- Necessary since d3 doesn't let you extend its list -_-
- Add new symbols by doing nv.utils.symbols.set('name', function(size){...});
- */
-nv.utils.symbolMap = d3v3.map();
-
-
-/*
- Replaces d3v3.svg.symbol so that we can look both there and our own map
- */
-nv.utils.symbol = function () {
-  var type,
-    size = 64;
-
-  function symbol(d, i) {
-    var t = type.call(this, d, i);
-    var s = size.call(this, d, i);
-    if (d3v3.svg.symbolTypes.indexOf(t) !== -1) {
-      return d3v3.svg.symbol().type(t).size(s)();
-    } else {
-      return nv.utils.symbolMap.get(t)(s);
-    }
-  }
-
-  symbol.type = function (_) {
-    if (!arguments.length) return type;
-    type = d3v3.functor(_);
-    return symbol;
-  };
-  symbol.size = function (_) {
-    if (!arguments.length) return size;
-    size = d3v3.functor(_);
-    return symbol;
-  };
-  return symbol;
-};
-
-
-/*
- Inherit option getter/setter functions from source to target
- d3v3.rebind makes calling the function on target actually call it on source
- Also track via _inherited and _d3options so we can track what we inherit
- for documentation generation purposes and chained inheritance
- */
-nv.utils.inheritOptions = function (target, source) {
-  // inherit all the things
-  var ops = Object.getOwnPropertyNames(source._options || {});
-  var calls = Object.getOwnPropertyNames(source._calls || {});
-  var inherited = source._inherited || [];
-  var d3ops = source._d3options || [];
-  var args = ops.concat(calls).concat(inherited).concat(d3ops);
-  args.unshift(source);
-  args.unshift(target);
-  d3v3.rebind.apply(this, args);
-  // pass along the lists to keep track of them, don't allow duplicates
-  target._inherited = nv.utils.arrayUnique(ops.concat(calls).concat(inherited).concat(ops).concat(target._inherited || []));
-  target._d3options = nv.utils.arrayUnique(d3ops.concat(target._d3options || []));
-};
-
-
-/*
- Runs common initialize code on the svg before the chart builds
- */
-nv.utils.initSVG = function (svg) {
-  svg.classed({'nvd3-svg': true});
-};
-
-
-/*
- Sanitize and provide default for the container height.
- */
-nv.utils.sanitizeHeight = function (height, container) {
-  return (height || parseInt(container.style('height'), 10) || 400);
-};
-
-
-/*
- Sanitize and provide default for the container width.
- */
-nv.utils.sanitizeWidth = function (width, container) {
-  return (width || parseInt(container.style('width'), 10) || 960);
-};
-
-
-/*
- Calculate the available height for a chart.
- */
-nv.utils.availableHeight = function (height, container, margin) {
-  return Math.max(0, nv.utils.sanitizeHeight(height, container) - margin.top - margin.bottom);
-};
-
-/*
- Calculate the available width for a chart.
- */
-nv.utils.availableWidth = function (width, container, margin) {
-  return Math.max(0, nv.utils.sanitizeWidth(width, container) - margin.left - margin.right);
-};
-
-/*
- Clear any rendered chart components and display a chart's 'noData' message
- */
-nv.utils.noData = function (chart, container) {
-  var opt = chart.options(),
-    margin = opt.margin(),
-    noData = opt.noData(),
-    data = (noData == null) ? ["No Data Available."] : [noData],
-    height = nv.utils.availableHeight(null, container, margin),
-    width = nv.utils.availableWidth(null, container, margin),
-    x = margin.left + width / 2,
-    y = margin.top + height / 2;
-
-  //Remove any previously created chart components
-  container.selectAll('g').remove();
-
-  var noDataText = container.selectAll('.nv-noData').data(data);
-
-  noDataText.enter().append('text')
-    .attr('class', 'nvd3 nv-noData')
-    .attr('dy', '-.7em')
-    .style('text-anchor', 'middle');
-
-  noDataText
-    .attr('x', x)
-    .attr('y', y)
-    .text(function (t) {
-      return t;
-    });
-};
-
-/*
- Wrap long labels.
- */
-nv.utils.wrapTicks = function (text, width) {
-  text.each(function () {
-    var text = d3v3.select(this),
-      words = text.text().split(/\s+/).reverse(),
-      word,
-      line = [],
-      lineNumber = 0,
-      lineHeight = 1.1,
-      y = text.attr("y"),
-      dy = parseFloat(text.attr("dy")),
-      tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
-    while (word = words.pop()) {
-      line.push(word);
-      tspan.text(line.join(" "));
-      if (tspan.node().getComputedTextLength() > width) {
-        line.pop();
-        tspan.text(line.join(" "));
-        line = [word];
-        tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
-      }
-    }
-  });
-};
-
-/*
- Check equality of 2 array
- */
-nv.utils.arrayEquals = function (array1, array2) {
-  if (array1 === array2)
-    return true;
-
-  if (!array1 || !array2)
-    return false;
-
-  // compare lengths - can save a lot of time
-  if (array1.length != array2.length)
-    return false;
-
-  for (var i = 0,
-         l = array1.length; i < l; i++) {
-    // Check if we have nested arrays
-    if (array1[i] instanceof Array && array2[i] instanceof Array) {
-      // recurse into the nested arrays
-      if (!nv.arrayEquals(array1[i], array2[i]))
-        return false;
-    } else if (array1[i] != array2[i]) {
-      // Warning - two different object instances will never be equal: {x:20} != {x:20}
-      return false;
-    }
-  }
-  return true;
-};

+ 0 - 54
desktop/core/src/desktop/templates/charting.mako

@@ -1,54 +0,0 @@
-## Licensed to Cloudera, Inc. under one
-## or more contributor license agreements.  See the NOTICE file
-## distributed with this work for additional information
-## regarding copyright ownership.  Cloudera, Inc. licenses this file
-## to you 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.
-
-<%!
-from desktop import conf
-%>
-
-<%def name="import_charts()">
-  <link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
-  <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.css') }">
-  <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.markercluster.css') }">
-  <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.zoombox.css') }">
-
-  <script src="${ static('desktop/js/hue.geo.js') }"></script>
-
-  <script src="${ static('desktop/ext/js/leaflet/leaflet.js') }"></script>
-  <script src="${ static('desktop/ext/js/leaflet/leaflet.markercluster.js') }"></script>
-  <script src="${ static('desktop/ext/js/leaflet/leaflet.zoombox.js') }"></script>
-  <script src="${ static('desktop/ext/js/leaflet/leaflet.heat.js') }"></script>
-
-  %if conf.USE_NEW_CHARTS.get():
-  <script src="${ static('desktop/ext/js/plotly-latest.min.js') }"></script>
-  <script src="${ static('desktop/js/ko.charts.plotly.js') }"></script>
-  <script src="${ static('desktop/js/ko.charts.leaflet.js') }"></script>
-  %else:
-  <link rel="stylesheet" href="${ static('desktop/ext/css/nv.d3.min.css') }">
-  <link rel="stylesheet" href="${ static('desktop/css/nv.d3.css') }">
-
-  <script src="${ static('desktop/js/nv.d3.legend.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.multiBarWithBrushChart.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.lineWithBrushChart.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.growingDiscreteBar.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.growingDiscreteBarChart.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.growingMultiBar.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.growingMultiBarChart.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.growingPie.js') }"></script>
-  <script src="${ static('desktop/js/nv.d3.growingPieChart.js') }"></script>
-  <script src="${ static('desktop/js/ko.charts.leaflet.js') }"></script>
-  %endif
-
-</%def>

+ 0 - 2
desktop/core/src/desktop/templates/common_header.mako

@@ -31,7 +31,6 @@ if USE_NEW_EDITOR.get():
   home_url = url('desktop_views_home2')
 %>
 
-<%namespace name="charting" file="/charting.mako" />
 <%namespace name="commonHeaderFooterComponents" file="/common_header_footer_components.mako" />
 <%namespace name="hueAceAutocompleter" file="/hue_ace_autocompleter.mako" />
 <%namespace name="hueIcons" file="/hue_icons.mako" />
@@ -161,7 +160,6 @@ if USE_NEW_EDITOR.get():
 
   <script src="${ static('metastore/js/metastore.model.js') }"></script>
 
-  ${ charting.import_charts() }
   ${ koComponents.all() }
   ${ hueAceAutocompleter.hueAceAutocompleter() }
 %endif

+ 0 - 3
desktop/core/src/desktop/templates/common_header_m.mako

@@ -126,9 +126,6 @@ if USE_NEW_EDITOR.get():
     ace.config.set("basePath", "/static/desktop/js/ace");
   </script>
 
-  <%namespace name="charting" file="/charting.mako" />
-  ${ charting.import_charts() }
-
   <script type="text/javascript">
 
     moment.locale(window.navigator.userLanguage || window.navigator.language);

+ 8 - 2
desktop/core/src/desktop/templates/hue.mako

@@ -91,6 +91,14 @@
 % endif
   <link rel="stylesheet" href="${ static('desktop/ext/chosen/chosen.min.css') }">
   <link rel="stylesheet" href="${ static('desktop/ext/select2/select2.css') }">
+
+  <link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
+  <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.css') }">
+  <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.markercluster.css') }">
+  <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.zoombox.css') }">
+  <link rel="stylesheet" href="${ static('desktop/ext/css/nv.d3.min.css') }">
+  <link rel="stylesheet" href="${ static('desktop/css/nv.d3.css') }">
+
   <script type="text/javascript">
 % if IS_EMBEDDED.get():
   // Bootstrap 2.3.2 relies on the hide css class presence for modals but doesn't remove it when opened for fade type
@@ -480,12 +488,10 @@ ${ render_bundle('hue') | n,unicode }
   var shareViewModel = initSharing("#documentShareModal");
 </script>
 
-<%namespace name="charting" file="/charting.mako" />
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="notebookKoComponents" file="/common_notebook_ko_components.mako" />
 <%namespace name="hueAceAutocompleter" file="/hue_ace_autocompleter.mako" />
 
-${ charting.import_charts() }
 ${ configKoComponents.config() }
 ${ notebookKoComponents.aceKeyboardShortcuts() }
 ${ notebookKoComponents.downloadSnippetResults() }

+ 0 - 1
desktop/libs/dashboard/src/dashboard/templates/common_search.mako

@@ -3063,7 +3063,6 @@ ${ dashboard.layout_skeleton(suffix='search') }
 <link rel="stylesheet" href="${ static('dashboard/css/search_mobile.css') }">
 %endif
 <link rel="stylesheet" href="${ static('desktop/ext/css/hue-filetypes.css') }">
-<link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
 <link rel="stylesheet" href="${ static('desktop/ext/css/jquery.gridster.min.css') }">
 
 ${ dashboard.import_layout(True) }

+ 3 - 2
ext/thirdparty/README.md

@@ -174,8 +174,9 @@ Frontend third party dependencies (some checked in and some via npm)
 |Knockout Validation|2.0.3|MIT|https://github.com/Knockout-Contrib/Knockout-Validation|
 |KnockoutJS|3.4.2|MIT|https://github.com/knockout/knockout|
 |Leaflet|0.7.2|BSD|https://github.com/Leaflet/Leaflet|
-|Leaflet Heat|?|BSD|https://github.com/mourner/simpleheat|
-|Leaflet ZoomBox|?|ISC|https://github.com/consbio/Leaflet.ZoomBox|
+|Leaflet Heat|0.2.0|BSD|https://github.com/mourner/simpleheat|
+|Leaflet Marker cluster|0.5.0|MIT|https://github.com/Leaflet/Leaflet.markercluster|
+|Leaflet ZoomBox|0.5.1|ISC|https://github.com/consbio/Leaflet.ZoomBox|
 |LESS|3.9.0|Apache|https://github.com/less/less.js/|
 |Load Grunt Tasks|4.0.0|MIT|https://www.npmjs.com/package/load-grunt-tasks|
 |LocalForage|1.7.3|Apache|https://github.com/localForage/localForage|

+ 28 - 0
package-lock.json

@@ -7110,6 +7110,29 @@
         "invert-kv": "^2.0.0"
       }
     },
+    "leaflet": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-0.7.2.tgz",
+      "integrity": "sha1-gUpYh9BER9qQtWPAZRm3k0bXHkA="
+    },
+    "leaflet-zoombox": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/leaflet-zoombox/-/leaflet-zoombox-0.5.1.tgz",
+      "integrity": "sha512-qbLm6vkJzN1thr1cQFf9xsP+M7K5dz0Xa4EAt9kppkGDxV9Xewr1kpg6e8JBFfCGcqJi6pulNhkxLnfooxYZRQ=="
+    },
+    "leaflet.heat": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/leaflet.heat/-/leaflet.heat-0.2.0.tgz",
+      "integrity": "sha1-EJ2M9Ybwre5B8Fr/Ax4np3/swik="
+    },
+    "leaflet.markercluster": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-0.5.0.tgz",
+      "integrity": "sha1-gEpcKwLsrLGcBkolM5arYNXfaZs=",
+      "requires": {
+        "leaflet": "~0.7.1"
+      }
+    },
     "less": {
       "version": "3.9.0",
       "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz",
@@ -8598,6 +8621,11 @@
         }
       }
     },
+    "plotly.js-dist": {
+      "version": "1.45.3",
+      "resolved": "https://registry.npmjs.org/plotly.js-dist/-/plotly.js-dist-1.45.3.tgz",
+      "integrity": "sha512-suJi344/mTIQn3OKVjDtnDwiv9dhnluGqaH+poqgdJABp21rjDMa07LUQV5nZJ68d6+ZYTjkpC/DPfkiP+8ezA=="
+    },
     "pluralize": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",

+ 9 - 4
package.json

@@ -25,26 +25,31 @@
   },
   "dependencies": {
     "clipboard": "1.7.1",
-    "d3v3": "1.0.3",
     "d3": "5.7.0",
+    "d3v3": "1.0.3",
     "dropzone": "5.5.1",
     "filesize": "4.0.0",
     "jquery": "3.3.1",
-    "jquery-ui": "1.12.1",
-    "jquery.cookie": "1.4.1",
     "jquery-form": "4.2.2",
     "jquery-mousewheel": "3.1.13",
+    "jquery-ui": "1.12.1",
+    "jquery.cookie": "1.4.1",
     "knockout": "3.4.2",
-    "knockout.mapping": "2.4.3",
     "knockout-sortable": "1.1.0",
     "knockout-switch-case": "2.1.0",
+    "knockout.mapping": "2.4.3",
     "knockout.validation": "2.0.3",
+    "leaflet": "0.7.2",
+    "leaflet-zoombox": "0.5.1",
+    "leaflet.heat": "0.2.0",
+    "leaflet.markercluster": "0.5.0",
     "less": "3.9.0",
     "localforage": "1.7.3",
     "lodash": "4.17.11",
     "medium-editor": "5.23.3",
     "minimist": "^1.2.0",
     "page": "1.8.6",
+    "plotly.js-dist": "1.45.3",
     "select2": "3.5.1",
     "selectize": "0.12.6",
     "selectize-plugin-clear": "0.0.3",

Some files were not shown because too many files changed in this diff