瀏覽代碼

HUE-8687 [frontend] Move D3 and chart bindings into webpack

Johan Ahlen 6 年之前
父節點
當前提交
1606475570
共有 28 個文件被更改,包括 2583 次插入1776 次删除
  1. 4 4
      .eslintrc.js
  2. 13 13
      apps/beeswax/src/beeswax/templates/execute.mako
  3. 0 2
      apps/jobbrowser/src/jobbrowser/templates/job_browser.mako
  4. 14 14
      desktop/core/src/desktop/js/apps/notebook/snippet.js
  5. 8 1
      desktop/core/src/desktop/js/hue.js
  6. 678 0
      desktop/core/src/desktop/js/ko/bindings/charts/chartUtils.js
  7. 106 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.barChart.js
  8. 68 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.lineChart.js
  9. 350 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.mapChart.js
  10. 229 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.partitionChart.js
  11. 183 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.pieChart.js
  12. 90 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.scatterChart.js
  13. 91 0
      desktop/core/src/desktop/js/ko/bindings/charts/ko.timelineChart.js
  14. 8 0
      desktop/core/src/desktop/js/ko/ko.all.js
  15. 343 0
      desktop/core/src/desktop/js/utils/d3Extensions.js
  16. 0 0
      desktop/core/src/desktop/static/desktop/ext/js/d3.v3.js
  17. 0 1
      desktop/core/src/desktop/static/desktop/ext/js/d3.v4.js
  18. 0 1
      desktop/core/src/desktop/static/desktop/ext/js/d3.v5.js
  19. 0 1625
      desktop/core/src/desktop/static/desktop/js/ko.charts.js
  20. 0 3
      desktop/core/src/desktop/templates/charting.mako
  21. 14 14
      desktop/core/src/desktop/templates/common_dashboard.mako
  22. 0 2
      desktop/core/src/desktop/templates/common_header.mako
  23. 0 2
      desktop/core/src/desktop/templates/common_header_m.mako
  24. 3 3
      desktop/libs/dashboard/src/dashboard/static/dashboard/js/search.ko.js
  25. 42 42
      desktop/libs/dashboard/src/dashboard/templates/common_search.mako
  26. 49 49
      desktop/libs/notebook/src/notebook/templates/editor_components.mako
  27. 288 0
      package-lock.json
  28. 2 0
      package.json

+ 4 - 4
.eslintrc.js

