Forráskód Böngészése

Heatmap fixes (adapted for v4.4.x branch) (#8920)

* heatmap: fix converting error when series contains 0 and log scale is selected, issue #8884

* heatmap: fix app crash when Y min set to 0 with log scale

* heatmap: fix tooltip for 'zero' buckets in log scale

* heatmap: fix tooltip histogram for log scales

* heatmap: fix flicker of the highlighted element

this was caused by too often fired mouseenter/mouseleave events

* heatmap: fix missing X axis option for log scales

* heatmap: fix missing zero bucket in tooltip histogram
Alexander Zobnin 8 éve
szülő
commit
cb8ecb2d5f

+ 2 - 0
public/app/plugins/panel/heatmap/heatmap_data_converter.ts

@@ -214,12 +214,14 @@ function pushToYBuckets(buckets, bucketNum, value, point, bounds) {
   }
   if (buckets[bucketNum]) {
     buckets[bucketNum].values.push(value);
+    buckets[bucketNum].points.push(point);
     buckets[bucketNum].count += count;
   } else {
     buckets[bucketNum] = {
       y: bucketNum,
       bounds: bounds,
       values: [value],
+      points: [point],
       count: count,
     };
   }

+ 10 - 4
public/app/plugins/panel/heatmap/heatmap_tooltip.ts

@@ -83,7 +83,10 @@ export class HeatmapTooltip {
 
     let boundBottom, boundTop, valuesNumber;
     let xData = data.buckets[xBucketIndex];
-    let yData = xData.buckets[yBucketIndex];
+    // Search in special 'zero' bucket also
+    let yData = _.find(xData.buckets, (bucket, bucketIndex) => {
+      return bucket.bounds.bottom === yBucketIndex || bucketIndex === yBucketIndex;
+    });
 
     let tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
     let time = this.dashboard.formatDate(xData.x, tooltipTimeFormat);
@@ -105,7 +108,9 @@ export class HeatmapTooltip {
 
     if (yData) {
       if (yData.bounds) {
-        boundBottom = valueFormatter(yData.bounds.bottom);
+        // Display 0 if bucket is a special 'zero' bucket
+        let bottom = yData.y ? yData.bounds.bottom : 0;
+        boundBottom = valueFormatter(bottom);
         boundTop = valueFormatter(yData.bounds.top);
         valuesNumber = yData.count;
         tooltipHtml += `<div>
@@ -165,7 +170,7 @@ export class HeatmapTooltip {
     let yBucketSize = this.scope.ctrl.data.yBucketSize;
     let {min, max, ticks} = this.scope.ctrl.data.yAxis;
     let histogramData = _.map(xBucket.buckets, bucket => {
-      return [bucket.y, bucket.values.length];
+      return [bucket.bounds.bottom, bucket.values.length];
     });
     histogramData = _.filter(histogramData, d => {
       return d[0] >= min && d[0] <= max;
@@ -180,7 +185,8 @@ export class HeatmapTooltip {
     if (this.panel.yAxis.logBase === 1) {
       barWidth = Math.floor(HISTOGRAM_WIDTH / (max - min) * yBucketSize * 0.9);
     } else {
-      barWidth = Math.floor(HISTOGRAM_WIDTH / ticks / yBucketSize * 0.9);
+      let barNumberFactor = yBucketSize ? yBucketSize : 1;
+      barWidth = Math.floor(HISTOGRAM_WIDTH / ticks / barNumberFactor * 0.9);
     }
     barWidth = Math.max(barWidth, 1);
 

+ 32 - 34
public/app/plugins/panel/heatmap/partials/axes_editor.html

@@ -33,43 +33,26 @@
 
   <div class="section gf-form-group" ng-if="ctrl.panel.dataFormat == 'timeseries'">
     <h5 class="section-heading">Buckets</h5>
-    <div ng-show="ctrl.panel.yAxis.logBase === 1">
-      <div class="gf-form-inline">
-        <div class="gf-form">
-          <label class="gf-form-label">Y Axis</label>
-          <label class="gf-form-label">Buckets</label>
-          <input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
-                                                                                bs-tooltip="'Number of buckets for Y axis.'"
-                                                                                ng-model="ctrl.panel.yBucketNumber" ng-change="ctrl.refresh()" ng-model-onblur>
-        </div>
-        <div class="gf-form">
-          <label class="gf-form-label">Size</label>
-          <input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
-                                                                                bs-tooltip="'Size of bucket. Has priority over Buckets option.'"
-                                                                                ng-model="ctrl.panel.yBucketSize" ng-change="ctrl.refresh()" ng-model-onblur>
-        </div>
+    <div class="gf-form-inline">
+      <div class="gf-form">
+        <label class="gf-form-label width-5">Y Axis</label>
       </div>
-      <div class="gf-form-inline">
-        <div class="gf-form">
-          <label class="gf-form-label">X Axis</label>
-          <label class="gf-form-label">Buckets</label>
-          <input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
-                                                                                bs-tooltip="'Number of buckets for Y axis.'"
-                                                                                ng-model="ctrl.panel.xBucketNumber" ng-change="ctrl.refresh()" ng-model-onblur>
-        </div>
-        <div class="gf-form">
-          <label class="gf-form-label">Size</label>
-          <input type="text" class="gf-form-input width-5" placeholder="auto" data-placement="right"
-                                                                              bs-tooltip="'Size of bucket. Number or interval (10s, 5m, 1h, etc). Supported intervals: ms, s, m, h, d, w, M, y. Has priority over Buckets option.'"
-                                                                              ng-model="ctrl.panel.xBucketSize" ng-change="ctrl.refresh()" ng-model-onblur>
-        </div>
+      <div class="gf-form" ng-show="ctrl.panel.yAxis.logBase === 1">
+        <label class="gf-form-label width-5">Buckets</label>
+        <input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
+                                                                              bs-tooltip="'Number of buckets for Y axis.'"
+                                                                              ng-model="ctrl.panel.yBucketNumber" ng-change="ctrl.refresh()" ng-model-onblur>
       </div>
-    </div>
-    <div ng-show="ctrl.panel.yAxis.logBase !== 1">
-      <div class="gf-form">
-        <label class="gf-form-label width-7">Split Factor</label>
+      <div class="gf-form" ng-show="ctrl.panel.yAxis.logBase === 1">
+        <label class="gf-form-label width-4">Size</label>
+        <input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
+                                                                              bs-tooltip="'Size of bucket. Has priority over Buckets option.'"
+                                                                              ng-model="ctrl.panel.yBucketSize" ng-change="ctrl.refresh()" ng-model-onblur>
+      </div>
+      <div class="gf-form" ng-show="ctrl.panel.yAxis.logBase !== 1">
+        <label class="gf-form-label width-10">Split Factor</label>
         <input type="number"
-               class="gf-form-input width-3"
+               class="gf-form-input width-9"
                placeholder="1"
                data-placement="right"
                bs-tooltip="'For log scales only. By default Y values is splitted by integer powers of log base (1, 2, 4, 8, 16, ... for log2). This option allows to split each default bucket into specified number of buckets.'"
@@ -77,6 +60,21 @@
         </input>
       </div>
     </div>
+    <div class="gf-form-inline">
+      <div class="gf-form">
+        <label class="gf-form-label width-5">X Axis</label>
+        <label class="gf-form-label width-5">Buckets</label>
+        <input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
+                                                                              bs-tooltip="'Number of buckets for X axis.'"
+                                                                              ng-model="ctrl.panel.xBucketNumber" ng-change="ctrl.refresh()" ng-model-onblur>
+      </div>
+      <div class="gf-form">
+        <label class="gf-form-label width-4">Size</label>
+        <input type="text" class="gf-form-input width-5" placeholder="auto" data-placement="right"
+                                                                            bs-tooltip="'Size of bucket. Number or interval (10s, 5m, 1h, etc). Supported intervals: ms, s, m, h, d, w, M, y. Has priority over Buckets option.'"
+                                                                            ng-model="ctrl.panel.xBucketSize" ng-change="ctrl.refresh()" ng-model-onblur>
+      </div>
+    </div>
   </div>
 
   <div class="section gf-form-group">

+ 1 - 1
public/app/plugins/panel/heatmap/rendering.ts

@@ -210,7 +210,7 @@ export default function link(scope, elem, attrs, ctrl) {
     let log_base = panel.yAxis.logBase;
     let {y_min, y_max} = adjustLogRange(data.heatmapStats.minLog, data.heatmapStats.max, log_base);
 
-    y_min = panel.yAxis.min !== null ? adjustLogMin(panel.yAxis.min, log_base) : y_min;
+    y_min = panel.yAxis.min && panel.yAxis.min !== '0' ? adjustLogMin(panel.yAxis.min, log_base) : y_min;
     y_max = panel.yAxis.max !== null ? adjustLogMax(panel.yAxis.max, log_base) : y_max;
 
     // Set default Y min and max if no data

+ 9 - 0
public/sass/components/_panel_heatmap.scss

@@ -18,6 +18,15 @@
       stroke: $text-color-weak;
     }
   }
+
+  // This hack prevents mouseenter/mouseleave events get fired too often
+  svg {
+    pointer-events: none;
+
+    rect {
+      pointer-events: visiblePainted;
+    }
+  }
 }
 
 .heatmap-tooltip {