Commit 22758d51 by Daniel Lee

Merge branch 'v4.4.x'

parents c4683f1a 7b768bca
......@@ -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,
};
}
......
......@@ -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);
......
......@@ -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">
......
......@@ -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
......
......@@ -14,11 +14,27 @@ describe('grafanaSingleStat', function() {
expect(getColorForValue(data, 5)).to.be('green');
});
it('25 should return green', () => {
it('19.9 should return green', () => {
expect(getColorForValue(data, 19.9)).to.be('green');
});
it('20 should return yellow', () => {
expect(getColorForValue(data, 20)).to.be('yellow');
});
it('20.1 should return yellow', () => {
expect(getColorForValue(data, 20.1)).to.be('yellow');
});
it('25 should return yellow', () => {
expect(getColorForValue(data, 25)).to.be('yellow');
});
it('55 should return green', () => {
it('50 should return red', () => {
expect(getColorForValue(data, 50)).to.be('red');
});
it('55 should return red', () => {
expect(getColorForValue(data, 55)).to.be('red');
});
});
......
......@@ -108,7 +108,7 @@ describe('SingleStatCtrl', function() {
});
});
singleStatScenario('When range to text mapping is specifiedfor first range', function(ctx) {
singleStatScenario('When range to text mapping is specified for first range', function(ctx) {
ctx.setup(function() {
ctx.data = [
{target: 'test.cpu1', datapoints: [[41,50]]}
......
......@@ -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 {
......
......@@ -85,17 +85,17 @@
* @return the calculated layout properties
*/
Gauge.prototype.calculateLayout = function() {
var canvasWidth = placeholder.width();
var canvasHeight = placeholder.height();
// calculate cell size
var columns = Math.min(series.length, gaugeOptions.layout.columns);
var rows = Math.ceil(series.length / columns);
var margin = gaugeOptions.layout.margin;
var hMargin = gaugeOptions.layout.hMargin;
......@@ -107,8 +107,8 @@
cellWidth = cell;
cellHeight = cell;
}
// calculate 'auto' values
calculateAutoValues(gaugeOptions, cellWidth);
......@@ -155,13 +155,13 @@
var maxRadiusV = outerRadiusV - (thresholdLabelMargin * 2) - thresholdLabelFontSize - thresholdWidth;
var radius = Math.min(maxRadiusH, maxRadiusV);
var width = gaugeOptions.gauge.width;
if (width >= radius) {
width = Math.max(3, radius / 3);
}
var outerRadius = (thresholdLabelMargin * 2) + thresholdLabelFontSize + thresholdWidth + radius;
var gaugeOuterHeight = Math.max(outerRadius * (1 + heightRatioV), outerRadius + valueMargin + (valueFontSize / 2));
......@@ -198,7 +198,7 @@
* @param {Number} cellWidth the width of cell
*/
function calculateAutoValues(gaugeOptionsi, cellWidth) {
if (gaugeOptionsi.gauge.width === "auto") {
gaugeOptionsi.gauge.width = Math.max(5, cellWidth / 8);
}
......@@ -223,7 +223,7 @@
if (gaugeOptionsi.threshold.label.font.size === "auto") {
gaugeOptionsi.threshold.label.font.size = Math.max(5, cellWidth / 15);
}
}
Gauge.prototype.calculateAutoValues = calculateAutoValues;
......@@ -237,7 +237,7 @@
* @return the calculated cell layout properties
*/
Gauge.prototype.calculateCellLayout = function(gaugeOptionsi, layout, i) {
// calculate top, left and center
var c = col(layout.columns, i);
var r = row(layout.columns, i);
......@@ -276,7 +276,7 @@
* @param {Object} layout the layout properties
*/
Gauge.prototype.drawBackground = function(layout) {
if (!gaugeOptions.frame.show) {
return;
}
......@@ -299,7 +299,7 @@
* @param {Object} cellLayout the cell layout properties
*/
Gauge.prototype.drawCellBackground = function(gaugeOptionsi, cellLayout) {
context.save();
if (gaugeOptionsi.cell.border && gaugeOptionsi.cell.border.show && gaugeOptionsi.cell.border.color && gaugeOptionsi.cell.border.width) {
context.strokeStyle = gaugeOptionsi.cell.border.color;
......@@ -324,10 +324,10 @@
* @param {Number} data the value of the gauge
*/
Gauge.prototype.drawGauge = function(gaugeOptionsi, layout, cellLayout, label, data) {
var blur = gaugeOptionsi.gauge.shadow.show ? gaugeOptionsi.gauge.shadow.blur : 0;
// draw gauge frame
drawArcWithShadow(
......@@ -371,7 +371,7 @@
for (var i = 0; i < gaugeOptionsi.threshold.values.length; i++) {
var threshold = gaugeOptionsi.threshold.values[i];
color = threshold.color;
if (data <= threshold.value) {
if (data < threshold.value) {
break;
}
}
......@@ -410,7 +410,7 @@
* @param {Object} cellLayout the cell layout properties
*/
Gauge.prototype.drawThreshold = function(gaugeOptionsi, layout, cellLayout) {
var a1 = gaugeOptionsi.gauge.startAngle;
for (var i = 0; i < gaugeOptionsi.threshold.values.length; i++) {
var threshold = gaugeOptionsi.threshold.values[i];
......@@ -478,7 +478,7 @@
* @param {Object} item the item of the series
*/
Gauge.prototype.drawLable = function(gaugeOptionsi, layout, cellLayout, i, item) {
drawText(
cellLayout.cx,
cellLayout.y + cellLayout.cellMargin + layout.labelMargin + cellLayout.offsetY,
......@@ -498,7 +498,7 @@
* @param {Object} item the item of the series
*/
Gauge.prototype.drawValue = function(gaugeOptionsi, layout, cellLayout, i, item) {
drawText(
cellLayout.cx,
cellLayout.cy - (gaugeOptionsi.value.font.size / 2),
......@@ -517,7 +517,7 @@
* @param {Number} i the index of the series
*/
Gauge.prototype.drawThresholdValues = function(gaugeOptionsi, layout, cellLayout, i) {
// min, max
drawThresholdValue(gaugeOptionsi, layout, cellLayout, "Min" + i, gaugeOptionsi.gauge.min, gaugeOptionsi.gauge.startAngle);
drawThresholdValue(gaugeOptionsi, layout, cellLayout, "Max" + i, gaugeOptionsi.gauge.max, gaugeOptionsi.gauge.endAngle);
......@@ -729,8 +729,8 @@
plot.hooks.processOptions.push(function(plot, options) {
var logger = getLogger(options.series.gauges.debug);
// turn 'grid' and 'legend' off
if (options.series.gauges.show) {
......@@ -740,7 +740,7 @@
// sort threshold
var thresholds = options.series.gauges.threshold.values;
thresholds.sort(function(a, b) {
if (a.value < b.value) {
return -1;
......@@ -750,9 +750,9 @@
return 0;
}
});
});
// add draw hook
......@@ -761,14 +761,14 @@
var gaugeOptions = options.series.gauges;
var logger = getLogger(gaugeOptions.debug);
if (!gaugeOptions.show) {
return;
}
var series = plot.getData();
if (!series || !series.length) {
return; // if no series were passed
}
......@@ -777,10 +777,10 @@
// calculate layout
var layout = gauge.calculateLayout();
// debug layout
if (gaugeOptions.debug.layout) {
}
// draw background
......@@ -789,21 +789,21 @@
// draw cells (label, gauge, value, threshold)
for (var i = 0; i < series.length; i++) {
var item = series[i];
var gaugeOptionsi = $.extend({}, gaugeOptions, item.gauges);
if (item.gauges) {
// re-calculate 'auto' values
gauge.calculateAutoValues(gaugeOptionsi, layout.cellWidth);
}
// calculate cell layout
var cellLayout = gauge.calculateCellLayout(gaugeOptionsi, layout, i);
// draw cell background
gauge.drawCellBackground(gaugeOptionsi, cellLayout)
// debug layout
if (gaugeOptionsi.debug.layout) {
}
// draw label
if (gaugeOptionsi.label.show) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment