Commit 3cdf0dce by Alexander Zobnin

graph: move auto decimals calc to ticks.ts and use it for legend values format.

parent 2cf1c29e
...@@ -52,6 +52,8 @@ import {gfPageDirective} from './components/gf_page'; ...@@ -52,6 +52,8 @@ import {gfPageDirective} from './components/gf_page';
import {orgSwitcher} from './components/org_switcher'; import {orgSwitcher} from './components/org_switcher';
import {profiler} from './profiler'; import {profiler} from './profiler';
import {registerAngularDirectives} from './angular_wrappers'; import {registerAngularDirectives} from './angular_wrappers';
import {updateLegendValues} from './time_series2';
import TimeSeries from './time_series2';
export { export {
profiler, profiler,
...@@ -83,5 +85,7 @@ export { ...@@ -83,5 +85,7 @@ export {
userGroupPicker, userGroupPicker,
geminiScrollbar, geminiScrollbar,
gfPageDirective, gfPageDirective,
orgSwitcher orgSwitcher,
TimeSeries,
updateLegendValues
}; };
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
import {getFlotTickDecimals} from 'app/core/utils/ticks';
import _ from 'lodash'; import _ from 'lodash';
function matchSeriesOverride(aliasOrRegex, seriesAlias) { function matchSeriesOverride(aliasOrRegex, seriesAlias) {
...@@ -16,6 +17,43 @@ function translateFillOption(fill) { ...@@ -16,6 +17,43 @@ function translateFillOption(fill) {
return fill === 0 ? 0.001 : fill/10; return fill === 0 ? 0.001 : fill/10;
} }
/**
* Calculate decimals for legend and update values for each series.
* @param data series data
* @param panel
* @param height Graph height
*/
export function updateLegendValues(data: TimeSeries[], panel, height) {
for (let i = 0; i < data.length; i++) {
let series = data[i];
let yaxes = panel.yaxes;
let axis = yaxes[series.yaxis - 1];
let {tickDecimals, scaledDecimals} = getFlotTickDecimals(data, axis, height);
let formater = kbn.valueFormats[panel.yaxes[series.yaxis - 1].format];
// decimal override
if (_.isNumber(panel.decimals)) {
series.updateLegendValues(formater, panel.decimals, null);
} else {
// auto decimals
// legend and tooltip gets one more decimal precision
// than graph legend ticks
tickDecimals = (tickDecimals || -1) + 1;
series.updateLegendValues(formater, tickDecimals, scaledDecimals + 2);
}
}
}
export function getDataMinMax(data: TimeSeries[]) {
const datamin = _.minBy(data, (series) => {
return series.stats.min;
}).stats.min;
const datamax = _.maxBy(data, (series: TimeSeries) => {
return series.stats.max;
}).stats.max;
return {datamin, datamax};
}
export default class TimeSeries { export default class TimeSeries {
datapoints: any; datapoints: any;
id: string; id: string;
......
import {getDataMinMax} from 'app/core/time_series2';
/** /**
* Calculate tick step. * Calculate tick step.
* Implementation from d3-array (ticks.js) * Implementation from d3-array (ticks.js)
...@@ -32,6 +34,7 @@ export function getScaledDecimals(decimals, tick_size) { ...@@ -32,6 +34,7 @@ export function getScaledDecimals(decimals, tick_size) {
/** /**
* Calculate tick size based on min and max values, number of ticks and precision. * Calculate tick size based on min and max values, number of ticks and precision.
* Implementation from Flot.
* @param min Axis minimum * @param min Axis minimum
* @param max Axis maximum * @param max Axis maximum
* @param noTicks Number of ticks * @param noTicks Number of ticks
...@@ -65,3 +68,107 @@ export function getFlotTickSize(min: number, max: number, noTicks: number, tickD ...@@ -65,3 +68,107 @@ export function getFlotTickSize(min: number, max: number, noTicks: number, tickD
return size; return size;
} }
/**
* Calculate axis range (min and max).
* Implementation from Flot.
*/
export function getFlotRange(panelMin, panelMax, datamin, datamax) {
const autoscaleMargin = 0.02;
let min = +(panelMin != null ? panelMin : datamin);
let max = +(panelMax != null ? panelMax : datamax);
let delta = max - min;
if (delta === 0.0) {
// Grafana fix: wide Y min and max using increased wideFactor
// when all series values are the same
var wideFactor = 0.25;
var widen = Math.abs(max === 0 ? 1 : max * wideFactor);
if (panelMin === null) {
min -= widen;
}
// always widen max if we couldn't widen min to ensure we
// don't fall into min == max which doesn't work
if (panelMax == null || panelMin != null) {
max += widen;
}
} else {
// consider autoscaling
var margin = autoscaleMargin;
if (margin != null) {
if (panelMin == null) {
min -= delta * margin;
// make sure we don't go below zero if all values
// are positive
if (min < 0 && datamin != null && datamin >= 0) {
min = 0;
}
}
if (panelMax == null) {
max += delta * margin;
if (max > 0 && datamax != null && datamax <= 0) {
max = 0;
}
}
}
}
return {min, max};
}
/**
* Estimate number of ticks for Y axis.
* Implementation from Flot.
*/
export function getFlotNumberOfTicks(height, ticks?) {
let noTicks;
if (typeof ticks === "number" && ticks > 0) {
noTicks = ticks;
} else {
// heuristic based on the model a*sqrt(x) fitted to
// some data points that seemed reasonable
noTicks = 0.3 * Math.sqrt(height);
}
return noTicks;
}
/**
* Calculate tick decimals.
* Implementation from Flot.
*/
export function getFlotTickDecimals(data, axis, height) {
let {datamin, datamax} = getDataMinMax(data);
let {min, max} = getFlotRange(axis.min, axis.max, datamin, datamax);
let noTicks = getFlotNumberOfTicks(height);
let tickDecimals, maxDec;
let delta = (max - min) / noTicks;
let dec = -Math.floor(Math.log(delta) / Math.LN10);
let magn = Math.pow(10, -dec);
// norm is between 1.0 and 10.0
let norm = delta / magn;
let size;
if (norm < 1.5) {
size = 1;
} else if (norm < 3) {
size = 2;
// special case for 2.5, requires an extra decimal
if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
size = 2.5;
++dec;
}
} else if (norm < 7.5) {
size = 5;
} else {
size = 10;
}
size *= magn;
tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
// grafana addition
const scaledDecimals = tickDecimals - Math.floor(Math.log(size) / Math.LN10);
return {tickDecimals, scaledDecimals};
}
...@@ -22,7 +22,7 @@ import {EventManager} from 'app/features/annotations/all'; ...@@ -22,7 +22,7 @@ import {EventManager} from 'app/features/annotations/all';
import {convertValuesToHistogram, getSeriesValues} from './histogram'; import {convertValuesToHistogram, getSeriesValues} from './histogram';
/** @ngInject **/ /** @ngInject **/
function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) { function graphDirective(timeSrv, popoverSrv, contextSrv) {
return { return {
restrict: 'A', restrict: 'A',
template: '', template: '',
...@@ -34,7 +34,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) { ...@@ -34,7 +34,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
var data; var data;
var plot; var plot;
var sortedSeries; var sortedSeries;
var rootScope = scope.$root;
var panelWidth = 0; var panelWidth = 0;
var eventManager = new EventManager(ctrl); var eventManager = new EventManager(ctrl);
var thresholdManager = new ThresholdManager(ctrl); var thresholdManager = new ThresholdManager(ctrl);
...@@ -143,27 +142,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) { ...@@ -143,27 +142,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
} }
function drawHook(plot) { function drawHook(plot) {
// Update legend values
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[panel.yaxes[series.yaxis - 1].format];
// decimal override
if (_.isNumber(panel.decimals)) {
series.updateLegendValues(formater, panel.decimals, null);
} else {
// auto decimals
// legend and tooltip gets one more decimal precision
// than graph legend ticks
var tickDecimals = (axis.tickDecimals || -1) + 1;
series.updateLegendValues(formater, tickDecimals, axis.scaledDecimals + 2);
}
if (!rootScope.$$phase) { scope.$digest(); }
}
// add left axis labels // add left axis labels
if (panel.yaxes[0].label && panel.yaxes[0].show) { if (panel.yaxes[0].label && panel.yaxes[0].show) {
$("<div class='axisLabel left-yaxis-label flot-temp-elem'></div>").text(panel.yaxes[0].label).appendTo(elem); $("<div class='axisLabel left-yaxis-label flot-temp-elem'></div>").text(panel.yaxes[0].label).appendTo(elem);
......
...@@ -2,6 +2,7 @@ import angular from 'angular'; ...@@ -2,6 +2,7 @@ import angular from 'angular';
import _ from 'lodash'; import _ from 'lodash';
import $ from 'jquery'; import $ from 'jquery';
import PerfectScrollbar from 'perfect-scrollbar'; import PerfectScrollbar from 'perfect-scrollbar';
import {updateLegendValues} from 'app/core/core';
var module = angular.module('grafana.directives'); var module = angular.module('grafana.directives');
...@@ -26,6 +27,11 @@ module.directive('graphLegend', function(popoverSrv, $timeout) { ...@@ -26,6 +27,11 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
ctrl.events.emit('legend-rendering-complete'); ctrl.events.emit('legend-rendering-complete');
}); });
function updateLegendDecimals() {
let graphHeight = ctrl.height - $container.height();
updateLegendValues(data, panel, graphHeight);
}
function getSeriesIndexForElement(el) { function getSeriesIndexForElement(el) {
return el.parents('[data-series-index]').data('series-index'); return el.parents('[data-series-index]').data('series-index');
} }
...@@ -170,6 +176,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) { ...@@ -170,6 +176,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
html += '<a class="graph-legend-alias pointer" title="' + series.aliasEscaped + '">' + series.aliasEscaped + '</a>'; html += '<a class="graph-legend-alias pointer" title="' + series.aliasEscaped + '">' + series.aliasEscaped + '</a>';
if (panel.legend.values) { if (panel.legend.values) {
updateLegendDecimals();
var avg = series.formatValue(series.stats.avg); var avg = series.formatValue(series.stats.avg);
var current = series.formatValue(series.stats.current); var current = series.formatValue(series.stats.current);
var min = series.formatValue(series.stats.min); var min = series.formatValue(series.stats.min);
......
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