@@ -11,12 +11,12 @@ const hueGlobals = [
   'USER_HOME_DIR', 'WorkerGlobalScope',
 
   // other misc
-  'ace', 'Autocompleter', 'CodeMirror', 'd3v3', 'impalaDagre', 'less', 'MediumEditor', 'moment', 'Plotly', 'Role',
-  'sqlStatementsParser', 'trackOnGA',
+  'ace', 'Autocompleter', 'CodeMirror', 'Datamap', 'd3v3', 'HueGeo', 'impalaDagre', 'less', 'MediumEditor', 'moment',
+  'nv', 'Plotly', 'Role', 'sqlStatementsParser', 'trackOnGA',
 
   // jasmine
-  'afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'describe', 'expect', 'fail', 'fit', 'it', 'jasmine', 'spyOn',
-  'xdescribe', 'xit'
+  'afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'describe', 'expect', 'fail', 'fdescribe', 'fit', 'it', 'jasmine',
+  'spyOn', 'xdescribe', 'xit'
 ];
 
 const globals = normalGlobals.concat(hueGlobals).reduce((acc, key) => {

+ 13 - 13
apps/beeswax/src/beeswax/templates/execute.mako

@@ -1813,7 +1813,7 @@ function generateGraph(graphType) {
   $("#chart .alert").addClass("hide");
   if (graphType != "") {
     $("#blueprint").attr("class", "").attr("style", "").empty();
-    if (graphType == ko.HUE_CHARTS.TYPES.MAP) {
+    if (graphType == window.HUE_CHARTS.TYPES.MAP) {
       if ($("#blueprintLat").val() != "-1" && $("#blueprintLng").val() != "-1") {
         var _latCol = $("#blueprintLat").val() * 1;
         var _lngCol = $("#blueprintLng").val() * 1;
@@ -1882,16 +1882,16 @@ function generateGraph(graphType) {
 function getGraphType() {
   var _type = "";
   if ($("#blueprintBars").hasClass("active")) {
-    _type = ko.HUE_CHARTS.TYPES.BARCHART;
+    _type = window.HUE_CHARTS.TYPES.BARCHART;
   }
   if ($("#blueprintLines").hasClass("active")) {
-    _type = ko.HUE_CHARTS.TYPES.LINECHART;
+    _type = window.HUE_CHARTS.TYPES.LINECHART;
   }
   if ($("#blueprintMap").hasClass("active")) {
-    _type = ko.HUE_CHARTS.TYPES.MAP;
+    _type = window.HUE_CHARTS.TYPES.MAP;
   }
   if ($("#blueprintPie").hasClass("active")) {
-    _type = ko.HUE_CHARTS.TYPES.PIECHART;
+    _type = window.HUE_CHARTS.TYPES.PIECHART;
   }
   viewModel.chartType(_type);
   return _type;
@@ -1963,26 +1963,26 @@ $(document).ready(function () {
   $("#blueprintBars").on("click", function () {
     $("#blueprintAxis").removeClass("hide");
     $("#blueprintLatLng").addClass("hide");
-    viewModel.chartType(ko.HUE_CHARTS.TYPES.BARCHART);
-    generateGraph(ko.HUE_CHARTS.TYPES.BARCHART)
+    viewModel.chartType(window.HUE_CHARTS.TYPES.BARCHART);
+    generateGraph(window.HUE_CHARTS.TYPES.BARCHART)
   });
   $("#blueprintLines").on("click", function () {
     $("#blueprintAxis").removeClass("hide");
     $("#blueprintLatLng").addClass("hide");
-    viewModel.chartType(ko.HUE_CHARTS.TYPES.LINECHART);
-    generateGraph(ko.HUE_CHARTS.TYPES.LINECHART)
+    viewModel.chartType(window.HUE_CHARTS.TYPES.LINECHART);
+    generateGraph(window.HUE_CHARTS.TYPES.LINECHART)
   });
   $("#blueprintPie").on("click", function () {
     $("#blueprintAxis").removeClass("hide");
     $("#blueprintLatLng").addClass("hide");
-    viewModel.chartType(ko.HUE_CHARTS.TYPES.PIECHART);
-    generateGraph(ko.HUE_CHARTS.TYPES.PIECHART)
+    viewModel.chartType(window.HUE_CHARTS.TYPES.PIECHART);
+    generateGraph(window.HUE_CHARTS.TYPES.PIECHART)
   });
   $("#blueprintMap").on("click", function () {
     $("#blueprintAxis").addClass("hide");
     $("#blueprintLatLng").removeClass("hide");
-    viewModel.chartType(ko.HUE_CHARTS.TYPES.MAP);
-    generateGraph(ko.HUE_CHARTS.TYPES.MAP)
+    viewModel.chartType(window.HUE_CHARTS.TYPES.MAP);
+    generateGraph(window.HUE_CHARTS.TYPES.MAP)
   });
 
   $("#blueprintNoSort").on("click", function () {

+ 0 - 2
apps/jobbrowser/src/jobbrowser/templates/job_browser.mako

@@ -52,10 +52,8 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
 <link rel="stylesheet" href="${ static('jobbrowser/css/jobbrowser-embeddable.css') }">
 
 <script src="${ static('oozie/js/dashboard-utils.js') }" type="text/javascript" charset="utf-8"></script>
-<script src="${ static('desktop/ext/js/d3.v5.js') }"></script>
 
 % if ENABLE_QUERY_BROWSER.get():
-<script src="${ static('desktop/ext/js/d3.v3.js') }"></script>
 <script src="${ static('desktop/ext/js/dagre-d3-min.js') }"></script>
 <script src="${ static('jobbrowser/js/impala_dagre.js') }"></script>
 % endif

+ 14 - 14
desktop/core/src/desktop/js/apps/notebook/snippet.js

@@ -1057,7 +1057,7 @@ class Snippet {
       const type = self.chartType();
       hueAnalytics.log('notebook', 'chart/' + type);
 
-      if (type === ko.HUE_CHARTS.TYPES.MAP && self.result.cleanedNumericMeta().length >= 2) {
+      if (type === window.HUE_CHARTS.TYPES.MAP && self.result.cleanedNumericMeta().length >= 2) {
         if (self.chartX() === null || typeof self.chartX() === 'undefined') {
           let name = self.result.cleanedNumericMeta()[0].name;
           self.result.cleanedNumericMeta().forEach(fld => {
@@ -1087,9 +1087,9 @@ class Snippet {
 
       if (
         (self.chartX() === null || typeof self.chartX() === 'undefined') &&
-        (type == ko.HUE_CHARTS.TYPES.BARCHART ||
-          type == ko.HUE_CHARTS.TYPES.PIECHART ||
-          type == ko.HUE_CHARTS.TYPES.GRADIENTMAP) &&
+        (type == window.HUE_CHARTS.TYPES.BARCHART ||
+          type == window.HUE_CHARTS.TYPES.PIECHART ||
+          type == window.HUE_CHARTS.TYPES.GRADIENTMAP) &&
         self.result.cleanedStringMeta().length >= 1
       ) {
         self.chartX(self.result.cleanedStringMeta()[0].name);
@@ -1098,7 +1098,7 @@ class Snippet {
       if (self.result.cleanedNumericMeta().length > 0) {
         if (
           self.chartYMulti().length === 0 &&
-          (type === ko.HUE_CHARTS.TYPES.BARCHART || type === ko.HUE_CHARTS.TYPES.LINECHART)
+          (type === window.HUE_CHARTS.TYPES.BARCHART || type === window.HUE_CHARTS.TYPES.LINECHART)
         ) {
           self.chartYMulti.push(
             self.result.cleanedNumericMeta()[
@@ -1107,11 +1107,11 @@ class Snippet {
           );
         } else if (
           (self.chartYSingle() === null || typeof self.chartYSingle() === 'undefined') &&
-          (type === ko.HUE_CHARTS.TYPES.PIECHART ||
-            type === ko.HUE_CHARTS.TYPES.MAP ||
-            type === ko.HUE_CHARTS.TYPES.GRADIENTMAP ||
-            type === ko.HUE_CHARTS.TYPES.SCATTERCHART ||
-            (type === ko.HUE_CHARTS.TYPES.BARCHART && self.chartXPivot() !== null))
+          (type === window.HUE_CHARTS.TYPES.PIECHART ||
+            type === window.HUE_CHARTS.TYPES.MAP ||
+            type === window.HUE_CHARTS.TYPES.GRADIENTMAP ||
+            type === window.HUE_CHARTS.TYPES.SCATTERCHART ||
+            (type === window.HUE_CHARTS.TYPES.BARCHART && self.chartXPivot() !== null))
         ) {
           if (self.chartYMulti().length === 0) {
             self.chartYSingle(
@@ -1166,7 +1166,7 @@ class Snippet {
     self.chartType = ko.observable(
       typeof snippet.chartType != 'undefined' && snippet.chartType != null
         ? snippet.chartType
-        : ko.HUE_CHARTS.TYPES.BARCHART
+        : window.HUE_CHARTS.TYPES.BARCHART
     );
     self.chartType.subscribe(prepopulateChart);
     self.chartSorting = ko.observable(
@@ -1246,9 +1246,9 @@ class Snippet {
 
     self.hasDataForChart = ko.computed(() => {
       if (
-        self.chartType() == ko.HUE_CHARTS.TYPES.BARCHART ||
-        self.chartType() == ko.HUE_CHARTS.TYPES.LINECHART ||
-        self.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART
+        self.chartType() == window.HUE_CHARTS.TYPES.BARCHART ||
+        self.chartType() == window.HUE_CHARTS.TYPES.LINECHART ||
+        self.chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART
       ) {
         return (
           typeof self.chartX() != 'undefined' &&

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

@@ -14,10 +14,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import _ from 'lodash';
 import 'jquery/jquery.common';
 import 'ext/bootstrap.2.3.2.min';
 import 'ext/bootstrap-editable.1.5.1.min';
-import _ from 'lodash';
+
+import * as d3 from 'd3';
+import d3v3 from 'd3v3';
+import 'utils/d3Extensions';
+
 import Dropzone from 'dropzone';
 import filesize from 'filesize';
 import qq from 'ext/fileuploader.custom';
@@ -70,6 +75,8 @@ window.apiHelper = apiHelper;
 window.CancellablePromise = CancellablePromise;
 window.contextCatalog = contextCatalog;
 window.dataCatalog = dataCatalog;
+window.d3 = d3;
+window.d3v3 = d3v3;
 window.Dropzone = Dropzone;
 window.EditorViewModel = EditorViewModel;
 window.filesize = filesize;

+ 678 - 0
desktop/core/src/desktop/js/ko/bindings/charts/chartUtils.js

@@ -0,0 +1,678 @@
+// 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 huePubSub from 'utils/huePubSub';
+
+const MS = 1;
+const SECOND_MS = 1000 * MS;
+const MINUTE_MS = SECOND_MS * 60;
+const HOUR_MS = MINUTE_MS * 60;
+const DAY_MS = HOUR_MS * 24;
+const WEEK_MS = DAY_MS * 7;
+const MONTH_MS = DAY_MS * 30.5;
+const YEAR_MS = DAY_MS * 365;
+
+const addLegend = element => {
+  const $el = d3v3.select($(element)[0]);
+  const $div = $el.select('div');
+  if (!$div.size()) {
+    $el
+      .append('div')
+      .style('position', 'absolute')
+      .style('overflow', 'auto')
+      .style('top', '20px')
+      .style('right', '0px')
+      .style('width', '175px')
+      .style('height', 'calc(100% - 20px)')
+      .append('svg');
+  } else {
+    $div.append('svg');
+  }
+};
+
+const barChartBuilder = (element, options, isTimeline) => {
+  let _datum = options.transformer(options.datum, isTimeline);
+  $(element).height(300);
+
+  const _isPivot = options.isPivot != null ? options.isPivot : false;
+
+  if ($(element).find('svg').length > 0 && (_datum.length === 0 || _datum[0].values.length === 0)) {
+    $(element)
+      .find('svg')
+      .remove();
+  }
+
+  if (_datum.length > 0 && _datum[0].values.length > 0 && isNaN(_datum[0].values[0].y)) {
+    _datum = [];
+    $(element)
+      .find('svg')
+      .remove();
+  }
+
+  nv.addGraph(() => {
+    if (
+      $(element).find('svg').length > 0 &&
+      $(element).find('.nv-discreteBarWithAxes').length > 0
+    ) {
+      $(element)
+        .find('svg')
+        .empty();
+    }
+    const _chart = nv.models.multiBarWithBrushChart();
+    _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
+    if (_datum.length > 0) {
+      $(element).data('chart_type', 'multibar_brush');
+    }
+    _chart.onSelectRange((from, to) => {
+      huePubSub.publish('charts.state', { updating: true });
+      options.onSelectRange(from, to);
+    });
+    _chart.multibar.dispatch.on('elementClick', d => {
+      if (typeof options.onClick != 'undefined') {
+        huePubSub.publish('charts.state', { updating: true });
+        options.onClick(d.point);
+      }
+    });
+    _chart.onStateChange(options.onStateChange);
+    if (options.selectedSerie) {
+      _chart.onLegendChange(state => {
+        const selectedSerie = options.selectedSerie();
+        const _datum = d3v3.select($(element).find('svg')[0]).datum();
+        for (let i = 0; i < state.disabled.length; i++) {
+          selectedSerie[_datum[i].key] = !state.disabled[i];
+        }
+        options.selectedSerie(selectedSerie);
+      });
+    }
+    _chart.multibar.hideable(true);
+    _chart.multibar.stacked(typeof options.stacked != 'undefined' ? options.stacked : false);
+    if (isTimeline) {
+      _chart.convert = function(d) {
+        return isTimeline ? new Date(moment(d[0].obj.from).valueOf()) : parseFloat(d);
+      };
+      _chart.staggerLabels(false);
+      _chart.tooltipContent(values => {
+        return values.map(value => {
+          value = JSON.parse(JSON.stringify(value));
+          value.x = moment(value.x)
+            .utc()
+            .format('YYYY-MM-DD HH:mm:ss');
+          value.y = _chart.yAxis.tickFormat()(value.y);
+          return value;
+        });
+      });
+      _chart.xAxis.tickFormat(multi(_chart.xAxis));
+      _chart.multibar.stacked(typeof options.stacked != 'undefined' ? options.stacked : false);
+      _chart.onChartUpdate(() => {
+        _d3.selectAll('g.nv-x.nv-axis g text').each(function(d) {
+          insertLinebreaks(_chart, d, this);
+        });
+      });
+    } else if (numeric(_datum)) {
+      _chart.xAxis.showMaxMin(false).tickFormat(d3v3.format(',0f'));
+      _chart.staggerLabels(false);
+    } else if (!_isPivot) {
+      _chart.multibar.barColor(nv.utils.defaultColor());
+      _chart.staggerLabels(true);
+    }
+    if ($(element).width() < 300 && typeof _chart.showLegend != 'undefined') {
+      _chart.showLegend(false);
+    }
+    _chart.transitionDuration(0);
+
+    _chart.yAxis.tickFormat(d3v3.format('s'));
+
+    $(element).data('chart', _chart);
+    handleSelection(_chart, options, _datum);
+    const _d3 =
+      $(element).find('svg').length > 0
+        ? d3v3.select($(element).find('svg')[0])
+        : d3v3.select($(element)[0]).insert('svg', ':first-child');
+    if ($(element).find('svg').length < 2) {
+      addLegend(element);
+    }
+    _d3
+      .datum(_datum)
+      .transition()
+      .duration(150)
+      .each('end', () => {
+        if (options.onComplete != null) {
+          options.onComplete();
+        }
+        if (isTimeline) {
+          _d3.selectAll('g.nv-x.nv-axis g text').each(function(d) {
+            insertLinebreaks(_chart, d, this);
+          });
+        }
+        if (options.slot && _chart.recommendedTicks) {
+          options.slot(_chart.recommendedTicks());
+        }
+      })
+      .call(_chart);
+
+    if (!options.skipWindowResize) {
+      let _resizeTimeout = -1;
+      nv.utils.windowResize(() => {
+        window.clearTimeout(_resizeTimeout);
+        _resizeTimeout = window.setTimeout(() => {
+          _chart.update();
+        }, 200);
+      });
+    }
+
+    $(element).on('forceUpdate', () => {
+      _chart.update();
+    });
+
+    return _chart;
+  });
+};
+
+const handleSelection = (_chart, _options, _datum) => {
+  let i, j;
+  if (_options.selectedSerie) {
+    const selectedSerie = _options.selectedSerie();
+    let enabledCount = 0;
+    for (i = 0; i < _datum.length; i++) {
+      if (!selectedSerie[_datum[i].key]) {
+        _datum[i].disabled = true;
+      } else {
+        enabledCount++;
+      }
+    }
+    if (enabledCount === 0) {
+      // Get the 5 series with the most non zero elements on x axis & total value.
+      const stats = {};
+      for (i = 0; i < _datum.length; i++) {
+        if (!stats[_datum[i].key]) {
+          stats[_datum[i].key] = { count: 0, total: 0 };
+        }
+        for (j = 0; j < _datum[i].values.length; j++) {
+          stats[_datum[i].key].count += Math.min(_datum[i].values[j].y, 1);
+          stats[_datum[i].key].total += _datum[i].values[j].y;
+        }
+      }
+      const aStats = Object.keys(stats).map(key => {
+        return { key: key, stat: stats[key] };
+      });
+      aStats.sort((a, b) => {
+        return a.stat.count - b.stat.count || a.stat.total - b.stat.total;
+      });
+      for (i = aStats.length - 1; i >= Math.max(aStats.length - 5, 0); i--) {
+        _datum[i].disabled = false;
+        selectedSerie[_datum[i].key] = true;
+      }
+    }
+  }
+  const _isPivot = _options.isPivot != null ? _options.isPivot : false;
+  const _hideSelection =
+    typeof _options.hideSelection !== 'undefined'
+      ? typeof _options.hideSelection === 'function'
+        ? _options.hideSelection()
+        : _options.hideSelection
+      : false;
+  let _enableSelection =
+    typeof _options.enableSelection !== 'undefined'
+      ? typeof _options.enableSelection === 'function'
+        ? _options.enableSelection()
+        : _options.enableSelection
+      : true;
+  _enableSelection = _enableSelection && numeric(_datum);
+  const _hideStacked =
+    _options.hideStacked !== null
+      ? typeof _options.hideStacked === 'function'
+        ? _options.hideStacked()
+        : _options.hideStacked
+      : false;
+  const _displayValuesInLegend =
+    _options.displayValuesInLegend !== null
+      ? typeof _options.displayValuesInLegend === 'function'
+        ? _options.displayValuesInLegend()
+        : _options.displayValuesInLegend
+      : false;
+  const fHideSelection = _isPivot || _hideSelection ? _chart.hideSelection : _chart.showSelection;
+  if (fHideSelection) {
+    fHideSelection.call(_chart);
+  }
+  const fEnableSelection = _enableSelection ? _chart.enableSelection : _chart.disableSelection;
+  if (fEnableSelection) {
+    fEnableSelection.call(_chart);
+  }
+  const fHideStacked = _hideStacked ? _chart.hideStacked : _chart.showStacked;
+  if (fHideStacked) {
+    fHideStacked.call(_chart);
+  }
+  if (_chart.displayValuesInLegend) {
+    _chart.displayValuesInLegend(_displayValuesInLegend);
+  }
+  if (_chart.selectBars) {
+    const _field = typeof _options.field == 'function' ? _options.field() : _options.field;
+    let bHasSelection = false;
+    $.each(_options.fqs ? _options.fqs() : [], (cnt, item) => {
+      if (item.id() === _options.datum.widget_id) {
+        if (item.field() === _field) {
+          if (item.properties && typeof item.properties === 'function') {
+            bHasSelection = true;
+            _chart.selectBars({
+              singleValues: $.map(item.filter(), it => {
+                return it.value();
+              }),
+              rangeValues: $.map(item.properties(), it => {
+                return { from: it.from(), to: it.to() };
+              })
+            });
+          } else {
+            bHasSelection = true;
+            _chart.selectBars(
+              $.map(item.filter(), it => {
+                return it.value();
+              })
+            );
+          }
+        }
+        if (Array.isArray(item.field())) {
+          bHasSelection = true;
+          _chart.selectBars({
+            field: item.field(),
+            selected: $.map(item.filter(), it => {
+              return { values: it.value() };
+            })
+          });
+        }
+      }
+    });
+    if (!bHasSelection) {
+      _chart.selectBars({ field: '', selected: [] });
+    }
+  }
+};
+
+const insertLinebreaks = (_chart, d, ref) => {
+  const _el = d3v3.select(ref);
+  const _mom = moment(d);
+  if (_mom != null && _mom.isValid()) {
+    const _words = _el.text().split(' ');
+    _el.text('');
+    for (let i = 0; i < _words.length; i++) {
+      const tspan = _el.append('tspan').text(_words[i]);
+      if (i > 0) {
+        tspan.attr('x', 0).attr('dy', '15');
+      }
+    }
+  }
+};
+
+const lineChartBuilder = (element, options, isTimeline) => {
+  let _datum = options.transformer(options.datum);
+  $(element).height(300);
+  if ($(element).find('svg').length > 0 && (_datum.length === 0 || _datum[0].values.length === 0)) {
+    $(element)
+      .find('svg')
+      .empty();
+  }
+  if (
+    _datum.length > 0 &&
+    _datum[0].values.length > 0 &&
+    (isNaN(_datum[0].values[0].x) || isNaN(_datum[0].values[0].y))
+  ) {
+    _datum = [];
+    $(element)
+      .find('svg')
+      .empty();
+  }
+
+  if ($(element).is(':visible')) {
+    nv.addGraph(() => {
+      const _chart = nv.models.lineWithBrushChart();
+      _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
+      $(element).data('chart', _chart);
+      _chart.transitionDuration(0);
+      _chart.convert = function(d) {
+        return isTimeline ? new Date(moment(d[0].obj.from).valueOf()) : parseFloat(d);
+      };
+      if (options.showControls != null) {
+        _chart.showControls(false);
+      }
+      _chart.onSelectRange((from, to) => {
+        huePubSub.publish('charts.state', { updating: true });
+        options.onSelectRange(
+          $.isNumeric(from) && isTimeline ? new Date(moment(from).valueOf()) : parseInt(from),
+          $.isNumeric(to) && isTimeline ? new Date(moment(to).valueOf()) : parseInt(to)
+        ); // FIXME when using pdouble we should not parseInt.
+      });
+      if (options.selectedSerie) {
+        _chart.onLegendChange(state => {
+          const selectedSerie = options.selectedSerie();
+          const _datum = d3v3.select($(element).find('svg')[0]).datum();
+          for (let i = 0; i < state.disabled.length; i++) {
+            selectedSerie[_datum[i].key] = !state.disabled[i];
+          }
+          options.selectedSerie(selectedSerie);
+        });
+      }
+      _chart.xAxis.showMaxMin(false);
+      if (isTimeline) {
+        _chart.xScale(d3v3.time.scale.utc());
+        _chart.tooltipContent(values => {
+          return values.map(value => {
+            value = JSON.parse(JSON.stringify(value));
+            value.x = moment(value.x)
+              .utc()
+              .format('YYYY-MM-DD HH:mm:ss');
+            value.y = _chart.yAxis.tickFormat()(value.y);
+            return value;
+          });
+        });
+        _chart.xAxis.tickFormat(multi(_chart.xAxis, _chart));
+        _chart.onChartUpdate(() => {
+          _d3.selectAll('g.nv-x.nv-axis g text').each(function(d) {
+            insertLinebreaks(_chart, d, this);
+          });
+        });
+      }
+
+      _chart.yAxis.tickFormat(d3v3.format('s'));
+      handleSelection(_chart, options, _datum);
+      const _d3 =
+        $(element).find('svg').length > 0
+          ? d3v3.select($(element).find('svg')[0])
+          : d3v3.select($(element)[0]).insert('svg', ':first-child');
+      if ($(element).find('svg').length < 2) {
+        addLegend(element);
+      }
+      _d3
+        .datum(_datum)
+        .transition()
+        .duration(150)
+        .each('end', () => {
+          if (options.onComplete != null) {
+            options.onComplete();
+          }
+          if (isTimeline) {
+            _d3.selectAll('g.nv-x.nv-axis g text').each(function(d) {
+              insertLinebreaks(_chart, d, this);
+            });
+          }
+        })
+        .call(_chart);
+
+      let _resizeTimeout = -1;
+      nv.utils.windowResize(() => {
+        window.clearTimeout(_resizeTimeout);
+        _resizeTimeout = window.setTimeout(() => {
+          _chart.update();
+        }, 200);
+      });
+
+      $(element).on('forceUpdate', () => {
+        _chart.update();
+      });
+      _chart.lines.dispatch.on('elementClick', d => {
+        if (typeof options.onClick != 'undefined') {
+          huePubSub.publish('charts.state', { updating: true });
+          options.onClick(d.point);
+        }
+      });
+
+      return _chart;
+    });
+  }
+};
+
+const multi = xAxis => {
+  let previous = new Date(9999, 11, 31);
+  return d3v3.time.format.utc.multi([
+    [
+      '%H:%M:%S %Y-%m-%d',
+      function(d) {
+        const domain = xAxis.domain();
+        const result =
+          (previous > d || d === domain[0]) &&
+          moment(d)
+            .utc()
+            .seconds();
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%H:%M %Y-%m-%d',
+      function(d) {
+        const domain = xAxis.domain();
+        const result = previous > d || d === domain[0];
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%S %H:%M',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .minutes() !==
+            moment(d)
+              .utc()
+              .minutes() && previousDiff < MINUTE_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%S',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .seconds() !==
+            moment(d)
+              .utc()
+              .seconds() && previousDiff < MINUTE_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%H:%M:%S %Y-%m-%d',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .date() !==
+            moment(d)
+              .utc()
+              .date() &&
+          previousDiff < WEEK_MS &&
+          moment(d)
+            .utc()
+            .seconds();
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%H:%M %Y-%m-%d',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .date() !==
+            moment(d)
+              .utc()
+              .date() && previousDiff < WEEK_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%H:%M:%S',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          (moment(previous)
+            .utc()
+            .hours() !==
+            moment(d)
+              .utc()
+              .hours() ||
+            moment(previous)
+              .utc()
+              .minutes() !==
+              moment(d)
+                .utc()
+                .minutes()) &&
+          previousDiff < WEEK_MS &&
+          moment(d)
+            .utc()
+            .seconds();
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%H:%M',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          (moment(previous)
+            .utc()
+            .hours() !==
+            moment(d)
+              .utc()
+              .hours() ||
+            moment(previous)
+              .utc()
+              .minutes() !==
+              moment(d)
+                .utc()
+                .minutes()) &&
+          previousDiff < WEEK_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%d %Y-%m',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .months() !==
+            moment(d)
+              .utc()
+              .months() && previousDiff < MONTH_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%d',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .date() !==
+            moment(d)
+              .utc()
+              .date() && previousDiff < MONTH_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%m %Y',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .years() !==
+            moment(d)
+              .utc()
+              .years() && previousDiff < YEAR_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%m',
+      function(d) {
+        const previousDiff = Math.abs(d - previous);
+        const result =
+          moment(previous)
+            .utc()
+            .months() !==
+            moment(d)
+              .utc()
+              .months() && previousDiff < YEAR_MS;
+        if (result) {
+          previous = d;
+        }
+        return result;
+      }
+    ],
+    [
+      '%Y',
+      function(d) {
+        previous = d;
+        return true;
+      }
+    ]
+  ]);
+};
+
+const numeric = _datum => {
+  for (let j = 0; j < _datum.length; j++) {
+    for (let i = 0; i < _datum[j].values.length; i++) {
+      if (isNaN(_datum[j].values[i].x * 1)) {
+        return false;
+      }
+    }
+  }
+  return true;
+};
+
+export { barChartBuilder, handleSelection, insertLinebreaks, lineChartBuilder, numeric };

+ 106 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.barChart.js

@@ -0,0 +1,106 @@
+// 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 {
+  barChartBuilder,
+  handleSelection,
+  lineChartBuilder,
+  numeric
+} from 'ko/bindings/charts/chartUtils';
+import huePubSub from 'utils/huePubSub';
+
+ko.bindingHandlers.barChart = {
+  init: function(element, valueAccessor) {
+    const _options = ko.unwrap(valueAccessor());
+    if (_options.type && _options.type() === 'line') {
+      window.setTimeout(() => {
+        lineChartBuilder(element, valueAccessor(), false);
+      }, 0);
+      $(element).data('type', 'line');
+    } else {
+      window.setTimeout(() => {
+        barChartBuilder(element, valueAccessor(), false);
+      }, 0);
+      $(element).data('type', 'bar');
+    }
+  },
+  update: function(element, valueAccessor) {
+    const _options = ko.unwrap(valueAccessor());
+    if (_options.type && _options.type() !== $(element).data('type')) {
+      if ($(element).find('svg').length > 0) {
+        $(element)
+          .find('svg')
+          .remove();
+      }
+      if (_options.type() === 'line') {
+        window.setTimeout(() => {
+          lineChartBuilder(element, valueAccessor(), false);
+        }, 0);
+      } else {
+        window.setTimeout(() => {
+          barChartBuilder(element, valueAccessor(), false);
+        }, 0);
+      }
+      $(element).data('type', _options.type());
+    }
+    const _datum = _options.transformer(_options.datum);
+    const _chart = $(element).data('chart');
+    const _isPivot = _options.isPivot != null ? _options.isPivot : false;
+
+    if (_chart) {
+      _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
+      if (_chart.multibar) {
+        _chart.multibar.stacked(typeof _options.stacked != 'undefined' ? _options.stacked : false);
+      }
+      if (numeric(_datum)) {
+        _chart.xAxis.showMaxMin(false).tickFormat(d3v3.format(',0f'));
+        if (_chart.multibar) {
+          _chart.multibar.barColor(null);
+        }
+      } else {
+        _chart.xAxis.tickFormat(s => {
+          return s;
+        });
+        if (_chart.multibar) {
+          if (!_isPivot) {
+            _chart.multibar.barColor(nv.utils.defaultColor());
+          } else {
+            _chart.multibar.barColor(null);
+          }
+        }
+      }
+      window.setTimeout(() => {
+        handleSelection(_chart, _options, _datum);
+        const _d3 = d3v3.select($(element).find('svg')[0]);
+        _d3
+          .datum(_datum)
+          .transition()
+          .duration(150)
+          .each('end', () => {
+            if (_options.onComplete != null) {
+              _options.onComplete();
+            }
+          })
+          .call(_chart);
+        huePubSub.publish('charts.state');
+      }, 0);
+    }
+  }
+};

+ 68 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.lineChart.js

@@ -0,0 +1,68 @@
+// 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 { insertLinebreaks, lineChartBuilder } from 'ko/bindings/charts/chartUtils';
+import huePubSub from 'utils/huePubSub';
+
+ko.bindingHandlers.lineChart = {
+  init: function(element, valueAccessor) {
+    window.setTimeout(() => {
+      lineChartBuilder(element, valueAccessor(), false);
+    }, 0);
+  },
+  update: function(element, valueAccessor) {
+    const _options = valueAccessor();
+    const _datum = _options.transformer(_options.datum);
+    const _chart = $(element).data('chart');
+    if (_chart) {
+      window.setTimeout(() => {
+        _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
+        const _d3 = d3v3.select($(element).find('svg')[0]);
+        if (
+          _datum.length > 0 &&
+          _datum[0].values.length > 0 &&
+          typeof _datum[0].values[0].x.isValid === 'function'
+        ) {
+          _chart.xAxis.tickFormat(d => {
+            return d3v3.time.format('%Y-%m-%d %H:%M:%S')(new Date(d));
+          });
+          _chart.onChartUpdate(() => {
+            _d3.selectAll('g.nv-x.nv-axis g text').each(function(d) {
+              insertLinebreaks(_chart, d, this);
+            });
+          });
+        }
+        _d3
+          .datum(_datum)
+          .transition()
+          .duration(150)
+          .each('end', () => {
+            if (_options.onComplete != null) {
+              _options.onComplete();
+            }
+          })
+          .call(_chart);
+        huePubSub.publish('charts.state');
+      }, 0);
+    } else if (_datum.length > 0) {
+      ko.bindingHandlers.lineChart.init(element, valueAccessor);
+    }
+  }
+};

+ 350 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.mapChart.js

@@ -0,0 +1,350 @@
+// 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 huePubSub from 'utils/huePubSub';
+import HueColors from 'utils/hueColors';
+
+ko.bindingHandlers.mapChart = {
+  render: function(element, valueAccessor) {
+    const _options = valueAccessor();
+
+    $(element).empty();
+
+    $(element).css('position', 'relative');
+    $(element).css('marginLeft', 'auto');
+    $(element).css('marginRight', 'auto');
+
+    if (typeof _options.maxWidth != 'undefined') {
+      const _max = _options.maxWidth * 1;
+      $(element).width(
+        Math.min(
+          $(element)
+            .parent()
+            .width(),
+          _max
+        )
+      );
+    } else {
+      $(element).width(
+        $(element)
+          .parent()
+          .width() - 10
+      );
+    }
+
+    $(element).height($(element).width() / 2.23);
+
+    const _scope =
+      typeof _options.data.scope != 'undefined' ? String(_options.data.scope) : 'world';
+    const _data = _options.transformer(_options.data);
+    let _is2d = false;
+    const _pivotCategories = [];
+    let _maxWeight = 0;
+
+    function comparePivotValues(a, b) {
+      if (a.count < b.count) {
+        return 1;
+      }
+      if (a.count > b.count) {
+        return -1;
+      }
+      return 0;
+    }
+
+    $(_data).each((cnt, item) => {
+      if (item.value > _maxWeight) {
+        _maxWeight = item.value;
+      }
+      if (item.obj.is2d) {
+        _is2d = true;
+      }
+      if (item.obj.pivot && item.obj.pivot.length > 0) {
+        item.obj.pivot.forEach(piv => {
+          let _category = null;
+          _pivotCategories.forEach(category => {
+            if (category.value === piv.value) {
+              _category = category;
+              if (piv.count > _category.count) {
+                _category.count = piv.count;
+              }
+            }
+          });
+
+          if (_category == null) {
+            _category = {
+              value: piv.value,
+              count: -1
+            };
+            _pivotCategories.push(_category);
+          }
+        });
+      }
+    });
+
+    _pivotCategories.sort(comparePivotValues);
+
+    const _chunk = _maxWeight / _data.length;
+    const _mapdata = {};
+    const _maphovers = {};
+    const _fills = {};
+    const _legend = [];
+
+    const _noncountries = [];
+
+    if (_options.isScale) {
+      _fills['defaultFill'] = HueColors.WHITE;
+      const _colors = _is2d
+        ? HueColors.d3Scale()
+        : HueColors.scale(HueColors.LIGHT_BLUE, HueColors.DARK_BLUE, _data.length);
+      $(_colors).each((cnt, item) => {
+        _fills['fill_' + cnt] = item;
+      });
+
+      const getHighestCategoryValue = (cnt, item) => {
+        let _cat = '';
+        let _max = -1;
+        if (item.obj.pivot && item.obj.pivot.length > 0) {
+          item.obj.pivot.forEach(piv => {
+            if (piv.count > _max) {
+              _max = piv.count;
+              _cat = piv.value;
+            }
+          });
+        }
+        let _found = cnt;
+        if (_cat !== '') {
+          _pivotCategories.forEach((cat, i) => {
+            if (cat.value === _cat) {
+              _found = i;
+            }
+          });
+        }
+        return {
+          idx: _found,
+          cat: _cat
+        };
+      };
+
+      const addToLegend = category => {
+        let _found = false;
+        _legend.forEach(lg => {
+          if (lg.cat === category.cat) {
+            _found = true;
+          }
+        });
+        if (!_found) {
+          _legend.push(category);
+        }
+      };
+
+      $(_data).each((cnt, item) => {
+        addToLegend(getHighestCategoryValue(cnt, item));
+        let _place = typeof item.label == 'string' ? item.label.toUpperCase() : item.label;
+        if (_place != null) {
+          if (
+            _scope !== 'world' &&
+            _scope !== 'usa' &&
+            _scope !== 'europe' &&
+            _place.indexOf('.') === -1
+          ) {
+            _place = HueGeo.getISOAlpha2(_scope) + '.' + _place;
+          }
+          if ((_scope === 'world' || _scope === 'europe') && _place.length === 2) {
+            _place = HueGeo.getISOAlpha3(_place);
+          }
+          _mapdata[_place] = {
+            fillKey:
+              'fill_' +
+              (_is2d ? getHighestCategoryValue(cnt, item).idx : Math.ceil(item.value / _chunk) - 1),
+            id: _place,
+            cat: item.obj.cat,
+            value: item.obj.values ? item.obj.values : item.obj.value,
+            pivot: _is2d ? item.obj.pivot : [],
+            selected: item.obj.selected,
+            fields: item.obj.fields ? item.obj.fields : null
+          };
+          _maphovers[_place] = item.value;
+        } else {
+          _noncountries.push(item);
+        }
+      });
+    } else {
+      _fills['defaultFill'] = HueColors.LIGHT_BLUE;
+      _fills['selected'] = HueColors.DARK_BLUE;
+      $(_data).each((cnt, item) => {
+        let _place = item.label.toUpperCase();
+        if (_place != null) {
+          if (
+            _scope !== 'world' &&
+            _scope !== 'usa' &&
+            _scope !== 'europe' &&
+            _place.indexOf('.') === -1
+          ) {
+            _place = HueGeo.getISOAlpha2(_scope) + '.' + _place;
+          }
+          if ((_scope === 'world' || _scope === 'europe') && _place.length === 2) {
+            _place = HueGeo.getISOAlpha3(_place);
+          }
+          _mapdata[_place] = {
+            fillKey: 'selected',
+            id: _place,
+            cat: item.obj.cat,
+            value: item.obj.values ? item.obj.values : item.obj.value,
+            pivot: [],
+            selected: item.obj.selected,
+            fields: item.obj.fields ? item.obj.fields : null
+          };
+          _maphovers[_place] = item.value;
+        } else {
+          _noncountries.push(item);
+        }
+      });
+    }
+
+    let _map = null;
+
+    function createDatamap(element, options, fills, mapData, nonCountries, mapHovers) {
+      _map = new Datamap({
+        element: element,
+        fills: fills,
+        scope: _scope,
+        data: mapData,
+        legendData: _legend,
+        onClick: function(data) {
+          if (typeof options.onClick != 'undefined') {
+            huePubSub.publish('charts.state', { updating: true });
+            options.onClick(data);
+          }
+        },
+        done: function() {
+          const _bubbles = [];
+          if (options.enableGeocoding) {
+            $(nonCountries).each((cnt, item) => {
+              HueGeo.getCityCoordinates(item.label, (lat, lng) => {
+                _bubbles.push({
+                  fillKey: 'selected',
+                  label: item.label,
+                  value: item.value,
+                  radius: 4,
+                  latitude: lat,
+                  longitude: lng
+                });
+                _map.bubbles(_bubbles, {
+                  popupTemplate: function(geo, data) {
+                    return (
+                      '<div class="hoverinfo" style="text-align: center"><strong>' +
+                      data.label +
+                      '</strong><br/>' +
+                      item.value +
+                      '</div>'
+                    );
+                  }
+                });
+              });
+            });
+          }
+        },
+        geographyConfig: {
+          hideAntarctica: true,
+          borderWidth: 1,
+          borderColor: HueColors.DARK_BLUE,
+          highlightOnHover: true,
+          highlightFillColor: HueColors.DARK_BLUE,
+          highlightBorderColor: HueColors.BLUE,
+          selectedFillColor: HueColors.DARKER_BLUE,
+          selectedBorderColor: HueColors.DARKER_BLUE,
+          popupTemplate: function(geography, data) {
+            let _hover = '';
+            if (data != null) {
+              _hover = '<br/>';
+              if (data.pivot && data.pivot.length > 0) {
+                data.pivot.sort(comparePivotValues);
+                data.pivot.forEach((piv, cnt) => {
+                  _hover +=
+                    (cnt === 0 ? '<strong>' : '') +
+                    piv.value +
+                    ': ' +
+                    piv.count +
+                    (cnt === 0 ? '</strong>' : '') +
+                    '<br/>';
+                });
+              } else {
+                _hover += mapHovers[data.id];
+              }
+            }
+            return (
+              '<div class="hoverinfo" style="text-align: center"><strong>' +
+              geography.properties.name +
+              '</strong>' +
+              _hover +
+              '</div>'
+            );
+          }
+        }
+      });
+      if (options.onComplete != null) {
+        options.onComplete();
+      }
+      if (_is2d) {
+        _map.legend();
+      }
+    }
+
+    createDatamap(element, _options, _fills, _mapdata, _noncountries, _maphovers);
+
+    const _parentSelector =
+      typeof _options.parentSelector != 'undefined' ? _options.parentSelector : '.card-widget';
+
+    $(element)
+      .parents(_parentSelector)
+      .one('resize', () => {
+        ko.bindingHandlers.mapChart.render(element, valueAccessor);
+      });
+
+    let _resizeTimeout = -1;
+    nv.utils.windowResize(() => {
+      window.clearTimeout(_resizeTimeout);
+      _resizeTimeout = window.setTimeout(() => {
+        ko.bindingHandlers.mapChart.render(element, valueAccessor);
+      }, 200);
+    });
+
+    huePubSub.publish('charts.state');
+  },
+  init: function(element, valueAccessor) {
+    ko.bindingHandlers.mapChart.render(element, valueAccessor);
+  },
+  update: function(element, valueAccessor, allBindingsAccessor) {
+    if (typeof allBindingsAccessor().mapChart.visible != 'undefined') {
+      if (
+        (typeof allBindingsAccessor().mapChart.visible == 'boolean' &&
+          allBindingsAccessor().mapChart.visible) ||
+        (typeof allBindingsAccessor().mapChart.visible == 'function' &&
+          allBindingsAccessor().mapChart.visible())
+      ) {
+        $(element).show();
+        ko.bindingHandlers.mapChart.render(element, valueAccessor);
+      } else {
+        $(element).hide();
+      }
+    } else {
+      ko.bindingHandlers.mapChart.render(element, valueAccessor);
+    }
+  }
+};

+ 229 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.partitionChart.js

@@ -0,0 +1,229 @@
+// 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 HueColors from 'utils/hueColors';
+import huePubSub from 'utils/huePubSub';
+
+ko.bindingHandlers.partitionChart = {
+  render: function(element, valueAccessor) {
+    huePubSub.publish('charts.state');
+    const MIN_HEIGHT_FOR_TOOLTIP = 24;
+
+    const _options = valueAccessor();
+    const _data = _options.transformer(valueAccessor().datum);
+
+    const _w = $(element).width(),
+      _h = 300,
+      _x = d3v3.scale.linear().range([0, _w]),
+      _y = d3v3.scale.linear().range([0, _h]);
+
+    if ($(element).find('svg').length > 0) {
+      $(element)
+        .find('svg')
+        .empty();
+    }
+
+    const _tip = d3v3
+      .tip()
+      .attr('class', 'd3-tip')
+      .html(d => {
+        if (d.depth === 0) {
+          return _options.tooltip || '';
+        } else if (d.depth > 0 && d.depth < 2) {
+          return d.name + ' (' + d.value + ')';
+        } else {
+          return d.parent.name + ' - ' + d.name + ' (' + d.value + ')';
+        }
+      })
+      .offset([-12, 0]);
+
+    const _svg =
+      $(element).find('svg.tip').length > 0
+        ? d3v3.select($(element).find('svg.tip')[0])
+        : d3v3.select($(element)[0]).append('svg');
+    _svg.attr('class', 'tip').style('height', '0px');
+    _svg.call(_tip);
+
+    const _vis =
+      $(element).find('svg').length > 0
+        ? d3v3.select($(element).find('svg')[0])
+        : d3v3.select($(element)[0]).append('svg');
+    _vis
+      .attr('class', 'partitionChart')
+      .style('width', _w + 'px')
+      .style('height', _h + 'px')
+      .attr('width', _w)
+      .attr('height', _h);
+
+    const _partition = d3v3.layout.partition().value(d => {
+      return d.size;
+    });
+
+    const g = _vis
+      .selectAll('g')
+      .data(_partition.nodes(_data))
+      .enter()
+      .append('svg:g')
+      .attr('transform', d => {
+        return 'translate(' + _x(d.y) + ',' + _y(d.x) + ')';
+      })
+      .on('mouseover', function(d, i) {
+        if (
+          element.querySelectorAll('rect')[i].getBBox().height < MIN_HEIGHT_FOR_TOOLTIP ||
+          d.depth === 0
+        ) {
+          _tip.attr('class', 'd3-tip').show(d);
+        }
+
+        if (typeof this.__data__.parent === 'undefined') {
+          return;
+        }
+        d3v3
+          .select(this)
+          .select('rect')
+          .classed('mouseover', true);
+      })
+      .on('mouseout', function(d, i) {
+        if (
+          element.querySelectorAll('rect')[i].getBBox().height < MIN_HEIGHT_FOR_TOOLTIP ||
+          d.depth === 0
+        ) {
+          _tip.attr('class', 'd3-tip').show(d);
+          _tip.hide();
+        }
+        d3v3
+          .select(this)
+          .select('rect')
+          .classed('mouseover', false);
+      });
+
+    if (typeof _options.zoomable == 'undefined' || _options.zoomable) {
+      g.on('click', click).on('dblclick', d => {
+        if (typeof _options.onClick != 'undefined' && d.depth > 0) {
+          huePubSub.publish('charts.state', { updating: true });
+          _options.onClick(d);
+        }
+      });
+    } else {
+      g.on('click', d => {
+        if (typeof _options.onClick != 'undefined' && d.depth > 0) {
+          huePubSub.publish('charts.state', { updating: true });
+          _options.onClick(d);
+        }
+      });
+    }
+
+    let _kx = _w / _data.dx,
+      _ky = _h / 1;
+
+    const _colors = [HueColors.cuiD3Scale('gray')[0]];
+
+    g.append('svg:rect')
+      .attr('width', _data.dy * _kx)
+      .attr('height', d => {
+        return d.dx * _ky;
+      })
+      .attr('class', d => {
+        return d.children ? 'parent' : 'child';
+      })
+      .attr('stroke', () => {
+        return HueColors.cuiD3Scale('gray')[3];
+      })
+      .attr('fill', d => {
+        let _fill = _colors[d.depth] || _colors[_colors.length - 1];
+        if (d.obj && _options.fqs) {
+          $.each(_options.fqs(), (cnt, item) => {
+            $.each(item.filter(), (icnt, filter) => {
+              if (JSON.stringify(filter.value()) === JSON.stringify(d.obj.fq_values)) {
+                _fill = HueColors.cuiD3Scale('gray')[3];
+              }
+            });
+          });
+        }
+        return _fill;
+      });
+
+    g.append('svg:text')
+      .attr('transform', transform)
+      .attr('dy', '.35em')
+      .style('opacity', d => {
+        return d.dx * _ky > 12 ? 1 : 0;
+      })
+      .text(d => {
+        if (d.depth < 2) {
+          return d.name + ' (' + d.value + ')';
+        } else {
+          return d.parent.name + ' - ' + d.name + ' (' + d.value + ')';
+        }
+      });
+
+    d3v3.select(window).on('click', () => {
+      click(_data);
+    });
+
+    function click(d) {
+      _tip.hide();
+      if (!d.children) {
+        return;
+      }
+
+      _kx = (d.y ? _w - 40 : _w) / (1 - d.y);
+      _ky = _h / d.dx;
+      _x.domain([d.y, 1]).range([d.y ? 40 : 0, _w]);
+      _y.domain([d.x, d.x + d.dx]);
+
+      const t = g
+        .transition()
+        .delay(250)
+        .duration(d3v3.event.altKey ? 7500 : 750)
+        .attr('transform', d => {
+          return 'translate(' + _x(d.y) + ',' + _y(d.x) + ')';
+        });
+
+      t.select('rect')
+        .attr('width', d.dy * _kx)
+        .attr('height', d => {
+          return d.dx * _ky;
+        });
+
+      t.select('text')
+        .attr('transform', transform)
+        .style('opacity', d => {
+          return d.dx * _ky > 12 ? 1 : 0;
+        });
+
+      d3v3.event.stopPropagation();
+    }
+
+    function transform(d) {
+      return 'translate(8,' + (d.dx * _ky) / 2 + ')';
+    }
+
+    if (_options.onComplete) {
+      _options.onComplete();
+    }
+  },
+  init: function(element, valueAccessor) {
+    ko.bindingHandlers.partitionChart.render(element, valueAccessor);
+  },
+  update: function(element, valueAccessor) {
+    ko.bindingHandlers.partitionChart.render(element, valueAccessor);
+  }
+};

+ 183 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.pieChart.js

@@ -0,0 +1,183 @@
+// 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 huePubSub from 'utils/huePubSub';
+import hueUtils from 'utils/hueUtils';
+
+ko.bindingHandlers.pieChart = {
+  init: function(element, valueAccessor) {
+    window.setTimeout(() => {
+      const _options = valueAccessor();
+      let _data = _options.transformer(_options.data);
+      $(element).css('marginLeft', 'auto');
+      $(element).css('marginRight', 'auto');
+      if (typeof _options.maxWidth != 'undefined') {
+        const _max = _options.maxWidth * 1;
+        $(element).width(
+          Math.min(
+            $(element)
+              .parent()
+              .width(),
+            _max
+          )
+        );
+      }
+
+      if ($(element).find('svg').length > 0 && _data.length === 0) {
+        $(element)
+          .find('svg')
+          .empty();
+      }
+
+      if (_data.length > 0 && isNaN(_data[0].value)) {
+        _data = [];
+        $(element)
+          .find('svg')
+          .empty();
+      }
+
+      if ($(element).is(':visible')) {
+        nv.addGraph(
+          () => {
+            const _chart = nv.models
+              .growingPieChart()
+              .x(d => {
+                return d.label;
+              })
+              .y(d => {
+                return d.value;
+              })
+              .height($(element).width())
+              .showLabels(true)
+              .showLegend(false)
+              .tooltipContent((key, y) => {
+                return '<h3>' + hueUtils.htmlEncode(key) + '</h3><p>' + y + '</p>';
+              });
+            _chart.noData(_data.message || window.HUE_I18n.chart.noData);
+            const _d3 =
+              $(element).find('svg').length > 0
+                ? d3v3.select($(element).find('svg')[0])
+                : d3v3.select($(element)[0]).append('svg');
+
+            _d3
+              .datum(_data)
+              .transition()
+              .duration(150)
+              .each('end', _options.onComplete != null ? _options.onComplete : void 0)
+              .call(_chart);
+
+            if (_options.fqs) {
+              $.each(_options.fqs(), (cnt, item) => {
+                if (item.id() === _options.data.widget_id && item.field() === _options.field()) {
+                  _chart.selectSlices(
+                    $.map(item.filter(), it => {
+                      return it.value();
+                    })
+                  );
+                }
+              });
+            }
+
+            $(element).data('chart', _chart);
+
+            let _resizeTimeout = -1;
+            nv.utils.windowResize(() => {
+              window.clearTimeout(_resizeTimeout);
+              _resizeTimeout = window.setTimeout(() => {
+                _chart.update();
+              }, 200);
+            });
+
+            $(element).on('forceUpdate', () => {
+              _chart.update();
+            });
+
+            $(element).height($(element).width());
+            const _parentSelector =
+              typeof _options.parentSelector != 'undefined'
+                ? _options.parentSelector
+                : '.card-widget';
+            $(element)
+              .parents(_parentSelector)
+              .on('resize', () => {
+                if (typeof _options.maxWidth != 'undefined') {
+                  const _max = _options.maxWidth * 1;
+                  $(element).width(
+                    Math.min(
+                      $(element)
+                        .parent()
+                        .width(),
+                      _max
+                    )
+                  );
+                }
+                $(element).height($(element).width());
+                _chart.update();
+              });
+
+            return _chart;
+          },
+          () => {
+            const _d3 =
+              $(element).find('svg').length > 0
+                ? d3v3.select($(element).find('svg')[0])
+                : d3v3.select($(element)[0]).append('svg');
+            _d3.selectAll('.nv-slice').on('click', (d) => {
+              if (typeof _options.onClick != 'undefined') {
+                huePubSub.publish('charts.state', { updating: true });
+                _options.onClick(d);
+              }
+            });
+          }
+        );
+      }
+    }, 0);
+  },
+  update: function(element, valueAccessor) {
+    const _options = valueAccessor();
+    const _data = _options.transformer(_options.data);
+    const _chart = $(element).data('chart');
+    if (_chart) {
+      _chart.noData(_data.message || window.HUE_I18n.chart.noData);
+      const _d3 = d3v3.select($(element).find('svg')[0]);
+      _d3
+        .datum(_data)
+        .transition()
+        .duration(150)
+        .each('end', _options.onComplete != null ? _options.onComplete : void 0)
+        .call(_chart);
+
+      if (_options.fqs) {
+        $.each(_options.fqs(), (cnt, item) => {
+          if (item.id() === _options.data.widget_id && item.field() === _options.field()) {
+            _chart.selectSlices(
+              $.map(item.filter(), it => {
+                return it.value();
+              })
+            );
+          }
+        });
+      }
+      huePubSub.publish('charts.state');
+    } else if (_data.length > 0) {
+      ko.bindingHandlers.pieChart.init(element, valueAccessor);
+    }
+  }
+};

+ 90 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.scatterChart.js

@@ -0,0 +1,90 @@
+// 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';
+
+ko.bindingHandlers.scatterChart = {
+  update: function(element, valueAccessor) {
+    const options = valueAccessor();
+    let _datum = options.transformer(options.datum);
+    window.setTimeout(() => {
+      $(element).height(300);
+      if (
+        $(element).find('svg').length > 0 &&
+        (_datum.length === 0 || _datum[0].values.length === 0)
+      ) {
+        $(element)
+          .find('svg')
+          .empty();
+      }
+      if (
+        _datum.length > 0 &&
+        _datum[0].values.length > 0 &&
+        (isNaN(_datum[0].values[0].x) || isNaN(_datum[0].values[0].y))
+      ) {
+        _datum = [];
+        $(element)
+          .find('svg')
+          .empty();
+      }
+
+      if ($(element).is(':visible')) {
+        nv.addGraph(() => {
+          const _chart = nv.models
+            .scatterChart()
+            .transitionDuration(350)
+            .color(d3v3.scale.category10().range())
+            .useVoronoi(false);
+
+          _chart.tooltipContent((key, x, y, obj) => {
+            return '<h3>' + key + '</h3><div class="center">' + obj.point.size + '</div>';
+          });
+
+          _chart.xAxis.tickFormat(d3v3.format('.02f'));
+          _chart.yAxis.tickFormat(d3v3.format('.02f'));
+          _chart.scatter.onlyCircles(true);
+
+          const _d3 =
+            $(element).find('svg').length > 0
+              ? d3v3.select($(element).find('svg')[0])
+              : d3v3.select($(element)[0]).append('svg');
+          _d3
+            .datum(_datum)
+            .transition()
+            .duration(150)
+            .each('end', options.onComplete != null ? options.onComplete : void 0)
+            .call(_chart);
+
+          let _resizeTimeout = -1;
+          nv.utils.windowResize(() => {
+            window.clearTimeout(_resizeTimeout);
+            _resizeTimeout = window.setTimeout(() => {
+              _chart.update();
+            }, 200);
+          });
+
+          $(element).on('forceUpdate', () => {
+            _chart.update();
+          });
+
+          return _chart;
+        });
+      }
+    }, 0);
+  }
+};

+ 91 - 0
desktop/core/src/desktop/js/ko/bindings/charts/ko.timelineChart.js

@@ -0,0 +1,91 @@
+// 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 {
+  barChartBuilder,
+  handleSelection,
+  insertLinebreaks,
+  lineChartBuilder
+} from 'ko/bindings/charts/chartUtils';
+import huePubSub from 'utils/huePubSub';
+
+ko.bindingHandlers.timelineChart = {
+  init: function(element, valueAccessor) {
+    if (valueAccessor().type && valueAccessor().type() === 'line') {
+      window.setTimeout(() => {
+        lineChartBuilder(element, valueAccessor(), true);
+      }, 0);
+      $(element).data('type', 'line');
+    } else {
+      window.setTimeout(() => {
+        barChartBuilder(element, valueAccessor(), true);
+      }, 0);
+      $(element).data('type', 'bar');
+    }
+  },
+  update: function(element, valueAccessor) {
+    const _options = valueAccessor();
+    if (valueAccessor().type && valueAccessor().type() !== $(element).data('type')) {
+      if ($(element).find('svg').length > 0) {
+        $(element)
+          .find('svg')
+          .remove();
+      }
+      if (valueAccessor().type() === 'line') {
+        window.setTimeout(() => {
+          lineChartBuilder(element, valueAccessor(), true);
+        }, 0);
+      } else {
+        window.setTimeout(() => {
+          barChartBuilder(element, valueAccessor(), true);
+        }, 0);
+      }
+      $(element).data('type', valueAccessor().type());
+    }
+    const _datum = _options.transformer(_options.datum, true);
+    const _chart = $(element).data('chart');
+    if (_chart) {
+      window.setTimeout(() => {
+        _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
+        if (_chart.multibar) {
+          _chart.multibar.stacked(
+            typeof _options.stacked != 'undefined' ? _options.stacked : false
+          );
+        }
+        handleSelection(_chart, _options, _datum);
+        const _d3 = d3v3.select($(element).find('svg')[0]);
+        _d3
+          .datum(_datum)
+          .transition()
+          .duration(150)
+          .each('end', () => {
+            if (_options.onComplete != null) {
+              _options.onComplete();
+            }
+          })
+          .call(_chart);
+        _d3.selectAll('g.nv-x.nv-axis g text').each(function(d) {
+          insertLinebreaks(_chart, d, this);
+        });
+        huePubSub.publish('charts.state');
+      }, 0);
+    }
+  }
+};

+ 8 - 0
desktop/core/src/desktop/js/ko/ko.all.js

@@ -24,6 +24,14 @@ import 'knockout.validation';
 import 'ext/ko.editable.custom';
 import 'ext/ko.selectize.custom';
 
+import 'ko/bindings/charts/ko.barChart';
+import 'ko/bindings/charts/ko.lineChart';
+import 'ko/bindings/charts/ko.mapChart';
+import 'ko/bindings/charts/ko.partitionChart';
+import 'ko/bindings/charts/ko.pieChart';
+import 'ko/bindings/charts/ko.scatterChart';
+import 'ko/bindings/charts/ko.timelineChart';
+
 import 'ko/bindings/ko.aceEditor';
 import 'ko/bindings/ko.aceResizer';
 import 'ko/bindings/ko.appAwareTemplateContextMenu';

+ 343 - 0
desktop/core/src/desktop/js/utils/d3Extensions.js

@@ -0,0 +1,343 @@
+// 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 HueColors from 'utils/hueColors';
+import huePubSub from 'utils/huePubSub';
+
+const HUE_CHARTS = {
+  TYPES: {
+    COUNTER: 'counter',
+    LINECHART: 'lines',
+    BARCHART: 'bars',
+    TIMELINECHART: 'timeline',
+    TEXTSELECT: 'textselect',
+    POINTCHART: 'points',
+    PIECHART: 'pie',
+    MAP: 'map',
+    GRADIENTMAP: 'gradientmap',
+    SCATTERCHART: 'scatter'
+  }
+};
+
+window.HUE_CHARTS = HUE_CHARTS;
+
+huePubSub.subscribe('charts.state', state => {
+  const opacity = state && state.updating ? '0.5' : '1';
+  $('.nvd3')
+    .parents('svg')
+    .css('opacity', opacity);
+});
+
+const tipBuilder = () => {
+  let direction = d3_tip_direction;
+  let offset = d3_tip_offset;
+  let html = d3_tip_html;
+  const node = initNode();
+  let svg = null;
+  let point = null;
+  let target = null;
+
+  function tip(vis) {
+    svg = getSVGNode(vis);
+    point = svg.createSVGPoint();
+    document.body.appendChild(node);
+  }
+
+  // Public - show the tooltip on the screen
+  //
+  // Returns a tip
+  tip.show = function() {
+    const args = Array.prototype.slice.call(arguments);
+    if (args[args.length - 1] instanceof SVGElement) {
+      target = args.pop();
+    }
+
+    const content = html.apply(this, args);
+    const poffset = offset.apply(this, args);
+    const dir = direction.apply(this, args);
+    const nodel = d3v3.select(node);
+    let i = 0;
+
+    nodel.html(content).style({ opacity: 1, 'pointer-events': 'all' });
+
+    while (i--) {
+      nodel.classed(directions[i], false);
+    }
+    const coords = direction_callbacks.get(dir).apply(this);
+    nodel.classed(dir, true).style({
+      top: coords.top + poffset[0] + 'px',
+      left: coords.left + poffset[1] + 'px'
+    });
+
+    return tip;
+  };
+
+  // Public - hide the tooltip
+  //
+  // Returns a tip
+  tip.hide = function() {
+    const nodel = d3v3.select(node);
+    nodel.style({ opacity: 0, 'pointer-events': 'none' });
+    return tip;
+  };
+
+  // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
+  //
+  // n - name of the attribute
+  // v - value of the attribute
+  //
+  // Returns tip or attribute value
+  tip.attr = function(n, v) {
+    if (arguments.length < 2 && typeof n === 'string') {
+      return d3v3.select(node).attr(n);
+    } else {
+      const args = Array.prototype.slice.call(arguments);
+      d3v3.selection.prototype.attr.apply(d3v3.select(node), args);
+    }
+
+    return tip;
+  };
+
+  // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
+  //
+  // n - name of the property
+  // v - value of the property
+  //
+  // Returns tip or style property value
+  tip.style = function(n, v) {
+    if (arguments.length < 2 && typeof n === 'string') {
+      return d3v3.select(node).style(n);
+    } else {
+      const args = Array.prototype.slice.call(arguments);
+      d3v3.selection.prototype.style.apply(d3v3.select(node), args);
+    }
+
+    return tip;
+  };
+
+  // Public: Set or get the direction of the tooltip
+  //
+  // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
+  //     sw(southwest), ne(northeast) or se(southeast)
+  //
+  // Returns tip or direction
+  tip.direction = function(v) {
+    if (!arguments.length) {
+      return direction;
+    }
+    direction = v == null ? v : d3v3.functor(v);
+
+    return tip;
+  };
+
+  // Public: Sets or gets the offset of the tip
+  //
+  // v - Array of [x, y] offset
+  //
+  // Returns offset or
+  tip.offset = function(v) {
+    if (!arguments.length) {
+      return offset;
+    }
+    offset = v == null ? v : d3v3.functor(v);
+
+    return tip;
+  };
+
+  // Public: sets or gets the html value of the tooltip
+  //
+  // v - String value of the tip
+  //
+  // Returns html value or tip
+  tip.html = function(v) {
+    if (!arguments.length) {
+      return html;
+    }
+    html = v == null ? v : d3v3.functor(v);
+
+    return tip;
+  };
+
+  function d3_tip_direction() {
+    return 'n';
+  }
+
+  function d3_tip_offset() {
+    return [0, 0];
+  }
+
+  function d3_tip_html() {
+    return ' ';
+  }
+
+  const direction_callbacks = d3v3.map({
+      n: direction_n,
+      s: direction_s,
+      e: direction_e,
+      w: direction_w,
+      nw: direction_nw,
+      ne: direction_ne,
+      sw: direction_sw,
+      se: direction_se
+    }),
+    directions = direction_callbacks.keys();
+
+  function direction_n() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.n.y - node.offsetHeight,
+      left: bbox.n.x - node.offsetWidth / 2
+    };
+  }
+
+  function direction_s() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.s.y,
+      left: bbox.s.x - node.offsetWidth / 2
+    };
+  }
+
+  function direction_e() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.e.y - node.offsetHeight / 2,
+      left: bbox.e.x
+    };
+  }
+
+  function direction_w() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.w.y - node.offsetHeight / 2,
+      left: bbox.w.x - node.offsetWidth
+    };
+  }
+
+  function direction_nw() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.nw.y - node.offsetHeight,
+      left: bbox.nw.x - node.offsetWidth
+    };
+  }
+
+  function direction_ne() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.ne.y - node.offsetHeight,
+      left: bbox.ne.x
+    };
+  }
+
+  function direction_sw() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.sw.y,
+      left: bbox.sw.x - node.offsetWidth
+    };
+  }
+
+  function direction_se() {
+    const bbox = getScreenBBox();
+    return {
+      top: bbox.se.y,
+      left: bbox.e.x
+    };
+  }
+
+  function initNode() {
+    const node = d3v3.select(document.createElement('div'));
+    node.style({
+      position: 'absolute',
+      background: HueColors.cuiD3Scale()[0],
+      padding: '4px',
+      color: HueColors.WHITE,
+      opacity: 0,
+      pointerEvents: 'none',
+      boxSizing: 'border-box'
+    });
+
+    return node.node();
+  }
+
+  function getSVGNode(el) {
+    el = el.node();
+    if (el != null) {
+      if (el.tagName != null && el.tagName.toLowerCase() === 'svg') {
+        return el;
+      }
+
+      return el.ownerSVGElement;
+    }
+  }
+
+  // Private - gets the screen coordinates of a shape
+  //
+  // Given a shape on the screen, will return an SVGPoint for the directions
+  // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
+  // sw(southwest).
+  //
+  //    +-+-+
+  //    |   |
+  //    +   +
+  //    |   |
+  //    +-+-+
+  //
+  // Returns an Object {n, s, e, w, nw, sw, ne, se}
+  function getScreenBBox() {
+    const targetel = target || d3v3.event.target,
+      bbox = {},
+      matrix = targetel.getScreenCTM(),
+      tbbox = targetel.getBBox(),
+      width = tbbox.width,
+      height = tbbox.height,
+      x = tbbox.x,
+      y = tbbox.y,
+      scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
+      scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+
+    point.x = x + scrollLeft;
+    point.y = y + scrollTop;
+    bbox.nw = point.matrixTransform(matrix);
+    point.x += width;
+    bbox.ne = point.matrixTransform(matrix);
+    point.y += height;
+    bbox.se = point.matrixTransform(matrix);
+    point.x -= width;
+    bbox.sw = point.matrixTransform(matrix);
+    point.y -= height / 2;
+    bbox.w = point.matrixTransform(matrix);
+    point.x += width;
+    bbox.e = point.matrixTransform(matrix);
+    point.x -= width / 2;
+    point.y -= height / 2;
+    bbox.n = point.matrixTransform(matrix);
+    point.y += height;
+    bbox.s = point.matrixTransform(matrix);
+
+    return bbox;
+  }
+
+  return tip;
+};
+
+if (typeof d3v3 !== 'undefined') {
+  d3v3.tip = tipBuilder;
+}

File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/ext/js/d3.v3.js


File diff suppressed because it is too large
+ 0 - 1
desktop/core/src/desktop/static/desktop/ext/js/d3.v4.js


File diff suppressed because it is too large
+ 0 - 1
desktop/core/src/desktop/static/desktop/ext/js/d3.v5.js


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

@@ -1,1625 +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 () {
-	var MS = 1,
-  SECOND_MS = 1000 * MS,
-  MINUTE_MS = SECOND_MS * 60,
-  HOUR_MS = MINUTE_MS * 60,
-  DAY_MS = HOUR_MS * 24,
-  WEEK_MS = DAY_MS * 7,
-  MONTH_MS = DAY_MS * 30.5,
-  YEAR_MS = DAY_MS * 365;
-  ko.HUE_CHARTS = {
-    TYPES: {
-      COUNTER: "counter",
-      LINECHART: "lines",
-      BARCHART: "bars",
-      TIMELINECHART: "timeline",
-      TEXTSELECT: "textselect",
-      POINTCHART: "points",
-      PIECHART: "pie",
-      MAP: "map",
-      GRADIENTMAP: "gradientmap",
-      SCATTERCHART: "scatter"
-    }
-  };
-
-  ko.bindingHandlers.pieChart = {
-    init: function (element, valueAccessor) {
-      window.setTimeout(function(){
-        var _options = valueAccessor();
-        var _data = _options.transformer(_options.data);
-        $(element).css("marginLeft", "auto");
-        $(element).css("marginRight", "auto");
-        if (typeof _options.maxWidth != "undefined") {
-          var _max = _options.maxWidth * 1;
-          $(element).width(Math.min($(element).parent().width(), _max));
-        }
-
-        if ($(element).find("svg").length > 0 && _data.length == 0) {
-          $(element).find("svg").empty();
-        }
-
-        if (_data.length > 0 && isNaN(_data[0].value)) {
-          _data = [];
-          $(element).find("svg").empty();
-        }
-
-        if ($(element).is(":visible")) {
-          nv.addGraph(function () {
-            var _chart = nv.models.growingPieChart()
-                .x(function (d) {
-                  return d.label
-                })
-                .y(function (d) {
-                  return d.value
-                })
-                .height($(element).width())
-                .showLabels(true).showLegend(false)
-                .tooltipContent(function (key, y, e, graph) {
-                  return '<h3>' + hueUtils.htmlEncode(key) + '</h3><p>' + y + '</p>'
-                });
-            _chart.noData(_data.message || window.HUE_I18n.chart.noData);
-            var _d3 = ($(element).find("svg").length > 0) ? d3v3.select($(element).find("svg")[0]) : d3v3.select($(element)[0]).append("svg");
-
-            _d3.datum(_data)
-                .transition().duration(150)
-                .each("end", _options.onComplete != null ? _options.onComplete : void(0))
-                .call(_chart);
-
-            if (_options.fqs) {
-              $.each(_options.fqs(), function (cnt, item) {
-                if (item.id() == _options.data.widget_id && item.field() == _options.field()) {
-                  _chart.selectSlices($.map(item.filter(), function (it) {
-                    return it.value();
-                  }));
-                }
-              });
-            }
-
-            $(element).data("chart", _chart);
-
-            var _resizeTimeout = -1;
-            nv.utils.windowResize(function () {
-              window.clearTimeout(_resizeTimeout);
-              _resizeTimeout = window.setTimeout(function () {
-                _chart.update();
-              }, 200);
-            });
-
-            $(element).on("forceUpdate", function () {
-              _chart.update();
-            });
-
-            $(element).height($(element).width());
-            var _parentSelector = typeof _options.parentSelector != "undefined" ? _options.parentSelector : ".card-widget";
-            $(element).parents(_parentSelector).on("resize", function () {
-              if (typeof _options.maxWidth != "undefined") {
-                var _max = _options.maxWidth * 1;
-                $(element).width(Math.min($(element).parent().width(), _max));
-              }
-              $(element).height($(element).width());
-              _chart.update();
-            });
-
-            return _chart;
-          }, function () {
-            var _d3 = ($(element).find("svg").length > 0) ? d3v3.select($(element).find("svg")[0]) : d3v3.select($(element)[0]).append("svg");
-            _d3.selectAll(".nv-slice").on("click",
-                function (d, i) {
-                  if (typeof _options.onClick != "undefined") {
-                    huePubSub.publish('charts.state', { updating: true });
-                    _options.onClick(d);
-                  }
-                });
-          });
-        }
-      }, 0);
-    },
-    update: function (element, valueAccessor) {
-      var _options = valueAccessor();
-      var _data = _options.transformer(_options.data);
-      var _chart = $(element).data("chart");
-      if (_chart) {
-        _chart.noData(_data.message || window.HUE_I18n.chart.noData);
-        var _d3 = d3v3.select($(element).find("svg")[0]);
-        _d3.datum(_data)
-              .transition().duration(150)
-              .each("end", _options.onComplete != null ? _options.onComplete : void(0))
-              .call(_chart);
-
-        if (_options.fqs) {
-            $.each(_options.fqs(), function (cnt, item) {
-              if (item.id() == _options.data.widget_id && item.field() == _options.field()) {
-                _chart.selectSlices($.map(item.filter(), function (it) {
-                  return it.value();
-                }));
-              }
-            });
-          }
-        huePubSub.publish('charts.state');
-      }
-      else if (_data.length > 0) {
-        ko.bindingHandlers.pieChart.init(element, valueAccessor);
-      }
-    }
-  };
-
-  ko.bindingHandlers.barChart = {
-    init: function (element, valueAccessor) {
-      var _options = ko.unwrap(valueAccessor());
-      if (_options.type && _options.type() == "line"){
-        window.setTimeout(function(){
-          lineChartBuilder(element, valueAccessor(), false);
-        }, 0);
-        $(element).data("type", "line");
-      }
-      else {
-        window.setTimeout(function(){
-          barChartBuilder(element, valueAccessor(), false);
-        }, 0);
-        $(element).data("type", "bar");
-      }
-    },
-    update: function (element, valueAccessor) {
-      var _options = ko.unwrap(valueAccessor());
-      if (_options.type && _options.type() != $(element).data("type")){
-        if ($(element).find("svg").length > 0) {
-          $(element).find("svg").remove();
-        }
-        if (_options.type() == "line"){
-          window.setTimeout(function(){
-            lineChartBuilder(element, valueAccessor(), false);
-          }, 0);
-        }
-        else {
-          window.setTimeout(function(){
-            barChartBuilder(element, valueAccessor(), false);
-          }, 0);
-        }
-        $(element).data("type", _options.type());
-      }
-      var _datum = _options.transformer(_options.datum);
-      var _chart = $(element).data("chart");
-      var _isPivot = _options.isPivot != null ? _options.isPivot : false;
-
-      if (_chart) {
-        _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
-        if (_chart.multibar){
-          _chart.multibar.stacked(typeof _options.stacked != "undefined" ? _options.stacked : false);
-        }
-       if (numeric(_datum)) {
-          _chart.xAxis.showMaxMin(false).tickFormat(d3v3.format(",0f"));
-          if (_chart.multibar) {
-            _chart.multibar.barColor(null);
-          }
-        } else {
-          _chart.xAxis.tickFormat(function(s){ return s; });
-          if (_chart.multibar) {
-            if (!_isPivot) {
-              _chart.multibar.barColor(nv.utils.defaultColor());
-            } else {
-              _chart.multibar.barColor(null);
-            }
-          }
-        }
-        window.setTimeout(function () {
-          handleSelection(_chart, _options, _datum);
-          var _d3 = d3v3.select($(element).find("svg")[0]);
-          _d3.datum(_datum)
-            .transition().duration(150)
-            .each("end", function () {
-              if (_options.onComplete != null) {
-                _options.onComplete();
-              }
-            }).call(_chart);
-          huePubSub.publish('charts.state');
-        }, 0);
-      }
-    }
-  };
-  ko.bindingHandlers.timelineChart = {
-    init: function (element, valueAccessor) {
-      if (valueAccessor().type && valueAccessor().type() == "line"){
-        window.setTimeout(function(){
-          lineChartBuilder(element, valueAccessor(), true);
-        }, 0);
-        $(element).data("type", "line");
-      }
-      else {
-        window.setTimeout(function(){
-          barChartBuilder(element, valueAccessor(), true);
-        }, 0);
-        $(element).data("type", "bar");
-      }
-    },
-    update: function (element, valueAccessor) {
-      var _options = valueAccessor();
-      if (valueAccessor().type && valueAccessor().type() != $(element).data("type")){
-        if ($(element).find("svg").length > 0) {
-          $(element).find("svg").remove();
-        }
-        if (valueAccessor().type() == "line"){
-          window.setTimeout(function(){
-            lineChartBuilder(element, valueAccessor(), true);
-          }, 0);
-        }
-        else {
-          window.setTimeout(function(){
-            barChartBuilder(element, valueAccessor(), true);
-          }, 0);
-        }
-        $(element).data("type", valueAccessor().type());
-      }
-      var _datum = _options.transformer(_options.datum, true);
-      var _chart = $(element).data("chart");
-      if (_chart) {
-        window.setTimeout(function () {
-          _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
-          if (_chart.multibar) {
-            _chart.multibar.stacked(typeof _options.stacked != "undefined" ? _options.stacked : false);
-          }
-          handleSelection(_chart, _options, _datum);
-          var _d3 = d3v3.select($(element).find("svg")[0]);
-          _d3.datum(_datum)
-            .transition().duration(150)
-            .each("end", function () {
-              if (_options.onComplete != null) {
-                _options.onComplete();
-              }
-            }).call(_chart);
-          _d3.selectAll("g.nv-x.nv-axis g text").each(function (d) {
-            insertLinebreaks(_chart, d, this);
-          });
-          huePubSub.publish('charts.state');
-        }, 0);
-      }
-    }
-  };
-
-  ko.bindingHandlers.lineChart = {
-    init: function (element, valueAccessor) {
-      window.setTimeout(function(){
-        lineChartBuilder(element, valueAccessor(), false);
-      }, 0);
-    },
-    update: function (element, valueAccessor) {
-      var _options = valueAccessor();
-      var _datum = _options.transformer(_options.datum);
-      var _chart = $(element).data("chart");
-      if (_chart) {
-        window.setTimeout(function () {
-          _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
-          var _d3 = d3v3.select($(element).find("svg")[0]);
-          if (_datum.length > 0 && _datum[0].values.length > 0 && typeof _datum[0].values[0].x.isValid === 'function'){
-            _chart.xAxis.tickFormat(function(d) { return d3v3.time.format("%Y-%m-%d %H:%M:%S")(new Date(d)); })
-            _chart.onChartUpdate(function () {
-              _d3.selectAll("g.nv-x.nv-axis g text").each(function (d){
-                insertLinebreaks(_chart, d, this);
-              });
-            });
-          }
-          _d3.datum(_datum)
-            .transition().duration(150)
-            .each("end", function () {
-              if (_options.onComplete != null) {
-                _options.onComplete();
-              }
-            }).call(_chart);
-          huePubSub.publish('charts.state');
-        }, 0);
-      }
-      else if (_datum.length > 0) {
-        ko.bindingHandlers.lineChart.init(element, valueAccessor);
-      }
-    }
-  };
-
-  ko.bindingHandlers.mapChart = {
-    render: function (element, valueAccessor) {
-
-      var _options = valueAccessor();
-
-      $(element).empty();
-
-      $(element).css("position", "relative");
-      $(element).css("marginLeft", "auto");
-      $(element).css("marginRight", "auto");
-
-      if (typeof _options.maxWidth != "undefined") {
-        var _max = _options.maxWidth * 1;
-        $(element).width(Math.min($(element).parent().width(), _max));
-      }
-      else {
-        $(element).width($(element).parent().width() - 10);
-      }
-
-      $(element).height($(element).width() / 2.23);
-
-      var _scope = typeof _options.data.scope != "undefined" ? String(_options.data.scope) : "world";
-      var _data = _options.transformer(_options.data);
-      var _is2d = false;
-      var _pivotCategories = [];
-      var _maxWeight = 0;
-
-      function comparePivotValues(a, b) {
-        if (a.count < b.count)
-          return 1;
-        if (a.count > b.count)
-          return -1;
-        return 0;
-      }
-
-      $(_data).each(function (cnt, item) {
-        if (item.value > _maxWeight) _maxWeight = item.value;
-        if (item.obj.is2d) _is2d = true;
-        if (item.obj.pivot && item.obj.pivot.length > 0) {
-          item.obj.pivot.forEach(function (piv) {
-
-            var _category = null;
-            _pivotCategories.forEach(function (category) {
-              if (category.value == piv.value) {
-                _category = category;
-                if (piv.count > _category.count) {
-                  _category.count = piv.count;
-                }
-              }
-            });
-
-            if (_category == null) {
-              _category = {
-                value: piv.value,
-                count: -1
-              };
-              _pivotCategories.push(_category);
-            }
-
-          });
-        }
-      });
-
-      _pivotCategories.sort(comparePivotValues);
-
-      var _chunk = _maxWeight / _data.length;
-      var _mapdata = {};
-      var _maphovers = {};
-      var _fills = {};
-      var _legend = [];
-
-      var _noncountries = [];
-
-
-      if (_options.isScale) {
-        _fills["defaultFill"] = HueColors.WHITE;
-        var _colors = _is2d ? HueColors.d3Scale() : HueColors.scale(HueColors.LIGHT_BLUE, HueColors.DARK_BLUE, _data.length);
-        $(_colors).each(function (cnt, item) {
-          _fills["fill_" + cnt] = item;
-        });
-
-        function getHighestCategoryValue(cnt, item) {
-          var _cat = "";
-          var _max = -1;
-          if (item.obj.pivot && item.obj.pivot.length > 0) {
-            item.obj.pivot.forEach(function (piv) {
-              if (piv.count > _max) {
-                _max = piv.count;
-                _cat = piv.value;
-              }
-            });
-          }
-          var _found = cnt;
-          if (_cat != "") {
-            _pivotCategories.forEach(function (cat, i) {
-              if (cat.value == _cat) {
-                _found = i;
-              }
-            });
-          }
-          return {
-            idx: _found,
-            cat: _cat
-          };
-        }
-
-        function addToLegend(category) {
-          var _found = false;
-          _legend.forEach(function (lg) {
-            if (lg.cat == category.cat) {
-              _found = true;
-            }
-          });
-          if (!_found) {
-            _legend.push(category);
-          }
-        }
-
-        $(_data).each(function (cnt, item) {
-          addToLegend(getHighestCategoryValue(cnt, item));
-          var _place = typeof item.label == "string" ? item.label.toUpperCase() : item.label;
-          if (_place != null) {
-            if (_scope != "world" && _scope != "usa" && _scope != "europe" && _place.indexOf(".") == -1) {
-              _place = HueGeo.getISOAlpha2(_scope) + "." + _place;
-            }
-            if ((_scope == "world" || _scope == "europe") && _place.length == 2) {
-              _place = HueGeo.getISOAlpha3(_place);
-            }
-            _mapdata[_place] = {
-              fillKey: "fill_" + (_is2d ? getHighestCategoryValue(cnt, item).idx : (Math.ceil(item.value / _chunk) - 1)),
-              id: _place,
-              cat: item.obj.cat,
-              value: item.obj.values ? item.obj.values : item.obj.value,
-              pivot: _is2d ? item.obj.pivot : [],
-              selected: item.obj.selected,
-              fields: item.obj.fields ? item.obj.fields : null
-            };
-            _maphovers[_place] = item.value;
-          }
-          else {
-            _noncountries.push(item);
-          }
-        });
-      }
-      else {
-        _fills["defaultFill"] = HueColors.LIGHT_BLUE;
-        _fills["selected"] = HueColors.DARK_BLUE;
-        $(_data).each(function (cnt, item) {
-          var _place = item.label.toUpperCase();
-          if (_place != null) {
-            if (_scope != "world" && _scope != "usa" && _scope != "europe" && _place.indexOf(".") == -1) {
-              _place = HueGeo.getISOAlpha2(_scope) + "." + _place;
-            }
-            if ((_scope == "world" || _scope == "europe") && _place.length == 2) {
-              _place = HueGeo.getISOAlpha3(_place);
-            }
-            _mapdata[_place] = {
-              fillKey: "selected",
-              id: _place,
-              cat: item.obj.cat,
-              value: item.obj.values ? item.obj.values : item.obj.value,
-              pivot: [],
-              selected: item.obj.selected,
-              fields: item.obj.fields ? item.obj.fields : null
-            };
-            _maphovers[_place] = item.value;
-          }
-          else {
-            _noncountries.push(item);
-          }
-        });
-      }
-
-      var _map = null;
-
-      function createDatamap(element, options, fills, mapData, nonCountries, mapHovers) {
-        _map = new Datamap({
-          element: element,
-          fills: fills,
-          scope: _scope,
-          data: mapData,
-          legendData: _legend,
-          onClick: function (data) {
-            if (typeof options.onClick != "undefined") {
-              huePubSub.publish('charts.state', { updating: true });
-              options.onClick(data);
-            }
-          },
-          done: function (datamap) {
-            var _bubbles = [];
-            if (options.enableGeocoding) {
-              $(nonCountries).each(function (cnt, item) {
-                HueGeo.getCityCoordinates(item.label, function (lat, lng) {
-                  _bubbles.push({
-                    fillKey: "selected",
-                    label: item.label,
-                    value: item.value,
-                    radius: 4,
-                    latitude: lat,
-                    longitude: lng
-                  });
-                  _map.bubbles(_bubbles, {
-                    popupTemplate: function (geo, data) {
-                      return '<div class="hoverinfo" style="text-align: center"><strong>' + data.label + '</strong><br/>' + item.value + '</div>'
-                    }
-                  });
-                });
-              });
-            }
-          },
-          geographyConfig: {
-            hideAntarctica: true,
-            borderWidth: 1,
-            borderColor: HueColors.DARK_BLUE,
-            highlightOnHover: true,
-            highlightFillColor: HueColors.DARK_BLUE,
-            highlightBorderColor: HueColors.BLUE,
-            selectedFillColor: HueColors.DARKER_BLUE,
-            selectedBorderColor: HueColors.DARKER_BLUE,
-            popupTemplate: function (geography, data) {
-              var _hover = '';
-              if (data != null) {
-                _hover = '<br/>';
-                if (data.pivot && data.pivot.length > 0) {
-                  data.pivot.sort(comparePivotValues);
-                  data.pivot.forEach(function (piv, cnt) {
-                    _hover += (cnt == 0 ? "<strong>" : "") + piv.value + ": " + piv.count + (cnt == 0 ? "</strong>" : "") + "<br/>";
-                  });
-                }
-                else {
-                  _hover += mapHovers[data.id];
-                }
-              }
-              return '<div class="hoverinfo" style="text-align: center"><strong>' + geography.properties.name + '</strong>' + _hover + '</div>'
-            }
-          }
-        });
-        if (options.onComplete != null) {
-          options.onComplete();
-        }
-        if (_is2d) {
-          _map.legend();
-        }
-      }
-
-      createDatamap(element, _options, _fills, _mapdata, _noncountries, _maphovers)
-
-      var _parentSelector = typeof _options.parentSelector != "undefined" ? _options.parentSelector : ".card-widget";
-
-      $(element).parents(_parentSelector).one("resize", function () {
-        ko.bindingHandlers.mapChart.render(element, valueAccessor);
-      });
-
-      var _resizeTimeout = -1;
-      nv.utils.windowResize(function () {
-        window.clearTimeout(_resizeTimeout);
-        _resizeTimeout = window.setTimeout(function () {
-          ko.bindingHandlers.mapChart.render(element, valueAccessor);
-        }, 200);
-      });
-
-      huePubSub.publish('charts.state');
-    },
-    init: function (element, valueAccessor) {
-      ko.bindingHandlers.mapChart.render(element, valueAccessor);
-    },
-    update: function (element, valueAccessor, allBindingsAccessor) {
-      if (typeof allBindingsAccessor().mapChart.visible != "undefined") {
-        if ((typeof allBindingsAccessor().mapChart.visible == "boolean" && allBindingsAccessor().mapChart.visible) || (typeof allBindingsAccessor().mapChart.visible == "function" && allBindingsAccessor().mapChart.visible())) {
-          $(element).show();
-          ko.bindingHandlers.mapChart.render(element, valueAccessor);
-        }
-        else {
-          $(element).hide();
-        }
-      }
-      else {
-        ko.bindingHandlers.mapChart.render(element, valueAccessor);
-      }
-
-    }
-  };
-
-  ko.bindingHandlers.scatterChart = {
-    update: function (element, valueAccessor) {
-      var options = valueAccessor();
-      var _datum = options.transformer(options.datum);
-      window.setTimeout(function () {
-        $(element).height(300);
-        if ($(element).find("svg").length > 0 && (_datum.length == 0 || _datum[0].values.length == 0)) {
-          $(element).find("svg").empty();
-        }
-        if (_datum.length > 0 && _datum[0].values.length > 0 && (isNaN(_datum[0].values[0].x) || isNaN(_datum[0].values[0].y))) {
-          _datum = [];
-          $(element).find("svg").empty();
-        }
-
-        if ($(element).is(":visible")) {
-          nv.addGraph(function () {
-            var _chart = nv.models.scatterChart()
-                .transitionDuration(350)
-                .color(d3v3.scale.category10().range())
-                .useVoronoi(false);
-
-            _chart.tooltipContent(function (key, x, y, obj) {
-              return '<h3>' + key + '</h3><div class="center">' + obj.point.size + '</div>';
-            });
-
-            _chart.xAxis.tickFormat(d3v3.format('.02f'));
-            _chart.yAxis.tickFormat(d3v3.format('.02f'));
-            _chart.scatter.onlyCircles(true);
-
-            var _d3 = ($(element).find("svg").length > 0) ? d3v3.select($(element).find("svg")[0]) : d3v3.select($(element)[0]).append("svg");
-            _d3.datum(_datum)
-                .transition().duration(150)
-                .each("end", options.onComplete != null ? options.onComplete : void(0))
-                .call(_chart);
-
-            var _resizeTimeout = -1;
-            nv.utils.windowResize(function () {
-              window.clearTimeout(_resizeTimeout);
-              _resizeTimeout = window.setTimeout(function () {
-                _chart.update();
-              }, 200);
-            });
-
-            $(element).on("forceUpdate", function () {
-              _chart.update();
-            });
-
-            return _chart;
-          });
-        }
-      }, 0);
-    }
-  };
-
-  var insertLinebreaks = function (_chart, d, ref) {
-    var _el = d3v3.select(ref);
-    var _mom = moment(d);
-    if (_mom != null && _mom.isValid()) {
-      var _words = _el.text().split(" ");
-      _el.text("");
-      for (var i = 0; i < _words.length; i++) {
-        var tspan = _el.append("tspan").text(_words[i]);
-        if (i > 0) {
-          tspan.attr("x", 0).attr("dy", "15");
-        }
-      }
-    }
-  };
-  function multi(xAxis, _chart) {
-    var previous = new Date(9999,11,31);
-    var minDiff = 5.1;
-    return d3v3.time.format.utc.multi([
-      ["%H:%M:%S %Y-%m-%d", function(d) {
-        var domain = xAxis.domain();
-        var isFirst = (previous > d || d == domain[0]) && moment(d).utc().seconds();
-        var result = isFirst;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%H:%M %Y-%m-%d", function(d) {
-        var domain = xAxis.domain();
-        var isFirst = (previous > d || d == domain[0]);
-        var result = isFirst;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%S %H:%M", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().minutes() !== moment(d).utc().minutes() && previousDiff < MINUTE_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%S", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().seconds() !== moment(d).utc().seconds() && previousDiff < MINUTE_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%H:%M:%S %Y-%m-%d", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().date() !== moment(d).utc().date() && previousDiff < WEEK_MS && moment(d).utc().seconds();
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%H:%M %Y-%m-%d", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().date() !== moment(d).utc().date() && previousDiff < WEEK_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%H:%M:%S", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = (moment(previous).utc().hours() !== moment(d).utc().hours() || moment(previous).utc().minutes() !== moment(d).utc().minutes()) && previousDiff < WEEK_MS && moment(d).utc().seconds();
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%H:%M", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = (moment(previous).utc().hours() !== moment(d).utc().hours() || moment(previous).utc().minutes() !== moment(d).utc().minutes()) && previousDiff < WEEK_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%d %Y-%m", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().months() !== moment(d).utc().months() && previousDiff < MONTH_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%d", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().date() !== moment(d).utc().date() && previousDiff < MONTH_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%m %Y", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().years() !== moment(d).utc().years() && previousDiff < YEAR_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%m", function(d) {
-        var previousDiff = Math.abs(d - previous);
-        var result = moment(previous).utc().months() !== moment(d).utc().months() && previousDiff < YEAR_MS;
-        if (result) {
-          previous = d;
-        }
-        return result;
-      }],
-      ["%Y", function(d) {
-        previous = d;
-        return true;
-      }]
-    ]);
-  }
-
-  function lineChartBuilder(element, options, isTimeline) {
-    var _datum = options.transformer(options.datum);
-    $(element).height(300);
-    if ($(element).find("svg").length > 0 && (_datum.length == 0 || _datum[0].values.length == 0)) {
-      $(element).find("svg").empty();
-    }
-    if (_datum.length > 0 && _datum[0].values.length > 0 && (isNaN(_datum[0].values[0].x) || isNaN(_datum[0].values[0].y))) {
-      _datum = [];
-      $(element).find("svg").empty();
-    }
-
-    if ($(element).is(":visible")) {
-      nv.addGraph(function () {
-        var _chart = nv.models.lineWithBrushChart();
-        _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
-        $(element).data("chart", _chart);
-        _chart.transitionDuration(0);
-        _chart.convert = function (d) {
-          return isTimeline ? new Date(moment(values1[0].obj.from).valueOf()) : parseFloat(d);
-        };
-        if (options.showControls != null) {
-          _chart.showControls(false);
-        }
-        _chart.onSelectRange(function (from, to) {
-          huePubSub.publish('charts.state', { updating: true });
-          options.onSelectRange($.isNumeric(from) && isTimeline ? new Date(moment(from).valueOf()) : parseInt(from), $.isNumeric(to) && isTimeline ? new Date(moment(to).valueOf()) : parseInt(to)); // FIXME when using pdouble we should not parseInt.
-        });
-        if (options.selectedSerie) {
-          _chart.onLegendChange(function (state) {
-            var selectedSerie = options.selectedSerie();
-            var _datum = d3v3.select($(element).find("svg")[0]).datum();
-            for (var i = 0; i < state.disabled.length; i++) {
-              selectedSerie[_datum[i].key] = !state.disabled[i];
-            }
-            options.selectedSerie(selectedSerie);
-          });
-        }
-        _chart.xAxis.showMaxMin(false);
-        if (isTimeline){
-          _chart.xScale(d3v3.time.scale.utc());
-          _chart.tooltipContent(function(values){
-            return values.map(function (value) {
-              value = JSON.parse(JSON.stringify(value));
-              value.x = moment(value.x).utc().format("YYYY-MM-DD HH:mm:ss");
-              value.y = _chart.yAxis.tickFormat()(value.y);
-              return value;
-            });
-          });
-          _chart.xAxis.tickFormat(multi(_chart.xAxis, _chart));
-          _chart.onChartUpdate(function () {
-            _d3.selectAll("g.nv-x.nv-axis g text").each(function (d){
-              insertLinebreaks(_chart, d, this);
-            });
-          });
-        }
-
-        _chart.yAxis.tickFormat(d3v3.format("s"));
-        handleSelection(_chart, options, _datum);
-        var _d3 = ($(element).find("svg").length > 0) ? d3v3.select($(element).find("svg")[0]) : d3v3.select($(element)[0]).insert("svg", ":first-child");
-        if ($(element).find("svg").length < 2) {
-          addLegend(element);
-        }
-        _d3.datum(_datum)
-            .transition().duration(150)
-            .each("end", function () {
-              if (options.onComplete != null) {
-                options.onComplete();
-              }
-              if (isTimeline) {
-                _d3.selectAll("g.nv-x.nv-axis g text").each(function (d){
-                  insertLinebreaks(_chart, d, this);
-                });
-              }
-            }).call(_chart);
-
-        var _resizeTimeout = -1;
-        nv.utils.windowResize(function () {
-          window.clearTimeout(_resizeTimeout);
-          _resizeTimeout = window.setTimeout(function () {
-            _chart.update();
-          }, 200);
-        });
-
-        $(element).on("forceUpdate", function () {
-          _chart.update();
-        });
-        _chart.lines.dispatch.on('elementClick', function(d){
-          if (typeof options.onClick != "undefined") {
-            huePubSub.publish('charts.state', { updating: true });
-            options.onClick(d.point);
-          }
-        });
-
-        return _chart;
-      });
-    }
-  }
-
-  function addLegend(element) {
-    var $el = d3v3.select($(element)[0]);
-    var $div = $el.select('div');
-    if (!$div.size()) {
-      $el.append("div")
-        .style("position", "absolute")
-        .style("overflow", "auto")
-        .style("top", "20px")
-        .style("right", "0px")
-        .style("width", "175px")
-        .style("height", "calc(100% - 20px)")
-      .append("svg");
-    } else {
-      $div.append("svg");
-    }
-  }
-  function numeric(_datum) {
-    for (var j = 0; j < _datum.length; j++) {
-      for (var i = 0; i < _datum[j].values.length; i++) {
-        if (isNaN(_datum[j].values[i].x * 1)) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-  function handleSelection(_chart, _options, _datum) {
-    var i, j;
-    var serieEnabled = {};
-    if (_options.selectedSerie) {
-      var selectedSerie = _options.selectedSerie();
-      var enabledCount = 0;
-      for (i = 0; i < _datum.length; i++) {
-        if (!selectedSerie[_datum[i].key]) {
-          _datum[i].disabled = true;
-        } else {
-          enabledCount++;
-        }
-      }
-      if (enabledCount === 0) {
-        // Get the 5 series with the most non zero elements on x axis & total value.
-        var stats = {};
-        for (i = 0; i < _datum.length; i++) {
-          if (!stats[_datum[i].key]) {
-            stats[_datum[i].key] = {count: 0, total: 0};
-          }
-          for (j = 0; j < _datum[i].values.length; j++) {
-            stats[_datum[i].key].count += Math.min(_datum[i].values[j].y, 1);
-            stats[_datum[i].key].total += _datum[i].values[j].y;
-          }
-        }
-        var aStats = Object.keys(stats).map(function(key) {
-          return {key: key, stat: stats[key]};
-        });
-        aStats.sort(function (a, b) {
-          return a.stat.count - b.stat.count || a.stat.total - b.stat.total;
-        });
-        for (i = aStats.length - 1; i >= Math.max(aStats.length - 5, 0); i--) {
-          _datum[i].disabled = false;
-          selectedSerie[_datum[i].key] = true;
-        }
-      }
-    }
-    var _isPivot = _options.isPivot != null ? _options.isPivot : false;
-    var _hideSelection = typeof _options.hideSelection !== 'undefined' ? typeof _options.hideSelection === 'function' ? _options.hideSelection() : _options.hideSelection : false;
-    var _enableSelection = typeof _options.enableSelection !== 'undefined' ? typeof _options.enableSelection === 'function' ? _options.enableSelection() : _options.enableSelection : true;
-    _enableSelection = _enableSelection && numeric(_datum);
-    var _hideStacked = _options.hideStacked !== null ? typeof _options.hideStacked === 'function' ? _options.hideStacked() : _options.hideStacked : false;
-    var _displayValuesInLegend = _options.displayValuesInLegend !== null ? typeof _options.displayValuesInLegend === 'function' ? _options.displayValuesInLegend() : _options.displayValuesInLegend : false;
-    var fHideSelection = _isPivot || _hideSelection ? _chart.hideSelection : _chart.showSelection;
-    if (fHideSelection) {
-      fHideSelection.call(_chart);
-    }
-    var fEnableSelection = _enableSelection ? _chart.enableSelection : _chart.disableSelection;
-    if (fEnableSelection) {
-      fEnableSelection.call(_chart);
-    }
-    var fHideStacked = _hideStacked ? _chart.hideStacked : _chart.showStacked;
-    if (fHideStacked) {
-      fHideStacked.call(_chart);
-    }
-    var fDisplayValuesInLegend = _displayValuesInLegend ? _chart.hideStacked : _chart.showStacked;
-    if (_chart.displayValuesInLegend) {
-      _chart.displayValuesInLegend(_displayValuesInLegend);
-    }
-    if (_chart.selectBars) {
-      var _field = (typeof _options.field == "function") ? _options.field() : _options.field;
-      var bHasSelection = false;
-      $.each(_options.fqs ? _options.fqs() : [], function (cnt, item) {
-        if (item.id() == _options.datum.widget_id) {
-          if (item.field() == _field) {
-            if (item.properties && typeof item.properties === 'function') {
-              bHasSelection = true;
-              _chart.selectBars({
-                singleValues: $.map(item.filter(), function (it) {
-                  return it.value();
-                }),
-                rangeValues: $.map(item.properties(), function (it) {
-                  return {from: it.from(), to: it.to()};
-                })
-              });
-            }
-            else {
-              bHasSelection = true;
-              _chart.selectBars($.map(item.filter(), function (it) {
-                return it.value();
-              }));
-            }
-          }
-          if (Array.isArray(item.field())) {
-            bHasSelection = true;
-            _chart.selectBars({
-              field: item.field(),
-              selected: $.map(item.filter(), function (it) {
-                return {values: it.value()};
-              })
-            });
-          }
-        }
-      });
-      if (!bHasSelection) {
-        _chart.selectBars({field: '', selected:[]});
-      }
-    }
-  }
-
-  function barChartBuilder(element, options, isTimeline) {
-    var _datum = options.transformer(options.datum, isTimeline);
-    $(element).height(300);
-
-    var _isPivot = options.isPivot != null ? options.isPivot : false;
-    var _hideSelection = typeof options.hideSelection !== 'undefined' ? typeof options.hideSelection === 'function' ? options.hideSelection() : options.hideSelection : false;
-
-    if ($(element).find("svg").length > 0 && (_datum.length == 0 || _datum[0].values.length == 0)) {
-      $(element).find("svg").remove();
-    }
-
-    if (_datum.length > 0 && _datum[0].values.length > 0 && isNaN(_datum[0].values[0].y)) {
-      _datum = [];
-      $(element).find("svg").remove();
-    }
-
-    nv.addGraph(function () {
-      var _chart;
-      if ($(element).find("svg").length > 0 && $(element).find(".nv-discreteBarWithAxes").length > 0) {
-        $(element).find("svg").empty();
-      }
-      _chart = nv.models.multiBarWithBrushChart();
-      _chart.noData(_datum.message || window.HUE_I18n.chart.noData);
-      if (_datum.length > 0) $(element).data('chart_type', 'multibar_brush');
-      _chart.onSelectRange(function (from, to) {
-        huePubSub.publish('charts.state', { updating: true });
-        options.onSelectRange(from, to);
-      });
-      _chart.multibar.dispatch.on('elementClick', function(d){
-        if (typeof options.onClick != "undefined") {
-          huePubSub.publish('charts.state', { updating: true });
-          options.onClick(d.point);
-        }
-      });
-      _chart.onStateChange(options.onStateChange);
-      if (options.selectedSerie) {
-        _chart.onLegendChange(function (state) {
-          var selectedSerie = options.selectedSerie();
-          var _datum = d3v3.select($(element).find("svg")[0]).datum();
-          for (var i = 0; i < state.disabled.length; i++) {
-            selectedSerie[_datum[i].key] = !state.disabled[i];
-          }
-          options.selectedSerie(selectedSerie);
-        });
-      }
-      _chart.multibar.hideable(true);
-      _chart.multibar.stacked(typeof options.stacked != "undefined" ? options.stacked : false);
-      if (isTimeline) {
-        _chart.convert = function (d) {
-          return isTimeline ? new Date(moment(values1[0].obj.from).valueOf()) : parseFloat(d);
-        };
-        _chart.staggerLabels(false);
-        _chart.tooltipContent(function(values){
-          return values.map(function (value) {
-            value = JSON.parse(JSON.stringify(value));
-            value.x = moment(value.x).utc().format("YYYY-MM-DD HH:mm:ss");
-            value.y = _chart.yAxis.tickFormat()(value.y);
-            return value;
-          });
-        });
-        _chart.xAxis.tickFormat(multi(_chart.xAxis));
-        _chart.multibar.stacked(typeof options.stacked != "undefined" ? options.stacked : false);
-        _chart.onChartUpdate(function () {
-          _d3.selectAll("g.nv-x.nv-axis g text").each(function (d) {
-            insertLinebreaks(_chart, d, this);
-          });
-        });
-      }
-      else {
-        if (numeric(_datum)) {
-          _chart.xAxis.showMaxMin(false).tickFormat(d3v3.format(",0f"));
-          _chart.staggerLabels(false);
-        } else if (!_isPivot) {
-          _chart.multibar.barColor(nv.utils.defaultColor());
-          _chart.staggerLabels(true);
-        }
-      }
-      if ($(element).width() < 300 && typeof _chart.showLegend != "undefined") {
-        _chart.showLegend(false);
-      }
-      _chart.transitionDuration(0);
-
-      _chart.yAxis.tickFormat(d3v3.format("s"));
-
-      $(element).data("chart", _chart);
-      handleSelection(_chart, options, _datum);
-      var _d3 = ($(element).find("svg").length > 0) ? d3v3.select($(element).find("svg")[0]) : d3v3.select($(element)[0]).insert("svg",":first-child");
-      if ($(element).find("svg").length < 2) {
-        addLegend(element);
-      }
-      _d3.datum(_datum)
-        .transition().duration(150)
-        .each("end", function () {
-          if (options.onComplete != null) {
-            options.onComplete();
-          }
-          if (isTimeline) {
-            _d3.selectAll("g.nv-x.nv-axis g text").each(function (d) {
-              insertLinebreaks(_chart, d, this);
-            });
-          }
-          if (options.slot && _chart.recommendedTicks) {
-            options.slot(_chart.recommendedTicks());
-          }
-        }).call(_chart);
-
-
-      if (!options.skipWindowResize) {
-        var _resizeTimeout = -1;
-        nv.utils.windowResize(function () {
-          window.clearTimeout(_resizeTimeout);
-          _resizeTimeout = window.setTimeout(function () {
-            _chart.update();
-          }, 200);
-        });
-      }
-
-      $(element).on("forceUpdate", function () {
-        _chart.update();
-      });
-
-      return _chart;
-    });
-  }
-
-  ko.bindingHandlers.partitionChart = {
-    render: function (element, valueAccessor) {
-      huePubSub.publish('charts.state');
-      var MIN_HEIGHT_FOR_TOOLTIP = 24;
-
-      var _options = valueAccessor();
-      var _data = _options.transformer(valueAccessor().datum);
-
-      var _w = $(element).width(),
-          _h = 300,
-          _x = d3v3.scale.linear().range([0, _w]),
-          _y = d3v3.scale.linear().range([0, _h]);
-
-      if ($(element).find("svg").length > 0) {
-        $(element).find("svg").empty();
-      }
-
-      var _tip = d3v3.tip()
-          .attr("class", "d3-tip")
-          .html(function (d) {
-            if (d.depth == 0) {
-              return _options.tooltip || "";
-            }
-            else if (d.depth > 0 && d.depth < 2) {
-              return d.name + " (" + d.value + ")";
-            }
-            else {
-              return d.parent.name + " - " + d.name + " (" + d.value + ")";
-            }
-          })
-          .offset([-12, 0])
-
-
-      var _svg = ($(element).find("svg.tip").length > 0) ? d3v3.select($(element).find("svg.tip")[0]) : d3v3.select($(element)[0]).append("svg");
-      _svg.attr("class", "tip")
-          .style("height", "0px")
-      _svg.call(_tip);
-
-
-      var _vis = ($(element).find("svg").length > 0) ? d3v3.select($(element).find("svg")[0]) : d3v3.select($(element)[0]).append("svg");
-      _vis.attr("class", "partitionChart")
-          .style("width", _w + "px")
-          .style("height", _h + "px")
-          .attr("width", _w)
-          .attr("height", _h);
-
-      var _partition = d3v3.layout.partition()
-          .value(function (d) {
-            return d.size;
-          });
-
-      var g = _vis.selectAll("g")
-          .data(_partition.nodes(_data))
-          .enter().append("svg:g")
-          .attr("transform", function (d) {
-            return "translate(" + _x(d.y) + "," + _y(d.x) + ")";
-          })
-          .on("mouseover", function (d, i) {
-            if (element.querySelectorAll("rect")[i].getBBox().height < MIN_HEIGHT_FOR_TOOLTIP || d.depth == 0) {
-              _tip.attr("class", "d3-tip").show(d);
-            }
-
-            if (this.__data__.parent == undefined) return;
-            d3v3.select(this).select("rect").classed("mouseover", true)
-          })
-          .on("mouseout", function (d, i) {
-            if (element.querySelectorAll("rect")[i].getBBox().height < MIN_HEIGHT_FOR_TOOLTIP || d.depth == 0) {
-              _tip.attr("class", "d3-tip").show(d);
-              _tip.hide();
-            }
-            d3v3.select(this).select("rect").classed("mouseover", false)
-          });
-
-      if (typeof _options.zoomable == "undefined" || _options.zoomable) {
-        g.on("click", click)
-          .on("dblclick", function (d, i) {
-            if (typeof _options.onClick != "undefined" && d.depth > 0) {
-              huePubSub.publish('charts.state', { updating: true });
-              _options.onClick(d);
-            }
-          });
-      }
-      else {
-        g.on("click", function (d, i) {
-          if (typeof _options.onClick != "undefined" && d.depth > 0) {
-            huePubSub.publish('charts.state', { updating: true });
-            _options.onClick(d);
-          }
-        });
-      }
-
-      var _kx = _w / _data.dx,
-          _ky = _h / 1;
-
-      var _colors = [HueColors.cuiD3Scale('gray')[0]];
-
-      g.append("svg:rect")
-          .attr("width", _data.dy * _kx)
-          .attr("height", function (d) {
-            return d.dx * _ky;
-          })
-          .attr("class", function (d) {
-            return d.children ? "parent" : "child";
-          })
-          .attr("stroke", function (d) {
-            return HueColors.cuiD3Scale('gray')[3];
-          })
-          .attr("fill", function (d, i) {
-            var _fill = _colors[d.depth] || _colors[_colors.length - 1];
-            if (d.obj && _options.fqs) {
-              $.each(_options.fqs(), function (cnt, item) {
-                $.each(item.filter(), function (icnt, filter) {
-                  if (JSON.stringify(filter.value()) == JSON.stringify(d.obj.fq_values)) {
-                    _fill = HueColors.cuiD3Scale('gray')[3];
-                  }
-                });
-              });
-            }
-            return _fill;
-          });
-
-      g.append("svg:text")
-          .attr("transform", transform)
-          .attr("dy", ".35em")
-          .style("opacity", function (d) {
-            return d.dx * _ky > 12 ? 1 : 0;
-          })
-          .text(function (d) {
-            if (d.depth < 2) {
-              return d.name + " (" + d.value + ")";
-            }
-            else {
-              return d.parent.name + " - " + d.name + " (" + d.value + ")";
-            }
-          });
-
-      d3v3.select(window)
-          .on("click", function () {
-            click(_data);
-          });
-
-      function click(d) {
-        _tip.hide();
-        if (!d.children) return;
-
-        _kx = (d.y ? _w - 40 : _w) / (1 - d.y);
-        _ky = _h / d.dx;
-        _x.domain([d.y, 1]).range([d.y ? 40 : 0, _w]);
-        _y.domain([d.x, d.x + d.dx]);
-
-        var t = g.transition()
-            .delay(250)
-            .duration(d3v3.event.altKey ? 7500 : 750)
-            .attr("transform", function (d) {
-              return "translate(" + _x(d.y) + "," + _y(d.x) + ")";
-            });
-
-        t.select("rect")
-            .attr("width", d.dy * _kx)
-            .attr("height", function (d) {
-              return d.dx * _ky;
-            });
-
-        t.select("text")
-            .attr("transform", transform)
-            .style("opacity", function (d) {
-              return d.dx * _ky > 12 ? 1 : 0;
-            });
-
-        d3v3.event.stopPropagation();
-      }
-
-      function transform(d) {
-        return "translate(8," + d.dx * _ky / 2 + ")";
-      }
-
-      if (_options.onComplete) {
-        _options.onComplete();
-      }
-
-    },
-    init: function (element, valueAccessor) {
-      ko.bindingHandlers.partitionChart.render(element, valueAccessor);
-    },
-    update: function (element, valueAccessor) {
-      ko.bindingHandlers.partitionChart.render(element, valueAccessor);
-    }
-  };
-
-  huePubSub.subscribe('charts.state', function(state) {
-    var opacity = state && state.updating ? '0.5' : '1';
-    $('.nvd3').parents('svg').css('opacity', opacity);
-  });
-
-  var tipBuilder = function () {
-    var direction = d3_tip_direction,
-        offset = d3_tip_offset,
-        html = d3_tip_html,
-        node = initNode(),
-        svg = null,
-        point = null,
-        target = null
-
-    function tip(vis) {
-      svg = getSVGNode(vis)
-      point = svg.createSVGPoint()
-      document.body.appendChild(node)
-    }
-
-    // Public - show the tooltip on the screen
-    //
-    // Returns a tip
-    tip.show = function () {
-      var args = Array.prototype.slice.call(arguments)
-      if (args[args.length - 1] instanceof SVGElement) target = args.pop()
-
-      var content = html.apply(this, args),
-          poffset = offset.apply(this, args),
-          dir = direction.apply(this, args),
-          nodel = d3v3.select(node), i = 0,
-          coords
-
-      nodel.html(content)
-          .style({ opacity: 1, "pointer-events": "all" })
-
-      while (i--) nodel.classed(directions[i], false)
-      coords = direction_callbacks.get(dir).apply(this)
-      nodel.classed(dir, true).style({
-        top: (coords.top + poffset[0]) + "px",
-        left: (coords.left + poffset[1]) + "px"
-      })
-
-      return tip
-    }
-
-    // Public - hide the tooltip
-    //
-    // Returns a tip
-    tip.hide = function () {
-      nodel = d3v3.select(node)
-      nodel.style({ opacity: 0, "pointer-events": "none" })
-      return tip
-    }
-
-    // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
-    //
-    // n - name of the attribute
-    // v - value of the attribute
-    //
-    // Returns tip or attribute value
-    tip.attr = function (n, v) {
-      if (arguments.length < 2 && typeof n === "string") {
-        return d3v3.select(node).attr(n)
-      } else {
-        var args = Array.prototype.slice.call(arguments)
-        d3v3.selection.prototype.attr.apply(d3v3.select(node), args)
-      }
-
-      return tip
-    }
-
-    // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
-    //
-    // n - name of the property
-    // v - value of the property
-    //
-    // Returns tip or style property value
-    tip.style = function (n, v) {
-      if (arguments.length < 2 && typeof n === "string") {
-        return d3v3.select(node).style(n)
-      } else {
-        var args = Array.prototype.slice.call(arguments)
-        d3v3.selection.prototype.style.apply(d3v3.select(node), args)
-      }
-
-      return tip
-    }
-
-    // Public: Set or get the direction of the tooltip
-    //
-    // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
-    //     sw(southwest), ne(northeast) or se(southeast)
-    //
-    // Returns tip or direction
-    tip.direction = function (v) {
-      if (!arguments.length) return direction
-      direction = v == null ? v : d3v3.functor(v)
-
-      return tip
-    }
-
-    // Public: Sets or gets the offset of the tip
-    //
-    // v - Array of [x, y] offset
-    //
-    // Returns offset or
-    tip.offset = function (v) {
-      if (!arguments.length) return offset
-      offset = v == null ? v : d3v3.functor(v)
-
-      return tip
-    }
-
-    // Public: sets or gets the html value of the tooltip
-    //
-    // v - String value of the tip
-    //
-    // Returns html value or tip
-    tip.html = function (v) {
-      if (!arguments.length) return html
-      html = v == null ? v : d3v3.functor(v)
-
-      return tip
-    }
-
-    function d3_tip_direction() {
-      return "n"
-    }
-
-    function d3_tip_offset() {
-      return [0, 0]
-    }
-
-    function d3_tip_html() {
-      return " "
-    }
-
-    var direction_callbacks = d3v3.map({
-          n: direction_n,
-          s: direction_s,
-          e: direction_e,
-          w: direction_w,
-          nw: direction_nw,
-          ne: direction_ne,
-          sw: direction_sw,
-          se: direction_se
-        }),
-
-        directions = direction_callbacks.keys()
-
-    function direction_n() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.n.y - node.offsetHeight,
-        left: bbox.n.x - node.offsetWidth / 2
-      }
-    }
-
-    function direction_s() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.s.y,
-        left: bbox.s.x - node.offsetWidth / 2
-      }
-    }
-
-    function direction_e() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.e.y - node.offsetHeight / 2,
-        left: bbox.e.x
-      }
-    }
-
-    function direction_w() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.w.y - node.offsetHeight / 2,
-        left: bbox.w.x - node.offsetWidth
-      }
-    }
-
-    function direction_nw() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.nw.y - node.offsetHeight,
-        left: bbox.nw.x - node.offsetWidth
-      }
-    }
-
-    function direction_ne() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.ne.y - node.offsetHeight,
-        left: bbox.ne.x
-      }
-    }
-
-    function direction_sw() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.sw.y,
-        left: bbox.sw.x - node.offsetWidth
-      }
-    }
-
-    function direction_se() {
-      var bbox = getScreenBBox()
-      return {
-        top: bbox.se.y,
-        left: bbox.e.x
-      }
-    }
-
-    function initNode() {
-      var node = d3v3.select(document.createElement("div"))
-      node.style({
-        position: "absolute",
-        background: HueColors.cuiD3Scale()[0],
-        padding: "4px",
-        color: HueColors.WHITE,
-        opacity: 0,
-        pointerEvents: "none",
-        boxSizing: "border-box"
-      })
-
-      return node.node()
-    }
-
-    function getSVGNode(el) {
-      el = el.node()
-      if (el != null) {
-        if (el.tagName != null && el.tagName.toLowerCase() == "svg")
-          return el
-
-        return el.ownerSVGElement
-      }
-    }
-
-    // Private - gets the screen coordinates of a shape
-    //
-    // Given a shape on the screen, will return an SVGPoint for the directions
-    // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
-    // sw(southwest).
-    //
-    //    +-+-+
-    //    |   |
-    //    +   +
-    //    |   |
-    //    +-+-+
-    //
-    // Returns an Object {n, s, e, w, nw, sw, ne, se}
-    function getScreenBBox() {
-      var targetel = target || d3v3.event.target,
-          bbox = {},
-          matrix = targetel.getScreenCTM(),
-          tbbox = targetel.getBBox(),
-          width = tbbox.width,
-          height = tbbox.height,
-          x = tbbox.x,
-          y = tbbox.y,
-          scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
-          scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
-
-
-      point.x = x + scrollLeft
-      point.y = y + scrollTop
-      bbox.nw = point.matrixTransform(matrix)
-      point.x += width
-      bbox.ne = point.matrixTransform(matrix)
-      point.y += height
-      bbox.se = point.matrixTransform(matrix)
-      point.x -= width
-      bbox.sw = point.matrixTransform(matrix)
-      point.y -= height / 2
-      bbox.w = point.matrixTransform(matrix)
-      point.x += width
-      bbox.e = point.matrixTransform(matrix)
-      point.x -= width / 2
-      point.y -= height / 2
-      bbox.n = point.matrixTransform(matrix)
-      point.y += height
-      bbox.s = point.matrixTransform(matrix)
-
-      return bbox
-    }
-
-    return tip
-  };
-
-  if (typeof d3v3 !== 'undefined') {
-    d3v3.tip = tipBuilder;
-  }
-
-})();

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

@@ -39,8 +39,6 @@ from desktop import conf
   <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/ext/js/d3.v3.js') }"></script>
-  <script src="${ static('desktop/ext/js/d3.v4.js') }"></script>
   <script src="${ static('desktop/js/nv.d3.js') }"></script>
   <script src="${ static('desktop/ext/js/topojson.v1.min.js') }"></script>
   <script src="${ static('desktop/ext/js/topo/world.topo.js') }"></script>
@@ -66,7 +64,6 @@ from desktop import conf
   <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.js') }"></script>
   <script src="${ static('desktop/js/ko.charts.leaflet.js') }"></script>
   %endif
 

+ 14 - 14
desktop/core/src/desktop/templates/common_dashboard.mako

@@ -239,55 +239,55 @@
                   <div class="dropdown inline-block">
                     <a class="dropdown-toggle" href="javascript: void(0)" data-toggle="dropdown" title="${ _('Change widget visualization') }">
                       <!-- ko switch: fieldViz -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.COUNTER --><i class="fa fa-superscript fa-fw"></i> ${_('Counter')}<!-- /ko -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.TEXTSELECT --><i class="fa fa-sort-amount-asc fa-fw"></i> ${_('Text select')}<!-- /ko -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.BARCHART --><i class="hcha hcha-bar-chart fa-fw"></i> ${_('Bars')}<!-- /ko -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.PIECHART --><i class="hcha hcha-pie-chart fa-fw"></i> ${_('Pie')}<!-- /ko -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.TIMELINECHART --><i class="fa fa-fw fa-line-chart"></i> ${_('Timeline')}<!-- /ko -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.GRADIENTMAP --><i class="hcha fa-fw hcha-map-chart chart-icon"></i> ${_('Gradient Map')}<!-- /ko -->
-                        <!-- ko case: ko.HUE_CHARTS.TYPES.MAP --><i class="fa fa-fw fa-map-marker chart-icon"></i> ${_('Marker Map')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.COUNTER --><i class="fa fa-superscript fa-fw"></i> ${_('Counter')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.TEXTSELECT --><i class="fa fa-sort-amount-asc fa-fw"></i> ${_('Text select')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.BARCHART --><i class="hcha hcha-bar-chart fa-fw"></i> ${_('Bars')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.PIECHART --><i class="hcha hcha-pie-chart fa-fw"></i> ${_('Pie')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.TIMELINECHART --><i class="fa fa-fw fa-line-chart"></i> ${_('Timeline')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.GRADIENTMAP --><i class="hcha fa-fw hcha-map-chart chart-icon"></i> ${_('Gradient Map')}<!-- /ko -->
+                        <!-- ko case: window.HUE_CHARTS.TYPES.MAP --><i class="fa fa-fw fa-map-marker chart-icon"></i> ${_('Marker Map')}<!-- /ko -->
                       <!-- /ko -->
                     </a>
                     <ul class="dropdown-menu">
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.COUNTER); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.COUNTER); }">
                           <i class="fa fa-superscript fa-fw"></i> ${_('Counter')}
                         </a>
                       </li>
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.TEXTSELECT); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.TEXTSELECT); }">
                           <i class="fa fa-sort-amount-asc fa-fw"></i> ${_('Text select')}
                         </a>
                       </li>
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.BARCHART); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.BARCHART); }">
                           <i class="hcha hcha-bar-chart fa-fw"></i> ${_('Bars')}
                         </a>
                       </li>
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.PIECHART); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.PIECHART); }">
                           <i class="hcha hcha-pie-chart fa-fw"></i> ${_('Pie')}
                         </a>
                       </li>
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.TIMELINECHART); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.TIMELINECHART); }">
                           <i class="fa fa-fw fa-line-chart"></i> ${_('Timeline')}
                         </a>
                       </li>
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.GRADIENTMAP); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.GRADIENTMAP); }">
                           <i class="hcha fa-fw hcha-map-chart chart-icon"></i> ${_('Gradient Map')}
                         </a>
                       </li>
                       <li>
                         <a href="javascript:void(0)"
