Browse Source

HUE-8178 [charts] Move mouseover y values to legend.

jdesjean 7 years ago
parent
commit
51eaac7d9d

+ 13 - 31
desktop/core/src/desktop/static/desktop/js/ko.charts.js

@@ -703,14 +703,15 @@
       }
       }
     }
     }
   };
   };
-  function multi(xAxis) {
-    var previous = null;
+  function multi(xAxis, _chart) {
+    var previous = new Date(9999,11,31);
     var minDiff = 5.1;
     var minDiff = 5.1;
     return d3v3.time.format.utc.multi([
     return d3v3.time.format.utc.multi([
       ["%S %Y-%m-%dT%H:%M", function(d) {
       ["%S %Y-%m-%dT%H:%M", function(d) {
         var domain = xAxis.domain();
         var domain = xAxis.domain();
+        var chart = _chart;
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
-        var isFirst = d == domain[0];
+        var isFirst = previous > d || d == domain[0];
         var result = isFirst && domainDiff < MINUTE_MS * minDiff;
         var result = isFirst && domainDiff < MINUTE_MS * minDiff;
         if (result) {
         if (result) {
           previous = d;
           previous = d;
@@ -720,7 +721,7 @@
       ["%H:%M %Y-%m-%d", function(d) {
       ["%H:%M %Y-%m-%d", function(d) {
         var domain = xAxis.domain();
         var domain = xAxis.domain();
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
-        var isFirst = d == domain[0];
+        var isFirst = previous > d || d == domain[0];
         var result = isFirst && domainDiff < HOUR_MS * minDiff;
         var result = isFirst && domainDiff < HOUR_MS * minDiff;
         if (result) {
         if (result) {
           previous = d;
           previous = d;
@@ -730,7 +731,7 @@
       ["%H:%M %Y-%m-%d", function(d) {
       ["%H:%M %Y-%m-%d", function(d) {
         var domain = xAxis.domain();
         var domain = xAxis.domain();
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
-        var isFirst = d == domain[0];
+        var isFirst = previous > d || d == domain[0];
         var result = isFirst && domainDiff < DAY_MS * minDiff;
         var result = isFirst && domainDiff < DAY_MS * minDiff;
         if (result) {
         if (result) {
           previous = d;
           previous = d;
@@ -740,7 +741,7 @@
       ["%d %Y-%m", function(d) {
       ["%d %Y-%m", function(d) {
         var domain = xAxis.domain();
         var domain = xAxis.domain();
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
-        var isFirst = d == domain[0];
+        var isFirst = previous > d || d == domain[0];
         var result = isFirst && domainDiff < MONTH_MS * minDiff;
         var result = isFirst && domainDiff < MONTH_MS * minDiff;
         if (result) {
         if (result) {
           previous = d;
           previous = d;
@@ -750,7 +751,7 @@
       ["%m %Y", function(d) {
       ["%m %Y", function(d) {
         var domain = xAxis.domain();
         var domain = xAxis.domain();
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
         var domainDiff = Math.abs(domain[domain.length - 1] - domain[0]);
-        var isFirst = d == domain[0];
+        var isFirst = previous > d || d == domain[0];
         var result = isFirst && domainDiff < YEAR_MS * minDiff;
         var result = isFirst && domainDiff < YEAR_MS * minDiff;
         if (result) {
         if (result) {
           previous = d;
           previous = d;
@@ -760,7 +761,7 @@
       ["%Y", function(d) {
       ["%Y", function(d) {
         var test = xAxis;
         var test = xAxis;
         var domain = xAxis.domain();
         var domain = xAxis.domain();
-        var isFirst = d == domain[0];
+        var isFirst = previous > d || d == domain[0];
         var result = isFirst;
         var result = isFirst;
         if (result) {
         if (result) {
           previous = d;
           previous = d;
@@ -839,7 +840,8 @@
         }
         }
         return result;
         return result;
       }],
       }],
-      ["%Y", function() {
+      ["%Y", function(d) {
+        previous = d;
         return true;
         return true;
       }]
       }]
     ]);
     ]);
@@ -891,7 +893,7 @@
               return {x: x, y: y, key: value.key};
               return {x: x, y: y, key: value.key};
             });
             });
           });
           });
-          _chart.xAxis.tickFormat(multi(_chart.xAxis));
+          _chart.xAxis.tickFormat(multi(_chart.xAxis, _chart));
           _chart.onChartUpdate(function () {
           _chart.onChartUpdate(function () {
             _d3.selectAll("g.nv-x.nv-axis g text").each(function (d){
             _d3.selectAll("g.nv-x.nv-axis g text").each(function (d){
               insertLinebreaks(_chart, d, this);
               insertLinebreaks(_chart, d, this);
@@ -899,8 +901,7 @@
           });
           });
         }
         }
 
 
-        _chart.yAxis
-            .tickFormat(d3v3.format(",0f"));
+        _chart.yAxis.tickFormat(d3v3.format("s"));
         handleSelection(_chart, options, _datum);
         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");
         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) {
         if ($(element).find("svg").length < 2) {
@@ -1005,10 +1006,6 @@
     if (fHideStacked) {
     if (fHideStacked) {
       fHideStacked.call(_chart);
       fHideStacked.call(_chart);
     }
     }
-    var fTooltips = _chart.tooltips;
-    if (fTooltips) {
-      fTooltips.call(_chart, _hideStacked);
-    }
     if (_chart.selectBars) {
     if (_chart.selectBars) {
       var _field = (typeof _options.field == "function") ? _options.field() : _options.field;
       var _field = (typeof _options.field == "function") ? _options.field() : _options.field;
       var bHasSelection = false;
       var bHasSelection = false;
@@ -1083,21 +1080,6 @@
           options.onClick(d.point);
           options.onClick(d.point);
         }
         }
       });
       });
-      _chart.multibar.dispatch.on('elementMouseover.tooltip', function(e) {
-        var _hideStacked = options.hideStacked !== null ? typeof options.hideStacked === 'function' ? options.hideStacked() : options.hideStacked : false;
-        if (!_hideStacked) {
-          $('a[href=\'#nv-detail-mouseover\']').tab('show');
-          var values = _chart.tooltipContent()((e.list || [e]).map(function (e) {
-            var x = _chart.multibar.x()(e.point, e.pointIndex),
-            y = _chart.multibar.y()(e.point, e.pointIndex);
-            return {x: x, y: y, key: e.series.key};
-          }));
-          var content = values.map(function (value) {
-            return '<p><b>' + hueUtils.htmlEncode(value.key) + '</b>: ' +  hueUtils.htmlEncode(value.y) + '</p>';
-          }).join("") + '<h3>' + hueUtils.htmlEncode(values[0] && values[0].x) + '</h3>';
-          $('#nv-detail-mouseover .tab-pane-content').html(content);
-        }
-      });
       _chart.onStateChange(options.onStateChange);
       _chart.onStateChange(options.onStateChange);
       if (options.selectedSerie) {
       if (options.selectedSerie) {
         _chart.onLegendChange(function (state) {
         _chart.onLegendChange(function (state) {

+ 57 - 4
desktop/core/src/desktop/static/desktop/js/nv.d3.lineWithBrushChart.js

@@ -47,6 +47,11 @@ nv.models.lineWithBrushChart = function() {
     , useInteractiveGuideline = false
     , useInteractiveGuideline = false
     , tooltips = true
     , tooltips = true
     , tooltip = null
     , tooltip = null
+    , displayValuesInLegend = true
+    , tooltipSimple = function(value) {
+      return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
+        '<p>' + hueUtils.htmlEncode(value.x) + '</p>';
+    }
     , tooltipSingle = function(value) {
     , tooltipSingle = function(value) {
       return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
       return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
         '<p>' + hueUtils.htmlEncode(value.y) + ' on ' + hueUtils.htmlEncode(value.x) + '</p>';
         '<p>' + hueUtils.htmlEncode(value.y) + ' on ' + hueUtils.htmlEncode(value.x) + '</p>';
@@ -100,19 +105,20 @@ nv.models.lineWithBrushChart = function() {
       values = (e.list || [e]).map(function (e) {
       values = (e.list || [e]).map(function (e) {
         var x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
         var x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
         y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex));
         y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex));
-        return {x: x, y: y, key: e.series.key};
+        return {x: x, y: y, key: displayValuesInLegend ? e.point.obj.field : e.series.key};
       });
       });
     } else {
     } else {
       values = tooltip((e.list || [e]).map(function (e) {
       values = tooltip((e.list || [e]).map(function (e) {
         var x = lines.x()(e.point, e.pointIndex),
         var x = lines.x()(e.point, e.pointIndex),
         y = lines.y()(e.point, e.pointIndex);
         y = lines.y()(e.point, e.pointIndex);
-        return {x: x, y: y, key: e.series.key};
+        return {x: x, y: y, key: displayValuesInLegend ? e.point.obj.field : e.series.key};
       }));
       }));
     }
     }
 
 
+
     var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
     var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
         top = e.pos[1] + ( offsetElement.offsetTop || 0),
         top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        content = values.length > 1 && tooltipMultiple(values) || tooltipSingle(values[0]);
+        content = displayValuesInLegend ? tooltipSimple(values[0]) : values.length > 1 && tooltipMultiple(values) || tooltipSingle(values[0]);
 
 
     nv.tooltip.show([left, top], content, null, null, offsetElement);
     nv.tooltip.show([left, top], content, null, null, offsetElement);
   };
   };
@@ -218,7 +224,7 @@ nv.models.lineWithBrushChart = function() {
       // Legend
       // Legend
 
 
       if (showLegend) {
       if (showLegend) {
-        legend.width(legendWidth);
+        legend.width(legendWidth / 2);
         legend.height(availableHeight);
         legend.height(availableHeight);
         legend.rightAlign(false);
         legend.rightAlign(false);
         legend.margin({top: 5, right: 0, left: 10, bottom: 0});
         legend.margin({top: 5, right: 0, left: 10, bottom: 0});
@@ -228,10 +234,30 @@ nv.models.lineWithBrushChart = function() {
             .datum(data)
             .datum(data)
             .call(legend)
             .call(legend)
           .selectAll('text')
           .selectAll('text')
+          .text(function (d) {
+            var addEllipsis = d.key && d.key.length > 12;
+            return d.key && d.key.substring(0, 12) + (addEllipsis ? '...' : '');
+          })
           .append('title')
           .append('title')
           .text(function(d){
           .text(function(d){
             return d.key;
             return d.key;
           });
           });
+          if (displayValuesInLegend) {
+            legendG.selectAll('g.nv-series')
+            .append('text')
+            .classed('nv-series-value', true)
+            .text(function (d, i) {
+              return '';
+            })
+            .attr('dx', 125)
+            .attr('dy', '.32em')
+            .attr('text-anchor', 'end')
+            .append('title')
+            .classed('nv-series-value', true)
+            .text(function (d, i) {
+              return '';
+            });
+          }
         }
         }
         catch (e){}
         catch (e){}
       }
       }
@@ -567,6 +593,7 @@ nv.models.lineWithBrushChart = function() {
             if (!distances[diff]) {
             if (!distances[diff]) {
               distances[diff] = [];
               distances[diff] = [];
             }
             }
+            filteredData[j].values[i].seriesKey = filteredData[j].key;
             distances[diff].push(filteredData[j].values[i]);
             distances[diff].push(filteredData[j].values[i]);
             if (diff < min) {
             if (diff < min) {
               min = diff;
               min = diff;
@@ -583,6 +610,32 @@ nv.models.lineWithBrushChart = function() {
             return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
             return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
           });
           });
         });
         });
+
+        if (el && el.length && displayValuesInLegend) {
+          var legendG = legendSvg.select('.nvd3.nv-wrap.nv-legendWrap');
+          var elBySerie = el.reduce(function (elBySerie, el) {
+            elBySerie[el.seriesKey] = el;
+            return elBySerie;
+          }, {});
+          legendG.selectAll('g.nv-series text.nv-series-value')
+          .text(function (d, i) {
+            if (elBySerie[d.key]) {
+              var value = yAxis.tickFormat()(d.values[elBySerie[d.key].index].y)+'';
+              var addEllipsis = value.length > 5;
+              return value && (addEllipsis ? '...' : '') + value.substring(value.length - 5);
+            } else {
+              return '';
+            }
+          })
+          .append('title')
+          .text(function (d, i) {
+            if (elBySerie[d.key]) {
+              return yAxis.tickFormat()(d.values[elBySerie[d.key].index].y);
+            } else {
+              return '';
+            }
+          });
+        }
         // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
         // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
         var others = container.selectAll('g.nv-wrap.nv-lineChart circle.hover').filter(function(rect) {
         var others = container.selectAll('g.nv-wrap.nv-lineChart circle.hover').filter(function(rect) {
           return !el || !el.some(function(d) {
           return !el || !el.some(function(d) {

+ 58 - 31
desktop/core/src/desktop/static/desktop/js/nv.d3.multiBarWithBrushChart.js

@@ -50,7 +50,12 @@ nv.models.multiBarWithBrushChart = function() {
     , tooltips = true
     , tooltips = true
     , tooltip = null
     , tooltip = null
     , minTickWidth = 60
     , minTickWidth = 60
+    , displayValuesInLegend = true
     , tooltipContent = null
     , tooltipContent = null
+    , tooltipSimple = function(value) {
+      return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
+        '<p>' + hueUtils.htmlEncode(value.x) + '</p>';
+    }
     , tooltipSingle = function(value) {
     , tooltipSingle = function(value) {
       return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
       return '<h3>' + hueUtils.htmlEncode(value.key) + '</h3>' +
         '<p>' + hueUtils.htmlEncode(value.y) + ' on ' + hueUtils.htmlEncode(value.x) + '</p>';
         '<p>' + hueUtils.htmlEncode(value.y) + ' on ' + hueUtils.htmlEncode(value.x) + '</p>';
@@ -112,19 +117,20 @@ nv.models.multiBarWithBrushChart = function() {
       values = (e.list || [e]).map(function (e) {
       values = (e.list || [e]).map(function (e) {
         var x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
         var x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
         y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex));
         y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex));
-        return {x: x, y: y, key: e.series.key};
+        return {x: x, y: y, key: displayValuesInLegend ? e.point.obj.field : e.series.key};
       });
       });
     } else {
     } else {
       values = tooltipContent((e.list || [e]).map(function (e) {
       values = tooltipContent((e.list || [e]).map(function (e) {
         var x = multibar.x()(e.point, e.pointIndex),
         var x = multibar.x()(e.point, e.pointIndex),
         y = multibar.y()(e.point, e.pointIndex);
         y = multibar.y()(e.point, e.pointIndex);
-        return {x: x, y: y, key: e.series.key};
+        return {x: x, y: y, key: displayValuesInLegend ? e.point.obj.field : e.series.key};
       }));
       }));
     }
     }
 
 
+
     var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
     var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
         top = e.pos[1] + ( offsetElement.offsetTop || 0),
         top = e.pos[1] + ( offsetElement.offsetTop || 0),
-        content = values.length > 1 && tooltipMultiple(values) || tooltipSingle(values[0]);
+        content = displayValuesInLegend ? tooltipSimple(values[0]) : values.length > 1 && tooltipMultiple(values) || tooltipSingle(values[0]);
 
 
     nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
     nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
   };
   };
@@ -223,11 +229,6 @@ nv.models.multiBarWithBrushChart = function() {
       gEnter.append('g').attr('class', 'nv-x nv-axis');
       gEnter.append('g').attr('class', 'nv-x nv-axis');
       gEnter.append('g').attr('class', 'nv-y nv-axis');
       gEnter.append('g').attr('class', 'nv-y nv-axis');
       gEnter.append('g').attr('class', 'nv-barsWrap');
       gEnter.append('g').attr('class', 'nv-barsWrap');
-      gEnter.append('g').attr('class', 'nv-mouseover')
-      .append('line')
-      .attr('stroke-dasharray', '5, 5')
-      .style('stroke', 'rgba(0,0,0,0.5)')
-      .style('stroke-width', '1');
       // We put the legend in an another SVG to support scrolling
       // We put the legend in an another SVG to support scrolling
       var legendDiv = d3.select(container.node().parentNode).select('div');
       var legendDiv = d3.select(container.node().parentNode).select('div');
       var legendSvg = legendDiv.select('svg').size() === 0 ? legendDiv.append('svg') : legendDiv.select('svg');
       var legendSvg = legendDiv.select('svg').size() === 0 ? legendDiv.append('svg') : legendDiv.select('svg');
@@ -243,7 +244,7 @@ nv.models.multiBarWithBrushChart = function() {
       // Legend
       // Legend
 
 
       if (showLegend) {
       if (showLegend) {
-        legend.width(legendWidth);
+        legend.width(legendWidth / 2);
         legend.height(availableHeight);
         legend.height(availableHeight);
         legend.rightAlign(false);
         legend.rightAlign(false);
         legend.margin({top: 5, right: 0, left: 10, bottom: 0});
         legend.margin({top: 5, right: 0, left: 10, bottom: 0});
@@ -258,24 +259,29 @@ nv.models.multiBarWithBrushChart = function() {
             .call(legend)
             .call(legend)
           .selectAll('text')
           .selectAll('text')
           .text(function (d) {
           .text(function (d) {
-            return d.key && d.key.substring(0, 15)
+            var value = d.key && d.key + '';
+            var addEllipsis = value && value.length > 12;
+            return value && value.substring(0, 12) + (addEllipsis ? '...' : '');
           })
           })
           .append('title')
           .append('title')
           .text(function(d){
           .text(function(d){
             return d.key;
             return d.key;
           });
           });
-          legendG.selectAll('g.nv-series')
-          .append('text')
-          .text(function (d, i) {
-            return d.values[0].y;
-          })
-          .attr('dx', 125)
-          .attr('dy', '.32em')
-          .attr('text-anchor', 'end')
-          .append('title')
-          .text(function (d, i) {
-            return d.values[0].y;
-          })
+          if (displayValuesInLegend) {
+            legendG.selectAll('g.nv-series')
+            .append('text')
+              .classed('nv-series-value', true)
+              .text(function (d, i) {
+                return '';
+              })
+              .attr('dx', 125)
+              .attr('dy', '.32em')
+              .attr('text-anchor', 'end')
+            .append('title')
+              .text(function (d, i) {
+                return '';
+            });
+          }
         }
         }
         catch (e){}
         catch (e){}
       }
       }
@@ -667,12 +673,32 @@ nv.models.multiBarWithBrushChart = function() {
             return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
             return fGetNumericValue(getX(rect)) === fGetNumericValue(getX(d)) && d.series === rect.series;
           });
           });
         });
         });
-        var mouse_x = d3v3.mouse(this)[0];
-        container.select('g.nv-mouseover line')
-        .attr('x1', mouse_x)
-        .attr('y1', 0)
-        .attr('x2', mouse_x)
-        .attr('y2', availableHeight);
+
+        if (el && el.length && displayValuesInLegend) {
+          var legendG = legendSvg.select('.nvd3.nv-wrap.nv-legendWrap');
+          var elBySerie = el.reduce(function (elBySerie, el) {
+            elBySerie[el.seriesKey] = el;
+            return elBySerie;
+          }, {});
+          legendG.selectAll('g.nv-series text.nv-series-value')
+          .text(function (d, i) {
+            if (elBySerie[d.key]) {
+              var value = yAxis.tickFormat()(d.values[elBySerie[d.key].index].y)+'';
+              var addEllipsis = value.length > 5;
+              return value && (addEllipsis ? '...' : '') + value.substring(value.length - 5);
+            } else {
+              return '';
+            }
+          })
+          .append('title')
+          .text(function (d, i) {
+            if (elBySerie[d.key]) {
+              return yAxis.tickFormat()(d.values[elBySerie[d.key].index].y);
+            } else {
+              return '';
+            }
+          });
+        }
 
 
         // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
         // If there's rectangle with the hover class that are not the target, remove the class and dispatch mouseout
         var others = container.selectAll('g.nv-wrap.nv-multiBarWithLegend rect.hover').filter(function(rect) {
         var others = container.selectAll('g.nv-wrap.nv-multiBarWithLegend rect.hover').filter(function(rect) {
@@ -704,13 +730,14 @@ nv.models.multiBarWithBrushChart = function() {
                 maxi = i;
                 maxi = i;
               }
               }
             });
             });
+            var width = x.rangeBand();
             d3v3.select(target[0][maxi])
             d3v3.select(target[0][maxi])
             .each(function(d, i){
             .each(function(d, i){
               multibar.dispatch.elementMouseover({
               multibar.dispatch.elementMouseover({
                 value: getY(d),
                 value: getY(d),
                 point: d,
                 point: d,
                 series: filteredData[d.series],
                 series: filteredData[d.series],
-                pos: [x(getX(d)) + (x.rangeBand() * (multibar.stacked() ? data.length / 2 : d.series + .5) / data.length), y(getY(d) + (multibar.stacked() ? d.y0 : 0))],  // TODO: Figure out why the value appears to be shifted
+                pos: [x(getX(d)) + width * 0.5, y(getY(d) + (multibar.stacked() ? d.y0 : 0))],
                 pointIndex: i,
                 pointIndex: i,
                 seriesIndex: d.series,
                 seriesIndex: d.series,
                 list: el.map(function (d) {
                 list: el.map(function (d) {
@@ -718,7 +745,7 @@ nv.models.multiBarWithBrushChart = function() {
                     value: getY(d),
                     value: getY(d),
                     point: d,
                     point: d,
                     series: data[d.series],
                     series: data[d.series],
-                    pos: [x(getX(d)) + (x.rangeBand() * (multibar.stacked() ? data.length / 2 : d.series + .5) / data.length), y(getY(d) + (multibar.stacked() ? d.y0 : 0))],  // TODO: Figure out why the value appears to be shifted
+                    pos: [x(getX(d)) + width * 0.5, y(getY(d) + (multibar.stacked() ? d.y0 : 0))],
                     pointIndex: -1,
                     pointIndex: -1,
                     seriesIndex: d.series,
                     seriesIndex: d.series,
                   };
                   };
@@ -738,7 +765,7 @@ nv.models.multiBarWithBrushChart = function() {
               value: getY(d,i),
               value: getY(d,i),
               point: d,
               point: d,
               series: data[d.series],
               series: data[d.series],
-              pointIndex: i,
+              pointIndex: d.index,
               seriesIndex: d.series,
               seriesIndex: d.series,
               e: d3v3.event
               e: d3v3.event
             });
             });

+ 40 - 33
desktop/libs/dashboard/src/dashboard/templates/common_search.mako

@@ -1238,17 +1238,17 @@ ${ dashboard.layout_skeleton(suffix='search') }
     <div class="clearfix"></div>
     <div class="clearfix"></div>
 
 
     <div style="padding-bottom: 10px; text-align: right; padding-right: 20px" data-bind="visible: counts().length > 0">
     <div style="padding-bottom: 10px; text-align: right; padding-right: 20px" data-bind="visible: counts().length > 0">
-      <div data-bind="visible: canZoomIn() || canReset()" class="inline-block">
-        <span class="facet-field-label">${ _('Zoom') }</span>
-        <i class="fa fa-search-minus"></i>
-      </div>
-      <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canZoomIn">
-        <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomIn">${ _('to selection') }</a>
-      </div>
-      <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canReset">
-        <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomOut">${ _('reset') }</a>
-      </div>
       <span data-bind="with: $root.collection.getFacetById($parent.id())">
       <span data-bind="with: $root.collection.getFacetById($parent.id())">
+        <div data-bind="visible: canZoomIn() || canReset()" class="inline-block">
+          <span class="facet-field-label">${ _('Zoom') }</span>
+          <i class="fa fa-search-minus"></i>
+        </div>
+        <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canZoomIn">
+          <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomIn">${ _('to selection') }</a>
+        </div>
+        <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canReset">
+          <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomOut">${ _('reset') }</a>
+        </div>
         <span class="facet-field-label">${ _('Chart Type') }</span>
         <span class="facet-field-label">${ _('Chart Type') }</span>
         <select class="input-small" data-bind="options: $root.timelineChartTypes,
         <select class="input-small" data-bind="options: $root.timelineChartTypes,
                        optionsText: 'label',
                        optionsText: 'label',
@@ -1808,25 +1808,25 @@ ${ dashboard.layout_skeleton(suffix='search') }
       <span data-bind="template: { name: 'facet-toggle2' }"></span>
       <span data-bind="template: { name: 'facet-toggle2' }"></span>
       <div class="pull-right">
       <div class="pull-right">
         <div data-bind="visible: canZoomIn() || canReset()" class="inline-block">
         <div data-bind="visible: canZoomIn() || canReset()" class="inline-block">
-        <span class="facet-field-label">${ _('Zoom') }</span>
-      <i class="fa fa-search-minus"></i>
-      </div>
-      <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canZoomIn">
-        <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomIn">${ _('to selection') }</a>
-      </div>
-      <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canReset">
-        <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomOut">${ _('reset') }</a>
-      </div>
-      <!-- ko if: properties.canRange -->
-      <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px">
-        <span class="facet-field-label">${ _('Chart Type') }</span>
-        <select class="input-small" data-bind="options: $root.timelineChartTypes,
-                     optionsText: 'label',
-                     optionsValue: 'value',
-                     value: properties.timelineChartType">
-        </select>
-      </div>
-      <!-- /ko -->
+          <span class="facet-field-label">${ _('Zoom') }</span>
+          <i class="fa fa-search-minus"></i>
+        </div>
+        <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canZoomIn">
+          <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomIn">${ _('to selection') }</a>
+        </div>
+        <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px" data-bind="visible: canReset">
+          <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomOut">${ _('reset') }</a>
+        </div>
+        <!-- ko if: properties.canRange -->
+        <div class="inline-block" style="padding-bottom: 10px; padding-right: 20px">
+          <span class="facet-field-label">${ _('Chart Type') }</span>
+          <select class="input-small" data-bind="options: $root.timelineChartTypes,
+                       optionsText: 'label',
+                       optionsValue: 'value',
+                       value: properties.timelineChartType">
+          </select>
+        </div>
+        <!-- /ko -->
       </div>
       </div>
       <div class="clearfix"></div>
       <div class="clearfix"></div>
     </div>
     </div>
@@ -3387,6 +3387,7 @@ function _barChartDataTransformer(rawDatum, isUp) {
       if (isUp){
       if (isUp){
         _data.push({
         _data.push({
           series: 0,
           series: 0,
+          index: cnt,
           x: item.from + (item.is_up ? ' & ${ _('Up') }' : ' & ${ _('Less') }'),
           x: item.from + (item.is_up ? ' & ${ _('Up') }' : ' & ${ _('Less') }'),
           y: item.value,
           y: item.value,
           obj: item
           obj: item
@@ -3395,6 +3396,7 @@ function _barChartDataTransformer(rawDatum, isUp) {
       else {
       else {
         _data.push({
         _data.push({
           series: 0,
           series: 0,
+          index: cnt,
           x: item.from,
           x: item.from,
           x_end: item.to,
           x_end: item.to,
           y: item.value,
           y: item.value,
@@ -3405,6 +3407,7 @@ function _barChartDataTransformer(rawDatum, isUp) {
     else {
     else {
       _data.push({
       _data.push({
         series: 0,
         series: 0,
+        index: cnt,
         x: item.value,
         x: item.value,
         y: item.count,
         y: item.count,
         obj: item
         obj: item
@@ -3507,6 +3510,7 @@ function pivotChartDataTransformer(rawDatum) {
 
 
     _category.values.push({
     _category.values.push({
       series: 0,
       series: 0,
+      index: _category.values.length,
       x: item.cat,
       x: item.cat,
       y: item.count,
       y: item.count,
       obj: item
       obj: item
@@ -3570,6 +3574,7 @@ function _timelineChartDataTransformer(rawDatum, isDate) {
     item.widget_id = rawDatum.widget_id;
     item.widget_id = rawDatum.widget_id;
     _data.push({
     _data.push({
       series: 0,
       series: 0,
+      index: cnt,
       x: getValue(item.from ? item.from : item.value), // When started from a non timeline widget
       x: getValue(item.from ? item.from : item.value), // When started from a non timeline widget
       x_end: item.to && getValue(item.to),
       x_end: item.to && getValue(item.to),
       y: item.from !== undefined ? item.value : item.count,
       y: item.from !== undefined ? item.value : item.count,
@@ -3613,8 +3618,8 @@ function _timelineChartDataTransformer(rawDatum, isDate) {
   if (isDate) {
   if (isDate) {
     keys.sort();
     keys.sort();
   }
   }
-  $(rawDatum.extraSeries).each(function (cnt, serie) {
-    if (cnt == 0) {
+  $(rawDatum.extraSeries).each(function (serieIndex, serie) {
+    if (serieIndex == 0) {
       _datum = [];
       _datum = [];
     }
     }
     var _data = [];
     var _data = [];
@@ -3624,7 +3629,8 @@ function _timelineChartDataTransformer(rawDatum, isDate) {
         var item = values[key][serie.label];
         var item = values[key][serie.label];
         item.widget_id = rawDatum.widget_id;
         item.widget_id = rawDatum.widget_id;
         _data.push({
         _data.push({
-          series: cnt + 1,
+          series: serieIndex,
+          index: _data.length,
           x: getValue(item.from ? item.from : item.value), // When started from a non timeline widget
           x: getValue(item.from ? item.from : item.value), // When started from a non timeline widget
           x_end: item.to && getValue(item.to),
           x_end: item.to && getValue(item.to),
           y: item.from !== undefined ? item.value : item.count,
           y: item.from !== undefined ? item.value : item.count,
@@ -3637,7 +3643,8 @@ function _timelineChartDataTransformer(rawDatum, isDate) {
         var copy = JSON.parse(JSON.stringify(item));
         var copy = JSON.parse(JSON.stringify(item));
         copy.value = 0;
         copy.value = 0;
         _data.push({
         _data.push({
-          series: cnt + 1,
+          series: serieIndex,
+          index: _data.length,
           x: getValue(item.from ? item.from : item.value),
           x: getValue(item.from ? item.from : item.value),
           x_end: item.to && getValue(item.to),
           x_end: item.to && getValue(item.to),
           y: copy.value,
           y: copy.value,