diff --git a/CHANGELOG.md b/CHANGELOG.md index 82390a8e88c..ad6ab03e0c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ # 1.9.0 (unreleased) +- [Issue #877](https://github.com/grafana/grafana/issues/877). Graph: Smart auto decimal precision when using scaled unit formats +- [Issue #850](https://github.com/grafana/grafana/issues/850). Graph: Shared tooltip that shows multiple series & crosshair line, thx @toni-moreno # 1.8.1 (unreleased) diff --git a/latest.json b/latest.json index 6e7dc07bae2..30dd2d3127b 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "version": "1.8.0", - "url": "http://grafanarel.s3.amazonaws.com/grafana-1.8.0.tar.gz" + "version": "1.8.1", + "url": "http://grafanarel.s3.amazonaws.com/grafana-1.8.1.tar.gz" } diff --git a/package.json b/package.json index 8de8f05cf8a..8369d640c62 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Coding Instinct AB" }, "name": "grafana", - "version": "1.8.0", + "version": "1.8.1", "repository": { "type": "git", "url": "http://github.com/torkelo/grafana.git" diff --git a/src/app/components/kbn.js b/src/app/components/kbn.js index 7c61b22c83b..cb084b1c166 100644 --- a/src/app/components/kbn.js +++ b/src/app/components/kbn.js @@ -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(';') + '">'; }; - 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"; } }; diff --git a/src/app/components/require.config.js b/src/app/components/require.config.js index 6a17f9635a2..61689fedc3c 100644 --- a/src/app/components/require.config.js +++ b/src/app/components/require.config.js @@ -40,6 +40,7 @@ require.config({ 'jquery.flot.stack': '../vendor/jquery/jquery.flot.stack', 'jquery.flot.stackpercent':'../vendor/jquery/jquery.flot.stackpercent', 'jquery.flot.time': '../vendor/jquery/jquery.flot.time', + 'jquery.flot.crosshair': '../vendor/jquery/jquery.flot.crosshair', modernizr: '../vendor/modernizr-2.6.1', @@ -83,6 +84,7 @@ require.config({ 'jquery.flot.stack': ['jquery', 'jquery.flot'], 'jquery.flot.stackpercent':['jquery', 'jquery.flot'], 'jquery.flot.time': ['jquery', 'jquery.flot'], + 'jquery.flot.crosshair':['jquery', 'jquery.flot'], 'angular-cookies': ['angular'], 'angular-dragdrop': ['jquery','jquery-ui','angular'], 'angular-loader': ['angular'], diff --git a/src/app/components/timeSeries.js b/src/app/components/timeSeries.js index 4c58c211cc3..a448a93649c 100644 --- a/src/app/components/timeSeries.js +++ b/src/app/components/timeSeries.js @@ -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; }); diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index a2987213cb4..42ef1b91cb5 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -3,9 +3,10 @@ define([ 'jquery', 'kbn', 'moment', - 'lodash' + 'lodash', + './grafanaGraph.tooltip' ], -function (angular, $, kbn, moment, _) { +function (angular, $, kbn, moment, _, graphTooltip) { 'use strict'; var module = angular.module('grafana.directives'); @@ -15,8 +16,8 @@ function (angular, $, kbn, moment, _) { restrict: 'A', template: '