-                           data-bind="click: function(){ fieldViz(ko.HUE_CHARTS.TYPES.MAP); }">
+                           data-bind="click: function(){ fieldViz(window.HUE_CHARTS.TYPES.MAP); }">
                           <i class="fa fa-fw fa-map-marker chart-icon"></i> ${_('Marker Map')}
                         </a>
                       </li>

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

@@ -140,8 +140,6 @@ if USE_NEW_EDITOR.get():
     ${ render_bundle('hue') | n,unicode }
   % endif
 
-  <script src="${ static('desktop/ext/js/d3.v3.js') }"></script>
-  <script src="${ static('desktop/ext/js/d3.v4.js') }"></script>
   <script src="${ static('desktop/js/bootstrap-tooltip.js') }"></script>
   <script src="${ static('desktop/js/bootstrap-typeahead-touchscreen.js') }"></script>
   <script src="${ static('desktop/ext/js/bootstrap-better-typeahead.min.js') }"></script>

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

@@ -170,8 +170,6 @@ if USE_NEW_EDITOR.get():
   <script src="${ static('desktop/ext/js/moment-with-locales.min.js') }"></script>
   <script src="${ static('desktop/ext/js/moment-timezone-with-data.min.js') }" type="text/javascript" charset="utf-8"></script>
   <script src="${ static('desktop/ext/js/tzdetect.js') }" type="text/javascript" charset="utf-8"></script>
