Commit 9f87d8d3 by Torkel Ödegaard

Merge branch 'develop-graph-legend' into develop

parents f78f86d0 35a7109a
......@@ -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';
import {searchResultsDirective} from './components/search/search_results';
import {manageDashboardsDirective} from './components/manage_dashboards/manage_dashboards';
......@@ -86,6 +88,8 @@ export {
geminiScrollbar,
gfPageDirective,
orgSwitcher,
searchResultsDirective,
manageDashboardsDirective
manageDashboardsDirective,
TimeSeries,
updateLegendValues,
searchResultsDirective
};
import kbn from 'app/core/utils/kbn';
import {getFlotTickDecimals} from 'app/core/utils/ticks';
import _ from 'lodash';
function matchSeriesOverride(aliasOrRegex, seriesAlias) {
......@@ -16,6 +17,48 @@ 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
*/
export function updateLegendValues(data: TimeSeries[], panel) {
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);
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[]) {
let datamin = null;
let datamax = null;
for (let series of data) {
if (datamax === null || datamax < series.stats.max) {
datamax = series.stats.max;
}
if (datamin === null || datamin > series.stats.min) {
datamin = series.stats.min;
}
}
return {datamin, datamax};
}
export default class TimeSeries {
datapoints: any;
id: string;
......
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,91 @@ 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};
}
/**
* Calculate tick decimals.
* Implementation from Flot.
*/
export function getFlotTickDecimals(data, axis) {
let {datamin, datamax} = getDataMinMax(data);
let {min, max} = getFlotRange(axis.min, axis.max, datamin, datamax);
let noTicks = 3;
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};
}
......@@ -20,7 +20,7 @@ var panelTemplate = `
</div>
<div class="panel-content">
<ng-transclude></ng-transclude>
<ng-transclude class="panel-height-helper"></ng-transclude>
</div>
</div>
......
......@@ -87,6 +87,8 @@ describe('grafanaGraph', function() {
$.plot = ctx.plotSpy = sinon.spy();
ctrl.events.emit('render', ctx.data);
ctrl.events.emit('render-legend');
ctrl.events.emit('legend-rendering-complete');
ctx.plotData = ctx.plotSpy.getCall(0).args[1];
ctx.plotOptions = ctx.plotSpy.getCall(0).args[2];
}));
......
var template = `
<div class="graph-wrapper" ng-class="{'graph-legend-rightside': ctrl.panel.legend.rightSide}">
<div class="graph-canvas-wrapper">
<div class="datapoints-warning" ng-if="ctrl.dataWarning">
<span class="small" bs-tooltip="ctrl.dataWarning.tip">{{ctrl.dataWarning.title}}</span>
</div>
<div grafana-graph class="histogram-chart" ng-dblclick="ctrl.zoomOut()">
</div>
<div class="graph-panel" ng-class="{'graph-panel--legend-right': ctrl.panel.legend.rightSide}">
<div class="graph-panel__chart" grafana-graph ng-dblclick="ctrl.zoomOut()">
</div>
<div class="graph-legend-wrapper" graph-legend></div>
</div>
<div class="clearfix"></div>
<div class="graph-legend" graph-legend></div>
</div>
`;
export default template;
.graph-canvas-wrapper {
position: relative;
cursor: crosshair;
.graph-panel {
display: flex;
flex-direction: column;
height: 100%;
&--legend-right {
flex-direction: row;
.graph-legend {
flex: 0 1 10px;
max-height: 100%;
}
.graph-legend-series {
display: block;
padding-left: 0px;
}
.graph-legend-table .graph-legend-series {
display: table-row;
}
}
}
.histogram-chart {
.graph-panel__chart {
position: relative;
cursor: crosshair;
flex-grow: 1;
}
.datapoints-warning {
......@@ -22,11 +43,12 @@
}
.graph-legend {
@include clearfix();
flex: 0 1 auto;
max-height: 30%;
margin: 0 $spacer;
text-align: center;
width: calc(100% - $spacer);
padding-top: 6px;
position: relative;
.popover-content {
padding: 0;
......@@ -89,7 +111,9 @@
display: block;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
padding-bottom: 1px;
padding-right: 5px;
}
.graph-legend-series {
......@@ -160,39 +184,6 @@
}
}
.graph-legend-rightside {
&.graph-wrapper {
display: table;
width: 100%;
}
.graph-canvas-wrapper {
display: table-cell;
width: 100%;
position: relative;
}
.graph-legend-wrapper {
display: table-cell;
vertical-align: top;
position: relative;
left: 4px;
}
.graph-legend {
margin: 0 0 0 1rem;
}
.graph-legend-series {
display: block;
padding-left: 0px;
}
.graph-legend-table .graph-legend-series {
display: table-row;
}
}
.graph-legend-series-hidden {
.graph-legend-value,
......
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