mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
graph: move auto decimals calc to ticks.ts and use it for legend values format.
This commit is contained in:
parent
2cf1c29eae
commit
3cdf0dce56
@ -52,6 +52,8 @@ import {gfPageDirective} from './components/gf_page';
|
||||
import {orgSwitcher} from './components/org_switcher';
|
||||
import {profiler} from './profiler';
|
||||
import {registerAngularDirectives} from './angular_wrappers';
|
||||
import {updateLegendValues} from './time_series2';
|
||||
import TimeSeries from './time_series2';
|
||||
|
||||
export {
|
||||
profiler,
|
||||
@ -83,5 +85,7 @@ export {
|
||||
userGroupPicker,
|
||||
geminiScrollbar,
|
||||
gfPageDirective,
|
||||
orgSwitcher
|
||||
orgSwitcher,
|
||||
TimeSeries,
|
||||
updateLegendValues
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import {getFlotTickDecimals} from 'app/core/utils/ticks';
|
||||
import _ from 'lodash';
|
||||
|
||||
function matchSeriesOverride(aliasOrRegex, seriesAlias) {
|
||||
@ -16,6 +17,43 @@ function translateFillOption(fill) {
|
||||
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 {
|
||||
datapoints: any;
|
||||
id: string;
|
||||
|
@ -1,3 +1,5 @@
|
||||
import {getDataMinMax} from 'app/core/time_series2';
|
||||
|
||||
/**
|
||||
* Calculate tick step.
|
||||
* Implementation from d3-array (ticks.js)
|
||||
@ -32,6 +34,7 @@ export function getScaledDecimals(decimals, tick_size) {
|
||||
|
||||
/**
|
||||
* Calculate tick size based on min and max values, number of ticks and precision.
|
||||
* Implementation from Flot.
|
||||
* @param min Axis minimum
|
||||
* @param max Axis maximum
|
||||
* @param noTicks Number of ticks
|
||||
@ -65,3 +68,107 @@ export function getFlotTickSize(min: number, max: number, noTicks: number, tickD
|
||||
|
||||
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';
|
||||
import {convertValuesToHistogram, getSeriesValues} from './histogram';
|
||||
|
||||
/** @ngInject **/
|
||||
function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
||||
function graphDirective(timeSrv, popoverSrv, contextSrv) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
template: '',
|
||||
@ -34,7 +34,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
||||
var data;
|
||||
var plot;
|
||||
var sortedSeries;
|
||||
var rootScope = scope.$root;
|
||||
var panelWidth = 0;
|
||||
var eventManager = new EventManager(ctrl);
|
||||
var thresholdManager = new ThresholdManager(ctrl);
|
||||
@ -143,27 +142,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
|
@ -2,6 +2,7 @@ import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import PerfectScrollbar from 'perfect-scrollbar';
|
||||
import {updateLegendValues} from 'app/core/core';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
@ -26,6 +27,11 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
||||
ctrl.events.emit('legend-rendering-complete');
|
||||
});
|
||||
|
||||
function updateLegendDecimals() {
|
||||
let graphHeight = ctrl.height - $container.height();
|
||||
updateLegendValues(data, panel, graphHeight);
|
||||
}
|
||||
|
||||
function getSeriesIndexForElement(el) {
|
||||
return el.parents('[data-series-index]').data('series-index');
|
||||
}
|
||||
@ -170,6 +176,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
||||
html += '<a class="graph-legend-alias pointer" title="' + series.aliasEscaped + '">' + series.aliasEscaped + '</a>';
|
||||
|
||||
if (panel.legend.values) {
|
||||
updateLegendDecimals();
|
||||
var avg = series.formatValue(series.stats.avg);
|
||||
var current = series.formatValue(series.stats.current);
|
||||
var min = series.formatValue(series.stats.min);
|
||||
|
Loading…
Reference in New Issue
Block a user