-  <script src="${ static('desktop/ext/js/d3.v3.js') }"></script>
-  <script src="${ static('desktop/ext/js/d3.v4.js') }"></script>
   <script src="${ static('desktop/js/ace/ace.js') }"></script>
   <script src="${ static('desktop/js/ace/mode-impala.js') }"></script>
   <script src="${ static('desktop/js/ace/mode-hive.js') }"></script>

+ 3 - 3
desktop/libs/dashboard/src/dashboard/static/dashboard/js/search.ko.js

@@ -121,7 +121,7 @@ var EmptyGridsterWidget = function (vm) {
 
   self.isAdding = ko.observable(true);
   self.fieldName = ko.observable();
-  self.fieldViz = ko.observable(ko.HUE_CHARTS.TYPES.BARCHART);
+  self.fieldViz = ko.observable(window.HUE_CHARTS.TYPES.BARCHART);
   self.fieldSort = ko.observable('desc');
   self.fieldOperation = ko.observable();
   self.fieldOperations = ko.pureComputed(function () {
@@ -1404,12 +1404,12 @@ var Collection = function (vm, collection) {
   self.template.hasDataForChart = ko.computed(function () {
     var hasData = false;
 
-    if ([ko.HUE_CHARTS.TYPES.BARCHART, ko.HUE_CHARTS.TYPES.LINECHART, ko.HUE_CHARTS.TYPES.TIMELINECHART].indexOf(self.template.chartSettings.chartType()) >= 0) {
+    if ([window.HUE_CHARTS.TYPES.BARCHART, window.HUE_CHARTS.TYPES.LINECHART, window.HUE_CHARTS.TYPES.TIMELINECHART].indexOf(self.template.chartSettings.chartType()) >= 0) {
       hasData = typeof self.template.chartSettings.chartX() != "undefined" && self.template.chartSettings.chartX() != null && self.template.chartSettings.chartYMulti().length > 0;
     }
     else {
       hasData = typeof self.template.chartSettings.chartX() != "undefined" && self.template.chartSettings.chartX() != null && typeof self.template.chartSettings.chartYSingle() != "undefined" && self.template.chartSettings.chartYSingle() != null
-        || self.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.COUNTER;
+        || self.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.COUNTER;
     }
     if (!hasData && self.template.showChart()){
       self.template.showFieldList(true);

+ 42 - 42
desktop/libs/dashboard/src/dashboard/templates/common_search.mako

@@ -868,10 +868,10 @@ ${ dashboard.layout_skeleton(suffix='search') }
 
 <script type="text/html" id="grid-chart-settings">
 <!-- ko if: $parent.widgetType() === 'resultset-widget' || $parent.widgetType() === 'document-widget' -->
-  <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: [ko.HUE_CHARTS.TYPES.TIMELINECHART, ko.HUE_CHARTS.TYPES.BARCHART].indexOf(chartSettings.chartType()) >= 0">
+  <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: [window.HUE_CHARTS.TYPES.TIMELINECHART, window.HUE_CHARTS.TYPES.BARCHART].indexOf(chartSettings.chartType()) >= 0">
     <li class="nav-header">${_('Chart Type')}</li>
   </ul>
-  <div data-bind="visible: [ko.HUE_CHARTS.TYPES.TIMELINECHART, ko.HUE_CHARTS.TYPES.BARCHART].indexOf(chartSettings.chartType()) >= 0">
+  <div data-bind="visible: [window.HUE_CHARTS.TYPES.TIMELINECHART, window.HUE_CHARTS.TYPES.BARCHART].indexOf(chartSettings.chartType()) >= 0">
     <select class="input-medium" data-bind="options: $root.timelineChartTypes,
                  optionsText: 'label',
                  optionsValue: 'value',
@@ -879,42 +879,42 @@ ${ dashboard.layout_skeleton(suffix='search') }
     </select>
   </div>
   <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartSettings.chartType() != ''">
-    <li data-bind="visible: [ko.HUE_CHARTS.TYPES.MAP, ko.HUE_CHARTS.TYPES.GRADIENTMAP, ko.HUE_CHARTS.TYPES.PIECHART].indexOf(chartSettings.chartType()) == -1" class="nav-header">${_('x-axis')}</li>
-    <li data-bind="visible: chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('region')}</li>
-    <li data-bind="visible: chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('latitude')}</li>
-    <li data-bind="visible: chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART" class="nav-header">${_('legend')}</li>
+    <li data-bind="visible: [window.HUE_CHARTS.TYPES.MAP, window.HUE_CHARTS.TYPES.GRADIENTMAP, window.HUE_CHARTS.TYPES.PIECHART].indexOf(chartSettings.chartType()) == -1" class="nav-header">${_('x-axis')}</li>
+    <li data-bind="visible: chartSettings.chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('region')}</li>
+    <li data-bind="visible: chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('latitude')}</li>
+    <li data-bind="visible: chartSettings.chartType() == window.HUE_CHARTS.TYPES.PIECHART" class="nav-header">${_('legend')}</li>
   </ul>
   <div data-bind="visible: chartSettings.chartType() != ''">
-    <select data-bind="options: [ko.HUE_CHARTS.TYPES.BARCHART, ko.HUE_CHARTS.TYPES.PIECHART, ko.HUE_CHARTS.TYPES.GRADIENTMAP, ko.HUE_CHARTS.TYPES.MAP].indexOf(chartSettings.chartType()) >= 0 ? cleanedMeta : chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART ? cleanedDateTimeMeta : cleanedNumericMeta, value: chartSettings.chartX, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartSettings.chartX}" class="input-medium"></select>
+    <select data-bind="options: [window.HUE_CHARTS.TYPES.BARCHART, window.HUE_CHARTS.TYPES.PIECHART, window.HUE_CHARTS.TYPES.GRADIENTMAP, window.HUE_CHARTS.TYPES.MAP].indexOf(chartSettings.chartType()) >= 0 ? cleanedMeta : chartSettings.chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART ? cleanedDateTimeMeta : cleanedNumericMeta, value: chartSettings.chartX, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartSettings.chartX}" class="input-medium"></select>
   </div>
 
   <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartSettings.chartType() != ''">
-    <li data-bind="visible: [ko.HUE_CHARTS.TYPES.MAP, , ko.HUE_CHARTS.TYPES.PIECHART].indexOf(chartSettings.chartType()) == -1" class="nav-header">${_('y-axis')}</li>
-    <li data-bind="visible: chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('longitude')}</li>
-    <li data-bind="visible: chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART" class="nav-header">${_('value')}</li>
+    <li data-bind="visible: [window.HUE_CHARTS.TYPES.MAP, , window.HUE_CHARTS.TYPES.PIECHART].indexOf(chartSettings.chartType()) == -1" class="nav-header">${_('y-axis')}</li>
+    <li data-bind="visible: chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('longitude')}</li>
+    <li data-bind="visible: chartSettings.chartType() == window.HUE_CHARTS.TYPES.PIECHART" class="nav-header">${_('value')}</li>
   </ul>
 
-  <div style="overflow-y: auto; max-height: 220px" data-bind="visible: chartSettings.chartType() != '' && ([ko.HUE_CHARTS.TYPES.TIMELINECHART, ko.HUE_CHARTS.TYPES.BARCHART, ko.HUE_CHARTS.TYPES.LINECHART].indexOf(chartSettings.chartType()) >= 0 )">
+  <div style="overflow-y: auto; max-height: 220px" data-bind="visible: chartSettings.chartType() != '' && ([window.HUE_CHARTS.TYPES.TIMELINECHART, window.HUE_CHARTS.TYPES.BARCHART, window.HUE_CHARTS.TYPES.LINECHART].indexOf(chartSettings.chartType()) >= 0 )">
     <ul class="unstyled" data-bind="foreach: cleanedNumericMeta">
       <li><input type="checkbox" data-bind="checkedValue: name, checked: $parent.chartSettings.chartYMulti" /> <span data-bind="text: name"></span></li>
     </ul>
   </div>
-  <div data-bind="visible: [ko.HUE_CHARTS.TYPES.PIECHART, ko.HUE_CHARTS.TYPES.MAP, ko.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartSettings.chartType()) >= 0">
+  <div data-bind="visible: [window.HUE_CHARTS.TYPES.PIECHART, window.HUE_CHARTS.TYPES.MAP, window.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartSettings.chartType()) >= 0">
     <select data-bind="options: cleanedNumericMeta, value: chartSettings.chartYSingle, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartSettings.chartYSingle}" class="input-medium"></select>
   </div>
 
-  <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartSettings.chartType() != '' && chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP && ko.HUE_CHARTS.TYPES.GRADIENTMAP">
+  <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartSettings.chartType() != '' && chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP && window.HUE_CHARTS.TYPES.GRADIENTMAP">
     <li class="nav-header">${_('label')}</li>
   </ul>
-  <div data-bind="visible: chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP">
+  <div data-bind="visible: chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP">
     <select data-bind="options: cleanedMeta, value: chartSettings.chartMapLabel, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartSettings.chartMapLabel}" class="input-medium"></select>
   </div>
 
 
-  <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartSettings.chartType() != '' && [ko.HUE_CHARTS.TYPES.MAP, ko.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartSettings.chartType()) < 0">
+  <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartSettings.chartType() != '' && [window.HUE_CHARTS.TYPES.MAP, window.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartSettings.chartType()) < 0">
     <li class="nav-header">${_('sorting')}</li>
   </ul>
-  <div class="btn-group" data-toggle="buttons-radio" data-bind="visible: chartSettings.chartType() != '' && [ko.HUE_CHARTS.TYPES.MAP, ko.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartSettings.chartType()) < 0">
+  <div class="btn-group" data-toggle="buttons-radio" data-bind="visible: chartSettings.chartType() != '' && [window.HUE_CHARTS.TYPES.MAP, window.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartSettings.chartType()) < 0">
     <a rel="tooltip" data-placement="top" title="${_('No sorting')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSettings.chartSorting() == 'none'}, click: function(){ chartSettings.chartSorting('none'); }"><i class="fa fa-align-left fa-rotate-270"></i></a>
     <a rel="tooltip" data-placement="top" title="${_('Sort ascending')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSettings.chartSorting() == 'asc'}, click: function(){ chartSettings.chartSorting('asc'); }"><i class="fa fa-sort-amount-asc fa-rotate-270"></i></a>
     <a rel="tooltip" data-placement="top" title="${_('Sort descending')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSettings.chartSorting() == 'desc'}, click: function(){ chartSettings.chartSorting('desc'); }"><i class="fa fa-sort-amount-desc fa-rotate-270"></i></a>
@@ -1391,14 +1391,14 @@ ${ dashboard.layout_skeleton(suffix='search') }
           <a class="grid-side-btn" style="padding-right:0" href="javascript:void(0)"
              data-bind="css: {'active': template.showChart() }, click: function(collection, event){ template.showChart(true); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate'); }">
             % if HAS_REPORT_ENABLED.get():
-            <i class="fa fa-superscript fa-fw" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.COUNTER"></i>
-            <i class="fa fa-sort-amount-asc fa-fw" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TEXTSELECT"></i>
+            <i class="fa fa-superscript fa-fw" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.COUNTER"></i>
+            <i class="fa fa-sort-amount-asc fa-fw" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.TEXTSELECT"></i>
             % endif
-            <i class="hcha hcha-bar-chart fa-fw" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.BARCHART"></i>
-            <i class="hcha hcha-pie-chart fa-fw" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART" style="display: none;"></i>
-            <i class="fa fa-fw fa-line-chart" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART" style="display: none;"></i>
-            <i class="hcha hcha-map-chart fa-fw" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" style="display: none;"></i>
-            <i class="fa fa-fw fa-map-marker" data-bind="visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP" style="display: none;"></i>
+            <i class="hcha hcha-bar-chart fa-fw" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.BARCHART"></i>
+            <i class="hcha hcha-pie-chart fa-fw" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.PIECHART" style="display: none;"></i>
+            <i class="fa fa-fw fa-line-chart" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART" style="display: none;"></i>
+            <i class="hcha hcha-map-chart fa-fw" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP" style="display: none;"></i>
+            <i class="fa fa-fw fa-map-marker" data-bind="visible: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP" style="display: none;"></i>
           </a>
           <a class="dropdown-toggle grid-side-btn" style="padding:0" data-toggle="dropdown"
              href="javascript: void(0)" data-bind="css: {'active': template.showChart()}">
@@ -1408,47 +1408,47 @@ ${ dashboard.layout_skeleton(suffix='search') }
           <ul class="dropdown-menu">
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.COUNTER}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.COUNTER); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}"
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.COUNTER}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.COUNTER); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}"
                  class="active">
                 <i class="fa fa-superscript fa-fw"></i> ${_('Counter')}
               </a>
             </li>
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TEXTSELECT}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.TEXTSELECT); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}"
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.TEXTSELECT}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.TEXTSELECT); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}"
                  class="active">
                 <i class="fa fa-sort-amount-asc fa-fw"></i> ${_('Text select')}
               </a>
             </li>
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.BARCHART}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.BARCHART); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}"
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.BARCHART}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.BARCHART); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}"
                  class="active">
                 <i class="hcha hcha-bar-chart fa-fw"></i> ${_('Bars')}
               </a>
             </li>
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.PIECHART); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.PIECHART}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.PIECHART); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
                 <i class="hcha hcha-pie-chart fa-fw"></i> ${_('Pie')}
               </a>
             </li>
             ##<!-- ko if: widgetType() != 'resultset-widget' -->
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.TIMELINECHART); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.TIMELINECHART); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
                 <i class="fa fa-fw fa-line-chart"></i> ${_('Timeline')}
               </a>
             </li>
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.GRADIENTMAP); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.GRADIENTMAP); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
                 <i class="hcha fa-fw hcha-map-chart chart-icon"></i> ${_('Gradient Map')}
               </a>
             </li>
             <li>
               <a href="javascript:void(0)"
