mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'v4.4.x'
This commit is contained in:
commit
22758d5112
@ -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>
|
||||
<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>
|
||||
</div>
|
||||
<div ng-show="ctrl.panel.yAxis.logBase !== 1">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">Split Factor</label>
|
||||
<label class="gf-form-label width-5">Y Axis</label>
|
||||
</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 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 {
|
||||
|
68
public/vendor/flot/jquery.flot.gauge.js
vendored
68
public/vendor/flot/jquery.flot.gauge.js
vendored
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user