Merged yaxis_precision branch, #877, updated changelog

This commit is contained in:
Torkel Ödegaard 2014-09-29 12:38:52 +02:00
commit af4f3f62e9
6 changed files with 98 additions and 348 deletions

View File

@ -1,4 +1,5 @@
# 1.9.0 (unreleased)
- [Issue #877](https://github.com/grafana/grafana/issues/877). Graph: Smart auto decimal precision when using scaled unit formats
# 1.8.1 (unreleased)

View File

@ -7,6 +7,7 @@ function($, _, moment) {
'use strict';
var kbn = {};
kbn.valueFormats = {};
kbn.round_interval = function(interval) {
switch (true) {
@ -309,240 +310,27 @@ function($, _, moment) {
].join(';') + '"></div>';
};
kbn.byteFormat = function(size, decimals) {
var ext, steps = 0;
if(_.isUndefined(decimals)) {
decimals = 2;
} else if (decimals === 0) {
decimals = undefined;
}
while (Math.abs(size) >= 1024) {
steps++;
size /= 1024;
}
switch (steps) {
case 0:
ext = " B";
break;
case 1:
ext = " KiB";
break;
case 2:
ext = " MiB";
break;
case 3:
ext = " GiB";
break;
case 4:
ext = " TiB";
break;
case 5:
ext = " PiB";
break;
case 6:
ext = " EiB";
break;
case 7:
ext = " ZiB";
break;
case 8:
ext = " YiB";
break;
}
return (size.toFixed(decimals) + ext);
kbn.valueFormats.percent = function(size, decimals) {
return kbn.toFixed(size, decimals) + '%';
};
kbn.bitFormat = function(size, decimals) {
var ext, steps = 0;
kbn.formatFuncCreator = function(factor, extArray) {
return function(size, decimals, scaledDecimals) {
var steps = 0;
if(_.isUndefined(decimals)) {
decimals = 2;
} else if (decimals === 0) {
decimals = undefined;
}
while (Math.abs(size) >= factor) {
steps++;
size /= factor;
}
if (steps > 0) {
decimals = scaledDecimals + (3 * steps);
}
while (Math.abs(size) >= 1024) {
steps++;
size /= 1024;
}
switch (steps) {
case 0:
ext = " b";
break;
case 1:
ext = " Kib";
break;
case 2:
ext = " Mib";
break;
case 3:
ext = " Gib";
break;
case 4:
ext = " Tib";
break;
case 5:
ext = " Pib";
break;
case 6:
ext = " Eib";
break;
case 7:
ext = " Zib";
break;
case 8:
ext = " Yib";
break;
}
return (size.toFixed(decimals) + ext);
return kbn.toFixed(size, decimals) + extArray[steps];
};
};
kbn.bpsFormat = function(size, decimals) {
var ext, steps = 0;
if(_.isUndefined(decimals)) {
decimals = 2;
} else if (decimals === 0) {
decimals = undefined;
}
while (Math.abs(size) >= 1000) {
steps++;
size /= 1000;
}
switch (steps) {
case 0:
ext = " bps";
break;
case 1:
ext = " Kbps";
break;
case 2:
ext = " Mbps";
break;
case 3:
ext = " Gbps";
break;
case 4:
ext = " Tbps";
break;
case 5:
ext = " Pbps";
break;
case 6:
ext = " Ebps";
break;
case 7:
ext = " Zbps";
break;
case 8:
ext = " Ybps";
break;
}
return (size.toFixed(decimals) + ext);
};
kbn.shortFormat = function(size, decimals) {
var ext, steps = 0;
if(_.isUndefined(decimals)) {
decimals = 2;
} else if (decimals === 0) {
decimals = undefined;
}
while (Math.abs(size) >= 1000) {
steps++;
size /= 1000;
}
switch (steps) {
case 0:
ext = "";
break;
case 1:
ext = " K";
break;
case 2:
ext = " Mil";
break;
case 3:
ext = " Bil";
break;
case 4:
ext = " Tri";
break;
case 5:
ext = " Quadr";
break;
case 6:
ext = " Quint";
break;
case 7:
ext = " Sext";
break;
case 8:
ext = " Sept";
break;
}
return (size.toFixed(decimals) + ext);
};
kbn.getFormatFunction = function(formatName, decimals) {
switch(formatName) {
case 'short':
return function(val) {
return kbn.shortFormat(val, decimals);
};
case 'bytes':
return function(val) {
return kbn.byteFormat(val, decimals);
};
case 'bits':
return function(val) {
return kbn.bitFormat(val, decimals);
};
case 'bps':
return function(val) {
return kbn.bpsFormat(val, decimals);
};
case 's':
return function(val) {
return kbn.sFormat(val, decimals);
};
case 'ms':
return function(val) {
return kbn.msFormat(val, decimals);
};
case 'µs':
return function(val) {
return kbn.microsFormat(val, decimals);
};
case 'ns':
return function(val) {
return kbn.nanosFormat(val, decimals);
};
case 'percent':
return function(val, axis) {
return kbn.noneFormat(val, axis ? axis.tickDecimals : null) + ' %';
};
default:
return function(val, axis) {
return kbn.noneFormat(val, axis ? axis.tickDecimals : null);
};
}
};
kbn.noneFormat = function(value, decimals) {
kbn.toFixed = function(value, decimals) {
var factor = decimals ? Math.pow(10, decimals) : 1;
var formatted = String(Math.round(value * factor) / factor);
@ -553,7 +341,6 @@ function($, _, moment) {
// If tickDecimals was specified, ensure that we have exactly that
// much precision; otherwise default to the value's own precision.
if (decimals != null) {
var decimalPos = formatted.indexOf(".");
var precision = decimalPos === -1 ? 0 : formatted.length - decimalPos - 1;
@ -565,97 +352,87 @@ function($, _, moment) {
return formatted;
};
kbn.msFormat = function(size, decimals) {
// Less than 1 milli, downscale to micro
if (size !== 0 && Math.abs(size) < 1) {
return kbn.microsFormat(size * 1000, decimals);
}
else if (Math.abs(size) < 1000) {
return size.toFixed(decimals) + " ms";
kbn.valueFormats.bits = kbn.formatFuncCreator(1024, [' b', ' Kib', ' Mib', ' Gib', ' Tib', ' Pib', ' Eib', ' Zib', ' Yib']);
kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']);
kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Qaudr', ' Quint', ' Sext', ' Sept']);
kbn.valueFormats.none = kbn.toFixed;
kbn.valueFormats.ms = function(size, decimals, scaledDecimals) {
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + " ms";
}
// Less than 1 min
else if (Math.abs(size) < 60000) {
return (size / 1000).toFixed(decimals) + " s";
return kbn.toFixed(size / 1000, scaledDecimals + 3) + " s";
}
// Less than 1 hour, devide in minutes
else if (Math.abs(size) < 3600000) {
return (size / 60000).toFixed(decimals) + " min";
return kbn.toFixed(size / 60000, scaledDecimals + 5) + " min";
}
// Less than one day, devide in hours
else if (Math.abs(size) < 86400000) {
return (size / 3600000).toFixed(decimals) + " hour";
return kbn.toFixed(size / 3600000, scaledDecimals + 7) + " hour";
}
// Less than one year, devide in days
else if (Math.abs(size) < 31536000000) {
return (size / 86400000).toFixed(decimals) + " day";
return kbn.toFixed(size / 86400000, scaledDecimals + 8) + " day";
}
return (size / 31536000000).toFixed(decimals) + " year";
return kbn.toFixed(size / 31536000000, scaledDecimals + 10) + " year";
};
kbn.sFormat = function(size, decimals) {
// Less than 1 sec, downscale to milli
if (size !== 0 && Math.abs(size) < 1) {
return kbn.msFormat(size * 1000, decimals);
}
// Less than 10 min, use seconds
else if (Math.abs(size) < 600) {
return size.toFixed(decimals) + " s";
kbn.valueFormats.s = function(size, decimals, scaledDecimals) {
if (Math.abs(size) < 600) {
return kbn.toFixed(size, decimals) + " s";
}
// Less than 1 hour, devide in minutes
else if (Math.abs(size) < 3600) {
return (size / 60).toFixed(decimals) + " min";
return kbn.toFixed(size / 60, scaledDecimals + 1) + " min";
}
// Less than one day, devide in hours
else if (Math.abs(size) < 86400) {
return (size / 3600).toFixed(decimals) + " hour";
return kbn.toFixed(size / 3600, scaledDecimals + 4) + " hour";
}
// Less than one week, devide in days
else if (Math.abs(size) < 604800) {
return (size / 86400).toFixed(decimals) + " day";
return kbn.toFixed(size / 86400, scaledDecimals + 5) + " day";
}
// Less than one year, devide in week
else if (Math.abs(size) < 31536000) {
return (size / 604800).toFixed(decimals) + " week";
return kbn.toFixed(size / 604800, scaledDecimals + 6) + " week";
}
return (size / 3.15569e7).toFixed(decimals) + " year";
return kbn.toFixed(size / 3.15569e7, scaledDecimals + 7) + " year";
};
kbn.microsFormat = function(size, decimals) {
// Less than 1 micro, downscale to nano
if (size !== 0 && Math.abs(size) < 1) {
return kbn.nanosFormat(size * 1000, decimals);
}
else if (Math.abs(size) < 1000) {
return size.toFixed(decimals) + " µs";
kbn.valueFormats['µs'] = function(size, decimals, scaledDecimals) {
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + " µs";
}
else if (Math.abs(size) < 1000000) {
return (size / 1000).toFixed(decimals) + " ms";
return kbn.toFixed(size / 1000, scaledDecimals + 3) + " ms";
}
else {
return (size / 1000000).toFixed(decimals) + " s";
return kbn.toFixed(size / 1000000, scaledDecimals + 6) + " s";
}
};
kbn.nanosFormat = function(size, decimals) {
if (Math.abs(size) < 1) {
return size.toFixed(decimals) + " ns";
}
else if (Math.abs(size) < 1000) {
return size.toFixed(0) + " ns";
kbn.valueFormats.ns = function(size, decimals, scaledDecimals) {
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + " ns";
}
else if (Math.abs(size) < 1000000) {
return (size / 1000).toFixed(decimals) + " µs";
return kbn.toFixed(size / 1000, scaledDecimals + 3) + " µs";
}
else if (Math.abs(size) < 1000000000) {
return (size / 1000000).toFixed(decimals) + " ms";
return kbn.toFixed(size / 1000000, scaledDecimals + 6) + " ms";
}
else if (Math.abs(size) < 60000000000){
return (size / 1000000000).toFixed(decimals) + " s";
return kbn.toFixed(size / 1000000000, scaledDecimals + 9) + " s";
}
else {
return (size / 60000000000).toFixed(decimals) + " m";
return kbn.toFixed(size / 60000000000, scaledDecimals + 12) + " m";
}
};

View File

@ -54,7 +54,7 @@ function (_, kbn) {
}
};
TimeSeries.prototype.getFlotPairs = function (fillStyle, yFormats) {
TimeSeries.prototype.getFlotPairs = function (fillStyle) {
var result = [];
this.color = this.info.color;
@ -100,21 +100,21 @@ function (_, kbn) {
}
if (result.length) {
this.info.avg = (this.info.total / result.length);
this.info.current = result[result.length-1][1];
var formater = kbn.getFormatFunction(yFormats[this.yaxis - 1], 2);
this.info.avg = this.info.avg != null ? formater(this.info.avg) : null;
this.info.current = this.info.current != null ? formater(this.info.current) : null;
this.info.min = this.info.min != null ? formater(this.info.min) : null;
this.info.max = this.info.max != null ? formater(this.info.max) : null;
this.info.total = this.info.total != null ? formater(this.info.total) : null;
}
return result;
};
TimeSeries.prototype.updateLegendValues = function(formater, decimals, scaledDecimals) {
this.info.avg = this.info.avg != null ? formater(this.info.avg, decimals, scaledDecimals) : null;
this.info.current = this.info.current != null ? formater(this.info.current, decimals, scaledDecimals) : null;
this.info.min = this.info.min != null ? formater(this.info.min, decimals, scaledDecimals) : null;
this.info.max = this.info.max != null ? formater(this.info.max, decimals, scaledDecimals) : null;
this.info.total = this.info.total != null ? formater(this.info.total, decimals, scaledDecimals) : null;
};
return TimeSeries;
});

View File

@ -80,6 +80,18 @@ function (angular, $, kbn, moment, _) {
}
}
function updateLegendValues(plot) {
var yaxis = plot.getYAxes();
for (var i = 0; i < data.length; i++) {
var series = data[i];
var axis = yaxis[series.yaxis - 1];
var formater = kbn.valueFormats[scope.panel.y_formats[series.yaxis - 1]];
series.updateLegendValues(formater, axis.tickDecimals, axis.scaledDecimals);
}
}
// Function for rendering panel
function render_panel() {
if (shouldAbortRender()) {
@ -91,6 +103,7 @@ function (angular, $, kbn, moment, _) {
// Populate element
var options = {
hooks: { draw: [updateLegendValues] },
legend: { show: false },
series: {
stackpercent: panel.stack ? panel.percentage : false,
@ -299,7 +312,9 @@ function (angular, $, kbn, moment, _) {
}
function configureAxisMode(axis, format) {
axis.tickFormatter = kbn.getFormatFunction(format, 1);
axis.tickFormatter = function(val, axis) {
return kbn.valueFormats[format](val, axis.tickDecimals, axis.scaledDecimals);
};
}
function time_format(interval, ticks, min, max) {
@ -349,7 +364,7 @@ function (angular, $, kbn, moment, _) {
value = item.datapoint[1];
}
value = kbn.getFormatFunction(format, 2)(value, item.series.yaxis);
value = kbn.valueFormats[format](value, item.series.yaxis.tickDecimals);
timestamp = dashboard.formatDate(item.datapoint[0]);
$tooltip.html(group + value + " @ " + timestamp).place_tt(pos.pageX, pos.pageY);

View File

@ -3,76 +3,31 @@ define([
], function(kbn) {
'use strict';
describe('millisecond formating', function() {
function describeValueFormat(desc, value, tickSize, tickDecimals, result) {
it('should translate 4378634603 as 1.67 years', function() {
var str = kbn.msFormat(4378634603, 2);
expect(str).to.be('50.68 day');
describe('value format: ' + desc, function() {
it('should translate ' + value + ' as ' + result, function() {
var scaledDecimals = tickDecimals - Math.floor(Math.log(tickSize) / Math.LN10);
var str = kbn.valueFormats[desc](value, tickDecimals, scaledDecimals);
expect(str).to.be(result);
});
});
it('should translate 3654454 as 1.02 hour', function() {
var str = kbn.msFormat(3654454, 2);
expect(str).to.be('1.02 hour');
});
}
it('should not downscale when value is zero', function() {
var str = kbn.msFormat(0, 2);
expect(str).to.be('0.00 ms');
});
describeValueFormat('ms', 0.0024, 0.0005, 4, '0.0024 ms');
describeValueFormat('ms', 100, 1, 0, '100 ms');
describeValueFormat('ms', 1250, 10, 0, '1.25 s');
describeValueFormat('ms', 1250, 300, 0, '1.3 s');
describeValueFormat('ms', 65150, 10000, 0, '1.1 min');
describeValueFormat('ms', 6515000, 1500000, 0, '1.8 hour');
describeValueFormat('ms', 651500000, 150000000, 0, '8 day');
describeValueFormat('none', 2.75e-10, 0, 10, '3e-10');
describeValueFormat('none', 0, 0, 2, '0');
it('should translate 365445 as 6.09 min', function() {
var str = kbn.msFormat(365445, 2);
expect(str).to.be('6.09 min');
});
});
describe('high negative exponent, issue #696', function() {
it('should ignore decimal correction if exponent', function() {
var str = kbn.getFormatFunction('')(2.75e-10, { tickDecimals: 12 });
expect(str).to.be('2.75e-10');
});
it('should format 0 correctly', function() {
var str = kbn.getFormatFunction('')(0.0, { tickDecimals: 12 });
expect(str).to.be('0');
});
});
describe('none format tests', function() {
it('should translate 2 as 2.0000 if axis decimals is 4', function() {
var str = kbn.getFormatFunction('')(2, { tickDecimals: 4 });
expect(str).to.be('2.0000');
});
});
describe('nanosecond formatting', function () {
it('should translate 25 to 25 ns', function () {
var str = kbn.nanosFormat(25, 2);
expect(str).to.be("25 ns");
});
it('should translate 2558 to 2.56 µs', function () {
var str = kbn.nanosFormat(2558, 2);
expect(str).to.be("2.56 µs");
});
it('should translate 2558000 to 2.56 ms', function () {
var str = kbn.nanosFormat(2558000, 2);
expect(str).to.be("2.56 ms");
});
it('should translate 2019962000 to 2.02 s', function () {
var str = kbn.nanosFormat(2049962000, 2);
expect(str).to.be("2.05 s");
});
it('should translate 95199620000 to 1.59 m', function () {
var str = kbn.nanosFormat(95199620000, 2);
expect(str).to.be("1.59 m");
});
});
describeValueFormat('ns', 25, 1, 0, '25 ns');
describeValueFormat('ns', 2558, 50, 0, '2.56 µs');
describe('calculateInterval', function() {
it('1h 100 resultion', function() {

View File

@ -1728,6 +1728,8 @@ Licensed under the MIT license.
axis.delta = delta;
axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
axis.tickSize = opts.tickSize || size;
// grafana addition
axis.scaledDecimals = axis.tickDecimals - Math.floor(Math.log(axis.tickSize) / Math.LN10);
// Time mode was moved to a plug-in in 0.8, and since so many people use it
// we'll add an especially friendly reminder to make sure they included it.