-                 data-bind="css: {'active': template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(ko.HUE_CHARTS.TYPES.MAP); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
+                 data-bind="css: {'active': template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP}, click: function(collection, event){ template.showChart(true); template.chartSettings.chartType(window.HUE_CHARTS.TYPES.MAP); template.showGrid(false); huePubSub.publish('gridster.clean.grid.whitespace', { event: event, lookFor: '.grid-results-chart' }); huePubSub.publish('gridChartForceUpdate');}">
                 <i class="fa fa-fw fa-map-marker chart-icon"></i> ${_('Marker Map')}
               </a>
             </li>
@@ -1741,28 +1741,28 @@ ${ dashboard.layout_skeleton(suffix='search') }
         <!-- /ko -->
 
         <!-- ko if: widgetType() == 'document-widget' -->
-          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART -->
+          <!-- ko if: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.PIECHART -->
           <div data-bind="attr:{'id': 'pieChart_'+id()}, pieChart: {data: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle}, field: template.chartSettings.chartX, fqs: $root.query.fqs,
                 transformer: pieChartDataTransformerGrid, maxWidth: 350, parentSelector: '.chart-container'}" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.BARCHART -->
+          <!-- ko if: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.BARCHART -->
           <div data-bind="attr:{'id': 'barChart_'+id()}, barChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti}, field: template.chartSettings.chartX, fqs: $root.query.fqs, hideSelection: true, enableSelection: false, hideStacked: template.chartSettings.hideStacked,
                 transformer: multiSerieDataTransformerGrid, stacked: false, showLegend: true, type: template.chartSettings.chartSelectorType},  stacked: true, showLegend: true" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.LINECHART -->
+          <!-- ko if: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.LINECHART -->
           <div data-bind="attr:{'id': 'lineChart_'+id()}, lineChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti}, field: template.chartSettings.chartX, fqs: $root.query.fqs, hideSelection: true, enableSelection: false,
                 transformer: multiSerieDataTransformerGrid, showControls: false}" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP -->
+          <!-- ko if: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP -->
           <div data-bind="attr: {'id': 'leafletMapChart_'+id()}, leafletMapChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle, chartZ: template.chartSettings.chartMapLabel},
                 transformer: leafletMapChartDataTransformerGrid, showControls: false, height: 380, forceRedraw: true,
                 showMoveCheckbox: false, moveCheckboxLabel: '${ _ko('Search as I move the map') }'}" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART -->
+          <!-- ko if: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART -->
           <div data-bind="attr:{'id': 'timelineChart_'+id()}, timelineChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti, widget_id: $parent.id()}, field: template.chartSettings.chartX, fqs: $root.query.fqs, hideSelection: true, enableSelection: false, hideStacked: template.chartSettings.hideStacked,
                 transformer: multiSerieDataTransformerGrid, showControls: false}" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP -->
+          <!-- ko if: template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP -->
           <div data-bind="attr:{'id': 'gradientMapChart_'+id()}, mapChart: {data: {counts: $parent.results(), scope: template.chartSettings.chartScope(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle},
               transformer: gradientMapChartDataTransformerGrid, maxWidth: 750, isScale: true}" />
           <!-- /ko -->
@@ -1770,27 +1770,27 @@ ${ dashboard.layout_skeleton(suffix='search') }
         <!-- /ko -->
 
         <!-- ko if: widgetType() == 'resultset-widget' -->
-          <!-- ko if: $root.collection.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART -->
+          <!-- ko if: $root.collection.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.PIECHART -->
           <div data-bind="attr:{'id': 'pieChart_'+id()}, pieChart: {data: {counts: $root.results(), sorting: $root.collection.template.chartSettings.chartSorting(), snippet: $data}, fqs: ko.observableArray([]),
                 transformer: pieChartDataTransformerGrid, maxWidth: 350, parentSelector: '.chart-container' }" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: $root.collection.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.BARCHART -->
+          <!-- ko if: $root.collection.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.BARCHART -->
           <div data-bind="attr:{'id': 'barChart_'+id()}, barChart: {datum: {counts: $root.results(), sorting: $root.collection.template.chartSettings.chartSorting(), snippet: $data}, fqs: ko.observableArray([]), hideSelection: true, enableSelection: false, hideStacked: $root.collection.template.chartSettings.hideStacked,
                 transformer: multiSerieDataTransformerGrid, stacked: false, showLegend: true, type: $root.collection.template.chartSettings.chartSelectorType},  stacked: true, showLegend: true" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: $root.collection.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.LINECHART -->
+          <!-- ko if: $root.collection.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.LINECHART -->
           <div data-bind="attr:{'id': 'lineChart_'+id()}, lineChart: {datum: {counts: $root.results(), sorting: $root.collection.template.chartSettings.chartSorting(), snippet: $data},
                 transformer: multiSerieDataTransformerGrid, showControls: false }" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: $root.collection.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP -->
+          <!-- ko if: $root.collection.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.MAP -->
           <div data-bind="attr: {'id': 'leafletMapChart_'+id()}, leafletMapChart: {datum: {counts: $root.results(), sorting: $root.collection.template.chartSettings.chartSorting(), snippet: $data},
                 transformer: leafletMapChartDataTransformerGrid, showControls: false, height: 380, forceRedraw: true}" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: $root.collection.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART -->
+          <!-- ko if: $root.collection.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART -->
           <div data-bind="attr:{'id': 'timelineChart_'+id()}, timelineChart: {datum: {counts: $root.results(), sorting: $root.collection.template.chartSettings.chartSorting(), snippet: $data}, fqs: ko.observableArray([]), hideSelection: true, enableSelection: false, hideStacked: $root.collection.template.chartSettings.hideStacked,
                 transformer: multiSerieDataTransformerGrid, showControls: false }" class="chart"></div>
           <!-- /ko -->
-          <!-- ko if: $root.collection.template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP -->
+          <!-- ko if: $root.collection.template.chartSettings.chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP -->
           <div data-bind="attr:{'id': 'gradientMapChart_'+id()}, mapChart: {data: {counts: $root.results(), scope: $root.collection.template.chartSettings.chartScope(), snippet: $data},
               transformer: gradientMapChartDataTransformerGrid, maxWidth: 750, isScale: true}" />
           <div class="clearfix"></div>

+ 49 - 49
desktop/libs/notebook/src/notebook/templates/editor_components.mako

@@ -1291,7 +1291,7 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
 
 <script type="text/html" id="snippet-chart-settings${ suffix }">
   <div>
-    <!-- ko if: chartType() != '' && [ko.HUE_CHARTS.TYPES.TIMELINECHART, ko.HUE_CHARTS.TYPES.BARCHART].indexOf(chartType()) >= 0  -->
+    <!-- ko if: chartType() != '' && [window.HUE_CHARTS.TYPES.TIMELINECHART, window.HUE_CHARTS.TYPES.BARCHART].indexOf(chartType()) >= 0  -->
     <ul class="nav nav-list" style="border: none; background-color: #FFF">
       <li class="nav-header">${_('type')}</li>
     </ul>
@@ -1303,7 +1303,7 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
     </div>
     <!-- /ko -->
 
-    <!-- ko if: chartType() != '' && chartType() === ko.HUE_CHARTS.TYPES.PIECHART -->
+    <!-- ko if: chartType() != '' && chartType() === window.HUE_CHARTS.TYPES.PIECHART -->
     <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != ''">
       <li class="nav-header">${_('value')}</li>
     </ul>
@@ -1318,36 +1318,36 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
     </div>
     <!-- /ko -->
 
-    <!-- ko if: chartType() != '' && chartType() !== ko.HUE_CHARTS.TYPES.PIECHART -->
+    <!-- ko if: chartType() != '' && chartType() !== window.HUE_CHARTS.TYPES.PIECHART -->
     <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != ''">
-      <li data-bind="visible: [ko.HUE_CHARTS.TYPES.MAP, ko.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartType()) == -1" class="nav-header">${_('x-axis')}</li>
-      <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('region')}</li>
-      <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('latitude')}</li>
+      <li data-bind="visible: [window.HUE_CHARTS.TYPES.MAP, window.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartType()) == -1" class="nav-header">${_('x-axis')}</li>
+      <li data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('region')}</li>
+      <li data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('latitude')}</li>
     </ul>
     <div>
-      <select data-bind="options: ([ko.HUE_CHARTS.TYPES.BARCHART, ko.HUE_CHARTS.TYPES.GRADIENTMAP, ko.HUE_CHARTS.TYPES.TIMELINECHART].indexOf(chartType()) > -1) ? ( chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART ? result.cleanedDateTimeMeta : result.cleanedMeta ) : result.cleanedNumericMeta, value: chartX, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartX, dropdownAutoWidth: true}" class="input-medium"></select>
+      <select data-bind="options: ([window.HUE_CHARTS.TYPES.BARCHART, window.HUE_CHARTS.TYPES.GRADIENTMAP, window.HUE_CHARTS.TYPES.TIMELINECHART].indexOf(chartType()) > -1) ? ( chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART ? result.cleanedDateTimeMeta : result.cleanedMeta ) : result.cleanedNumericMeta, value: chartX, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartX, dropdownAutoWidth: true}" class="input-medium"></select>
     </div>
 
     <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != ''">
-      <li data-bind="visible: [ko.HUE_CHARTS.TYPES.MAP, ko.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartType()) == -1" class="nav-header">${_('y-axis')}</li>
-      <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('value')}</li>
-      <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('longitude')}</li>
+      <li data-bind="visible: [window.HUE_CHARTS.TYPES.MAP, window.HUE_CHARTS.TYPES.GRADIENTMAP].indexOf(chartType()) == -1" class="nav-header">${_('y-axis')}</li>
+      <li data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('value')}</li>
+      <li data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('longitude')}</li>
     </ul>
 
-    <div style="max-height: 220px" data-bind="delayedOverflow, visible: chartType() != '' && ((chartType() == ko.HUE_CHARTS.TYPES.BARCHART && !chartXPivot()) || chartType() == ko.HUE_CHARTS.TYPES.LINECHART || chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART)">
+    <div style="max-height: 220px" data-bind="delayedOverflow, visible: chartType() != '' && ((chartType() == window.HUE_CHARTS.TYPES.BARCHART && !chartXPivot()) || chartType() == window.HUE_CHARTS.TYPES.LINECHART || chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART)">
       <ul class="unstyled" data-bind="foreach: result.cleanedNumericMeta" style="margin-bottom: 0">
         <li><label class="checkbox"><input type="checkbox" data-bind="checkedValue: name, checked: $parent.chartYMulti" /> <span data-bind="text: $data.name"></span></label></li>
       </ul>
     </div>
-    <div data-bind="visible: (chartType() == ko.HUE_CHARTS.TYPES.BARCHART && chartXPivot()) || chartType() == ko.HUE_CHARTS.TYPES.MAP || chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP || chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
-      <select data-bind="options: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP ? result.cleanedMeta : result.cleanedNumericMeta, value: chartYSingle, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartYSingle, dropdownAutoWidth: true}" class="input-medium"></select>
+    <div data-bind="visible: (chartType() == window.HUE_CHARTS.TYPES.BARCHART && chartXPivot()) || chartType() == window.HUE_CHARTS.TYPES.MAP || chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP || chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART">
+      <select data-bind="options: chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP ? result.cleanedMeta : result.cleanedNumericMeta, value: chartYSingle, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartYSingle, dropdownAutoWidth: true}" class="input-medium"></select>
     </div>
     <!-- /ko -->
 
-    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() === ko.HUE_CHARTS.TYPES.BARCHART">
+    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() === window.HUE_CHARTS.TYPES.BARCHART">
       <li class="nav-header">${_('group')}</li>
     </ul>
-    <div data-bind="visible: chartType() === ko.HUE_CHARTS.TYPES.BARCHART">
+    <div data-bind="visible: chartType() === window.HUE_CHARTS.TYPES.BARCHART">
       <select data-bind="options: result.cleanedMeta, value: chartXPivot, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column to pivot...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column to pivot...") }', update: chartXPivot, dropdownAutoWidth: true}" class="input-medium"></select>
     </div>
 
@@ -1358,7 +1358,7 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
       <select data-bind="options: chartLimits, value: chartLimit, optionsCaption: '${_ko('Limit the number of results to...')}', select2: { width: '100%', placeholder: '${ _ko("Limit the number of results to...") }', update: chartLimit, dropdownAutoWidth: true}" class="input-medium"></select>
     </div>
 
-    <!-- ko if: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.MAP -->
+    <!-- ko if: chartType() != '' && chartType() == window.HUE_CHARTS.TYPES.MAP -->
     <ul class="nav nav-list" style="border: none; background-color: #FFF">
       <li class="nav-header">${_('type')}</li>
     </ul>
@@ -1388,21 +1388,21 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
     <!-- /ko -->
     <!-- /ko -->
 
-    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
+    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART">
       <li class="nav-header">${_('scatter size')}</li>
     </ul>
-    <div data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
+    <div data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART">
       <select data-bind="options: result.cleanedNumericMeta, value: chartScatterSize, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartScatterSize, dropdownAutoWidth: true}" class="input-medium"></select>
     </div>
 
-    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
+    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART">
       <li class="nav-header">${_('scatter group')}</li>
     </ul>
-    <div data-bind="visible: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
+    <div data-bind="visible: chartType() != '' && chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART">
       <select data-bind="options: result.cleanedMeta, value: chartScatterGroup, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_ko('Choose a column...')}', select2: { width: '100%', placeholder: '${ _ko("Choose a column...") }', update: chartScatterGroup, dropdownAutoWidth: true}" class="input-medium"></select>
     </div>
 
-    <!-- ko if: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP -->
+    <!-- ko if: chartType() != '' && chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP -->
     <ul class="nav nav-list" style="border: none; background-color: #FFF">
       <li class="nav-header">${_('scope')}</li>
     </ul>
@@ -1424,10 +1424,10 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
     </div>
     <!-- /ko -->
 
-    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() != ko.HUE_CHARTS.TYPES.MAP && chartType() != ko.HUE_CHARTS.TYPES.GRADIENTMAP && chartType() != ko.HUE_CHARTS.TYPES.SCATTERCHART">
+    <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() != window.HUE_CHARTS.TYPES.MAP && chartType() != window.HUE_CHARTS.TYPES.GRADIENTMAP && chartType() != window.HUE_CHARTS.TYPES.SCATTERCHART">
       <li class="nav-header">${_('sorting')}</li>
     </ul>
-    <div class="btn-group" data-toggle="buttons-radio" data-bind="visible: chartType() != '' && chartType() != ko.HUE_CHARTS.TYPES.MAP && chartType() != ko.HUE_CHARTS.TYPES.GRADIENTMAP && chartType() != ko.HUE_CHARTS.TYPES.SCATTERCHART">
+    <div class="btn-group" data-toggle="buttons-radio" data-bind="visible: chartType() != '' && chartType() != window.HUE_CHARTS.TYPES.MAP && chartType() != window.HUE_CHARTS.TYPES.GRADIENTMAP && chartType() != window.HUE_CHARTS.TYPES.SCATTERCHART">
       <a rel="tooltip" data-placement="top" title="${_('No sorting')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSorting() == 'none'}, click: function(){ chartSorting('none'); }"><i class="fa fa-align-left fa-rotate-270"></i></a>
       <a rel="tooltip" data-placement="top" title="${_('Sort ascending')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSorting() == 'asc'}, click: function(){ chartSorting('asc'); }"><i class="fa fa-sort-amount-asc fa-rotate-270"></i></a>
       <a rel="tooltip" data-placement="top" title="${_('Sort descending')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSorting() == 'desc'}, click: function(){ chartSorting('desc'); }"><i class="fa fa-sort-amount-desc fa-rotate-270"></i></a>
@@ -1540,39 +1540,39 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
               <h1 class="empty" data-bind="visible: !hasDataForChart()">${ _('Select the chart parameters on the left') }</h1>
 
               <div data-bind="visible: hasDataForChart">
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.PIECHART -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.PIECHART -->
                 <div data-bind="attr:{'id': 'pieChart_'+id()}, pieChart: {data: {counts: result.data, sorting: chartSorting(), snippet: $data, limit: chartLimit()}, fqs: ko.observableArray([]),
-                      transformer: $root.ChartTransformers.pie, maxWidth: 350, parentSelector: '.chart-container' }, visible: chartType() == ko.HUE_CHARTS.TYPES.PIECHART" class="chart"></div>
+                      transformer: $root.ChartTransformers.pie, maxWidth: 350, parentSelector: '.chart-container' }, visible: chartType() == window.HUE_CHARTS.TYPES.PIECHART" class="chart"></div>
                 <!-- /ko -->
 
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.BARCHART -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.BARCHART -->
                 <div data-bind="attr:{'id': 'barChart_'+id()}, barChart: {skipWindowResize: true, datum: {counts: result.data, sorting: chartSorting(), snippet: $data, limit: chartLimit()}, fqs: ko.observableArray([]), hideSelection: true, enableSelection: false, hideStacked: hideStacked,
-                      transformer: $root.ChartTransformers.multiSerie, stacked: false, showLegend: true, isPivot: typeof chartXPivot() !== 'undefined', type: chartTimelineType},  stacked: true, showLegend: true, visible: chartType() == ko.HUE_CHARTS.TYPES.BARCHART" class="chart"></div>
+                      transformer: $root.ChartTransformers.multiSerie, stacked: false, showLegend: true, isPivot: typeof chartXPivot() !== 'undefined', type: chartTimelineType},  stacked: true, showLegend: true, visible: chartType() == window.HUE_CHARTS.TYPES.BARCHART" class="chart"></div>
                 <!-- /ko -->
 
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.LINECHART -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.LINECHART -->
                 <div data-bind="attr:{'id': 'lineChart_'+id()}, lineChart: {datum: {counts: result.data, sorting: chartSorting(), snippet: $data, limit: chartLimit()},
-                      transformer: $root.ChartTransformers.multiSerie, showControls: false, enableSelection: false }, visible: chartType() == ko.HUE_CHARTS.TYPES.LINECHART" class="chart"></div>
+                      transformer: $root.ChartTransformers.multiSerie, showControls: false, enableSelection: false }, visible: chartType() == window.HUE_CHARTS.TYPES.LINECHART" class="chart"></div>
                 <!-- /ko -->
 
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART -->
                 <div data-bind="attr:{'id': 'timelineChart_'+id()}, timelineChart: {type: chartTimelineType, skipWindowResize: true, datum: {counts: result.data, sorting: chartSorting(), snippet: $data, limit: chartLimit()}, fqs: ko.observableArray([]), hideSelection: true, enableSelection: false, hideStacked: hideStacked,
-                      transformer: $root.ChartTransformers.timeline, stacked: false, showLegend: true}, visible: chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART" class="chart"></div>
+                      transformer: $root.ChartTransformers.timeline, stacked: false, showLegend: true}, visible: chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART" class="chart"></div>
                 <!-- /ko -->
 
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.MAP -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.MAP -->
                 <div data-bind="attr:{'id': 'leafletMapChart_'+id()}, leafletMapChart: {datum: {counts: result.data, sorting: chartSorting(), snippet: $data, limit: chartLimit()},
-                      transformer: $root.ChartTransformers.leafletMap, showControls: false, height: 380, visible: chartType() == ko.HUE_CHARTS.TYPES.MAP, forceRedraw: true}" class="chart"></div>
+                      transformer: $root.ChartTransformers.leafletMap, showControls: false, height: 380, visible: chartType() == window.HUE_CHARTS.TYPES.MAP, forceRedraw: true}" class="chart"></div>
                 <!-- /ko -->
 
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP -->
                 <div data-bind="attr:{'id': 'gradientMapChart_'+id()}, mapChart: {data: {counts: result.data, sorting: chartSorting(), snippet: $data, scope: chartScope(), limit: chartLimit()},
-                      transformer: $root.ChartTransformers.map, isScale: true, showControls: false, height: 380, maxWidth: 750, parentSelector: '.chart-container', visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP}" class="chart"></div>
+                      transformer: $root.ChartTransformers.map, isScale: true, showControls: false, height: 380, maxWidth: 750, parentSelector: '.chart-container', visible: chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP}" class="chart"></div>
                 <!-- /ko -->
 
-                <!-- ko if: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART -->
+                <!-- ko if: chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART -->
                 <div data-bind="attr:{'id': 'scatterChart_'+id()}, scatterChart: {datum: {counts: result.data, snippet: $data, limit: chartLimit()},
-                      transformer: $root.ChartTransformers.scatter, maxWidth: 350, y: chartYSingle(), x: chartX(), size: chartScatterSize(), group: chartScatterGroup() }, visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART" class="chart"></div>
+                      transformer: $root.ChartTransformers.scatter, maxWidth: 350, y: chartYSingle(), x: chartX(), size: chartScatterSize(), group: chartScatterGroup() }, visible: chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART" class="chart"></div>
                 <!-- /ko -->
               </div>
             </div>
@@ -1888,12 +1888,12 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
 
     <div class="dropdown">
       <a class="snippet-side-btn" style="padding-right:0" href="javascript: void(0)" data-bind="css: {'active': $data.showChart }, click: function() { $data.showChart(true); }" >
-        <i class="hcha fa-fw hcha-bar-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.BARCHART" title="${ _('Bars') }"></i>
-        <i class="hcha fa-fw hcha-timeline-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART" title="${ _('Time') }"></i>
-        <i class="hcha fa-fw hcha-pie-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.PIECHART" title="${ _('Pie') }"></i>
-        <i class="fa fa-fw fa-dot-circle-o" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART" title="${ _('Scatter') }"></i>
-        <i class="fa fa-fw fa-map-marker" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP" title="${ _('Marker Map') }"></i>
-        <i class="hcha fa-fw hcha-map-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" title="${ _('Gradient Map') }"></i>
+        <i class="hcha fa-fw hcha-bar-chart" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.BARCHART" title="${ _('Bars') }"></i>
+        <i class="hcha fa-fw hcha-timeline-chart" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART" title="${ _('Time') }"></i>
+        <i class="hcha fa-fw hcha-pie-chart" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.PIECHART" title="${ _('Pie') }"></i>
+        <i class="fa fa-fw fa-dot-circle-o" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART" title="${ _('Scatter') }"></i>
+        <i class="fa fa-fw fa-map-marker" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.MAP" title="${ _('Marker Map') }"></i>
+        <i class="hcha fa-fw hcha-map-chart" data-bind="visible: chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP" title="${ _('Gradient Map') }"></i>
       </a>
       <a class="dropdown-toggle snippet-side-btn" style="padding:0" data-toggle="dropdown" href="javascript: void(0)" data-bind="css: {'active': $data.showChart}">
         <i class="fa fa-caret-down"></i>
@@ -1901,32 +1901,32 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
 
       <ul class="dropdown-menu less-padding">
         <li>
-          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.BARCHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.BARCHART); }">
+          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == window.HUE_CHARTS.TYPES.BARCHART}, click: function(){ $data.showChart(true); chartType(window.HUE_CHARTS.TYPES.BARCHART); }">
             <i class="hcha hcha-bar-chart"></i> ${_('Bars')}
           </a>
         </li>
         <li data-bind="visible: result.cleanedDateTimeMeta().length > 0">
-          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.TIMELINECHART); }">
+          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == window.HUE_CHARTS.TYPES.TIMELINECHART}, click: function(){ $data.showChart(true); chartType(window.HUE_CHARTS.TYPES.TIMELINECHART); }">
             <i class="hcha hcha-timeline-chart"></i> ${_('Time')}
           </a>
         </li>
         <li>
-          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.PIECHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.PIECHART); }">
+          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == window.HUE_CHARTS.TYPES.PIECHART}, click: function(){ $data.showChart(true); chartType(window.HUE_CHARTS.TYPES.PIECHART); }">
             <i class="hcha hcha-pie-chart"></i> ${_('Pie')}
           </a>
         </li>
         <li>
-          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.SCATTERCHART); }">
+          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == window.HUE_CHARTS.TYPES.SCATTERCHART}, click: function(){ $data.showChart(true); chartType(window.HUE_CHARTS.TYPES.SCATTERCHART); }">
             <i class="fa fa-fw fa-dot-circle-o chart-icon"></i> ${_('Scatter')}
           </a>
         </li>
         <li>
-          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.MAP}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.MAP); }">
+          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == window.HUE_CHARTS.TYPES.MAP}, click: function(){ $data.showChart(true); chartType(window.HUE_CHARTS.TYPES.MAP); }">
             <i class="fa fa-fw fa-map-marker chart-icon"></i> ${_('Marker Map')}
           </a>
         </li>
         <li>
-          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.GRADIENTMAP); }">
+          <a href="javascript:void(0)" data-bind="css: {'active': chartType() == window.HUE_CHARTS.TYPES.GRADIENTMAP}, click: function(){ $data.showChart(true); chartType(window.HUE_CHARTS.TYPES.GRADIENTMAP); }">
             <i class="hcha hcha-map-chart"></i> ${_('Gradient Map')}
           </a>
         </li>

+ 288 - 0
package-lock.json

@@ -3154,6 +3154,289 @@
       "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
       "dev": true
     },
+    "d3": {
+      "version": "5.7.0",
+      "resolved": "https://registry.npmjs.org/d3/-/d3-5.7.0.tgz",
+      "integrity": "sha512-8KEIfx+dFm8PlbJN9PI0suazrZ41QcaAufsKE9PRcqYPWLngHIyWJZX96n6IQKePGgeSu0l7rtlueSSNq8Zc3g==",
+      "requires": {
+        "d3-array": "1",
+        "d3-axis": "1",
+        "d3-brush": "1",
+        "d3-chord": "1",
+        "d3-collection": "1",
+        "d3-color": "1",
+        "d3-contour": "1",
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-dsv": "1",
+        "d3-ease": "1",
+        "d3-fetch": "1",
+        "d3-force": "1",
+        "d3-format": "1",
+        "d3-geo": "1",
+        "d3-hierarchy": "1",
+        "d3-interpolate": "1",
+        "d3-path": "1",
+        "d3-polygon": "1",
+        "d3-quadtree": "1",
+        "d3-random": "1",
+        "d3-scale": "2",
+        "d3-scale-chromatic": "1",
+        "d3-selection": "1",
+        "d3-shape": "1",
+        "d3-time": "1",
+        "d3-time-format": "2",
+        "d3-timer": "1",
+        "d3-transition": "1",
+        "d3-voronoi": "1",
+        "d3-zoom": "1"
+      },
+      "dependencies": {
+        "d3-scale": {
+          "version": "2.2.2",
+          "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
+          "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
+          "requires": {
+            "d3-array": "^1.2.0",
+            "d3-collection": "1",
+            "d3-format": "1",
+            "d3-interpolate": "1",
+            "d3-time": "1",
+            "d3-time-format": "2"
+          },
+          "dependencies": {
+            "d3-array": {
+              "version": "1.2.4",
+              "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+              "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+            }
+          }
+        }
+      }
+    },
+    "d3-array": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.0.1.tgz",
+      "integrity": "sha1-N1wCh0/NlsFu2fG89bSnvlPzWOc="
+    },
+    "d3-axis": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.3.tgz",
+      "integrity": "sha1-3cvYojwqVo03h94N7gCjZBPF1ZU="
+    },
+    "d3-brush": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.2.tgz",
+      "integrity": "sha1-yacl0Nf31pJFVR/5biZCFeWagus=",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-transition": "1"
+      }
+    },
+    "d3-chord": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.2.tgz",
+      "integrity": "sha1-mxrJDv595EjAuRiDCQcd5ShVqZo=",
+      "requires": {
+        "d3-array": "1",
+        "d3-path": "1"
+      }
+    },
+    "d3-collection": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.1.tgz",
+      "integrity": "sha1-W1xWJvcxEitgCxB9caCIM/7ASa0="
+    },
+    "d3-color": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.1.tgz",
+      "integrity": "sha1-c8yR9O4/EuAMoGsVlqfIPPEEcjo="
+    },
+    "d3-contour": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz",
+      "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==",
+      "requires": {
+        "d3-array": "^1.1.1"
+      },
+      "dependencies": {
+        "d3-array": {
+          "version": "1.2.4",
+          "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+          "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        }
+      }
+    },
+    "d3-dispatch": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.1.tgz",
+      "integrity": "sha1-S9ZaQ87P9DGN653yRVKqi/KBqEA="
+    },
+    "d3-drag": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.0.1.tgz",
+      "integrity": "sha1-Sa2fXJGGVZP7MMhrFfkyLUP+xR8=",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-selection": "1"
+      }
+    },
+    "d3-dsv": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.1.tgz",
+      "integrity": "sha1-1JU0fATLHg0mVXu9xHdcTRGiReo=",
+      "requires": {
+        "rw": "1"
+      }
+    },
+    "d3-ease": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.1.tgz",
+      "integrity": "sha1-oYwtROIY+4uextY1vMpYf4WXmoU="
+    },
+    "d3-fetch": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
+      "integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
+      "requires": {
+        "d3-dsv": "1"
+      }
+    },
+    "d3-force": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.0.2.tgz",
+      "integrity": "sha1-ktvt6s+aLT9mhkUMjWN188Njr2Y=",
+      "requires": {
+        "d3-collection": "1",
+        "d3-dispatch": "1",
+        "d3-quadtree": "1",
+        "d3-timer": "1"
+      }
+    },
+    "d3-format": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.0.2.tgz",
+      "integrity": "sha1-E4YYMgtLvrQ7XA/zBRkHn7vXN14="
+    },
+    "d3-geo": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.2.3.tgz",
+      "integrity": "sha1-myQwp2pyUQ8sSlhi/h8HMFBSxqk=",
+      "requires": {
+        "d3-array": "1"
+      }
+    },
+    "d3-hierarchy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.0.2.tgz",
+      "integrity": "sha1-yPqhHcSbzJORTGqjWka97k4B7nI="
+    },
+    "d3-interpolate": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.1.tgz",
+      "integrity": "sha1-+a1PmkIbIsrYg4z1PZvSy60Lj9c=",
+      "requires": {
+        "d3-color": "1"
+      }
+    },
+    "d3-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.1.tgz",
+      "integrity": "sha1-qMB89jO2vV+XDghjjknll5tBnLU="
+    },
+    "d3-polygon": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.1.tgz",
+      "integrity": "sha1-wecQzHFbCC8YSU0QLkG9qvjETQM="
+    },
+    "d3-quadtree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.1.tgz",
+      "integrity": "sha1-E74CViTxEEBe1DU2xQaq7Bme1ZE="
+    },
+    "d3-random": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.0.1.tgz",
+      "integrity": "sha1-LJREzcuiP4xB95QNRr8wG/mWA+s="
+    },
+    "d3-scale-chromatic": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.3.3.tgz",
+      "integrity": "sha512-BWTipif1CimXcYfT02LKjAyItX5gKiwxuPRgr4xM58JwlLocWbjPLI7aMEjkcoOQXMkYsmNsvv3d2yl/OKuHHw==",
+      "requires": {
+        "d3-color": "1",
+        "d3-interpolate": "1"
+      }
+    },
+    "d3-selection": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.0.2.tgz",
+      "integrity": "sha1-rmYq/UcCrJxdoDmyEHoXZPockHA="
+    },
+    "d3-shape": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.0.2.tgz",
+      "integrity": "sha1-N2VxT4ZFgbV4fQixfseo1i0DGPk=",
+      "requires": {
+        "d3-path": "1"
+      }
+    },
+    "d3-time": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.2.tgz",
+      "integrity": "sha1-JdpkGnBhr49orQjKFzEBcXt0MPw="
+    },
+    "d3-time-format": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.0.2.tgz",
+      "integrity": "sha1-HFN+nUVYlmpljFH0yj3RtHNpwtU=",
+      "requires": {
+        "d3-time": "1"
+      }
+    },
+    "d3-timer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.2.tgz",
+      "integrity": "sha1-br9rvrat1B/FBShKl8x2EaMAKfM="
+    },
+    "d3-transition": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.0.1.tgz",
+      "integrity": "sha1-A/zzTS/xAqF4V2juUt1rnBkK98g=",
+      "requires": {
+        "d3-color": "1",
+        "d3-dispatch": "1",
+        "d3-ease": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-timer": "1"
+      }
+    },
+    "d3-voronoi": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.0.2.tgz",
+      "integrity": "sha1-CbGjp4kcTtg3bZ/9sudwQw8/VcM="
+    },
+    "d3-zoom": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.0.3.tgz",
+      "integrity": "sha1-s2v7UX5TXf8OF5CI2+s9eJmmBQ4=",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-transition": "1"
+      }
+    },
+    "d3v3": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/d3v3/-/d3v3-1.0.3.tgz",
+      "integrity": "sha1-37Ddsh7cPkXD62CzheZYfTFdClk="
+    },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -9373,6 +9656,11 @@
         "aproba": "^1.1.1"
       }
     },
+    "rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
+    },
     "rxjs": {
       "version": "6.4.0",
       "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",

+ 2 - 0
package.json

@@ -25,6 +25,8 @@
   },
   "dependencies": {
     "clipboard": "1.7.1",
+    "d3v3": "1.0.3",
+    "d3": "5.7.0",
     "dropzone": "5.5.1",
     "filesize": "4.0.0",
     "jquery": "3.3.1",

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