|
@@ -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,8 +34,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
var data;
|
|
var data;
|
|
|
var plot;
|
|
var plot;
|
|
|
var sortedSeries;
|
|
var sortedSeries;
|
|
|
- var legendSideLastValue = null;
|
|
|
|
|
- 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);
|
|
@@ -53,17 +51,28 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- ctrl.events.on('render', function(renderData) {
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Split graph rendering into two parts.
|
|
|
|
|
+ * First, calculate series stats in buildFlotPairs() function. Then legend rendering started
|
|
|
|
|
+ * (see ctrl.events.on('render') in legend.ts).
|
|
|
|
|
+ * When legend is rendered it emits 'legend-rendering-complete' and graph rendered.
|
|
|
|
|
+ */
|
|
|
|
|
+ ctrl.events.on('render', (renderData) => {
|
|
|
data = renderData || data;
|
|
data = renderData || data;
|
|
|
if (!data) {
|
|
if (!data) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
annotations = ctrl.annotations || [];
|
|
annotations = ctrl.annotations || [];
|
|
|
|
|
+ buildFlotPairs(data);
|
|
|
|
|
+ ctrl.events.emit('render-legend');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ ctrl.events.on('legend-rendering-complete', () => {
|
|
|
render_panel();
|
|
render_panel();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// global events
|
|
// global events
|
|
|
- appEvents.on('graph-hover', function(evt) {
|
|
|
|
|
|
|
+ appEvents.on('graph-hover', (evt) => {
|
|
|
// ignore other graph hover events if shared tooltip is disabled
|
|
// ignore other graph hover events if shared tooltip is disabled
|
|
|
if (!dashboard.sharedTooltipModeEnabled()) {
|
|
if (!dashboard.sharedTooltipModeEnabled()) {
|
|
|
return;
|
|
return;
|
|
@@ -77,47 +86,17 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
tooltip.show(evt.pos);
|
|
tooltip.show(evt.pos);
|
|
|
}, scope);
|
|
}, scope);
|
|
|
|
|
|
|
|
- appEvents.on('graph-hover-clear', function(event, info) {
|
|
|
|
|
|
|
+ appEvents.on('graph-hover-clear', (event, info) => {
|
|
|
if (plot) {
|
|
if (plot) {
|
|
|
tooltip.clear(plot);
|
|
tooltip.clear(plot);
|
|
|
}
|
|
}
|
|
|
}, scope);
|
|
}, scope);
|
|
|
|
|
|
|
|
- function getLegendHeight(panelHeight) {
|
|
|
|
|
- if (!panel.legend.show || panel.legend.rightSide) {
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (panel.legend.alignAsTable) {
|
|
|
|
|
- var legendSeries = _.filter(data, function(series) {
|
|
|
|
|
- return series.hideFromLegend(panel.legend) === false;
|
|
|
|
|
- });
|
|
|
|
|
- var total = 23 + (21 * legendSeries.length);
|
|
|
|
|
- return Math.min(total, Math.floor(panelHeight/2));
|
|
|
|
|
- } else {
|
|
|
|
|
- return 26;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function setElementHeight() {
|
|
|
|
|
- try {
|
|
|
|
|
- var height = ctrl.height - getLegendHeight(ctrl.height);
|
|
|
|
|
- elem.css('height', height + 'px');
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
- } catch (e) { // IE throws errors sometimes
|
|
|
|
|
- console.log(e);
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
function shouldAbortRender() {
|
|
function shouldAbortRender() {
|
|
|
if (!data) {
|
|
if (!data) {
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!setElementHeight()) { return true; }
|
|
|
|
|
-
|
|
|
|
|
if (panelWidth === 0) {
|
|
if (panelWidth === 0) {
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -126,27 +105,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);
|
|
@@ -157,6 +115,10 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
$("<div class='axisLabel right-yaxis-label flot-temp-elem'></div>").text(panel.yaxes[1].label).appendTo(elem);
|
|
$("<div class='axisLabel right-yaxis-label flot-temp-elem'></div>").text(panel.yaxes[1].label).appendTo(elem);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (ctrl.dataWarning) {
|
|
|
|
|
+ $(`<div class="datapoints-warning flot-temp-elem">${ctrl.dataWarning.title}</div>`).appendTo(elem);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
thresholdManager.draw(plot);
|
|
thresholdManager.draw(plot);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -207,7 +169,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
// Function for rendering panel
|
|
// Function for rendering panel
|
|
|
function render_panel() {
|
|
function render_panel() {
|
|
|
panelWidth = elem.width();
|
|
panelWidth = elem.width();
|
|
|
-
|
|
|
|
|
if (shouldAbortRender()) {
|
|
if (shouldAbortRender()) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -218,67 +179,18 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
// un-check dashes if lines are unchecked
|
|
// un-check dashes if lines are unchecked
|
|
|
panel.dashes = panel.lines ? panel.dashes : false;
|
|
panel.dashes = panel.lines ? panel.dashes : false;
|
|
|
|
|
|
|
|
- var stack = panel.stack ? true : null;
|
|
|
|
|
-
|
|
|
|
|
// Populate element
|
|
// Populate element
|
|
|
- var options: any = {
|
|
|
|
|
- hooks: {
|
|
|
|
|
- draw: [drawHook],
|
|
|
|
|
- processOffset: [processOffsetHook],
|
|
|
|
|
- },
|
|
|
|
|
- legend: { show: false },
|
|
|
|
|
- series: {
|
|
|
|
|
- stackpercent: panel.stack ? panel.percentage : false,
|
|
|
|
|
- stack: panel.percentage ? null : stack,
|
|
|
|
|
- lines: {
|
|
|
|
|
- show: panel.lines,
|
|
|
|
|
- zero: false,
|
|
|
|
|
- fill: translateFillOption(panel.fill),
|
|
|
|
|
- lineWidth: panel.dashes ? 0 : panel.linewidth,
|
|
|
|
|
- steps: panel.steppedLine
|
|
|
|
|
- },
|
|
|
|
|
- dashes: {
|
|
|
|
|
- show: panel.dashes,
|
|
|
|
|
- lineWidth: panel.linewidth,
|
|
|
|
|
- dashLength: [panel.dashLength, panel.spaceLength]
|
|
|
|
|
- },
|
|
|
|
|
- bars: {
|
|
|
|
|
- show: panel.bars,
|
|
|
|
|
- fill: 1,
|
|
|
|
|
- barWidth: 1,
|
|
|
|
|
- zero: false,
|
|
|
|
|
- lineWidth: 0
|
|
|
|
|
- },
|
|
|
|
|
- points: {
|
|
|
|
|
- show: panel.points,
|
|
|
|
|
- fill: 1,
|
|
|
|
|
- fillColor: false,
|
|
|
|
|
- radius: panel.points ? panel.pointradius : 2
|
|
|
|
|
- },
|
|
|
|
|
- shadowSize: 0
|
|
|
|
|
- },
|
|
|
|
|
- yaxes: [],
|
|
|
|
|
- xaxis: {},
|
|
|
|
|
- grid: {
|
|
|
|
|
- minBorderMargin: 0,
|
|
|
|
|
- markings: [],
|
|
|
|
|
- backgroundColor: null,
|
|
|
|
|
- borderWidth: 0,
|
|
|
|
|
- hoverable: true,
|
|
|
|
|
- clickable: true,
|
|
|
|
|
- color: '#c8c8c8',
|
|
|
|
|
- margin: { left: 0, right: 0 },
|
|
|
|
|
- labelMarginX: 0,
|
|
|
|
|
- },
|
|
|
|
|
- selection: {
|
|
|
|
|
- mode: "x",
|
|
|
|
|
- color: '#666'
|
|
|
|
|
- },
|
|
|
|
|
- crosshair: {
|
|
|
|
|
- mode: 'x'
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ let options: any = buildFlotOptions(panel);
|
|
|
|
|
+ prepareXAxis(options, panel);
|
|
|
|
|
+ configureYAxisOptions(data, options);
|
|
|
|
|
+ thresholdManager.addFlotOptions(options, panel);
|
|
|
|
|
+ eventManager.addFlotEvents(annotations, options);
|
|
|
|
|
|
|
|
|
|
+ sortedSeries = sortSeries(data, panel);
|
|
|
|
|
+ callPlot(options, true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function buildFlotPairs(data) {
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
let series = data[i];
|
|
let series = data[i];
|
|
|
series.data = series.getFlotPairs(series.nullPointMode || panel.nullPointMode);
|
|
series.data = series.getFlotPairs(series.nullPointMode || panel.nullPointMode);
|
|
@@ -289,7 +201,9 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
series.stack = false;
|
|
series.stack = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ function prepareXAxis(options, panel) {
|
|
|
switch (panel.xaxis.mode) {
|
|
switch (panel.xaxis.mode) {
|
|
|
case 'series': {
|
|
case 'series': {
|
|
|
options.series.bars.barWidth = 0.7;
|
|
options.series.bars.barWidth = 0.7;
|
|
@@ -334,42 +248,89 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- thresholdManager.addFlotOptions(options, panel);
|
|
|
|
|
- eventManager.addFlotEvents(annotations, options);
|
|
|
|
|
- configureAxisOptions(data, options);
|
|
|
|
|
-
|
|
|
|
|
- sortedSeries = sortSeries(data, ctrl.panel);
|
|
|
|
|
-
|
|
|
|
|
- function callPlot(incrementRenderCounter) {
|
|
|
|
|
- try {
|
|
|
|
|
- plot = $.plot(elem, sortedSeries, options);
|
|
|
|
|
- if (ctrl.renderError) {
|
|
|
|
|
- delete ctrl.error;
|
|
|
|
|
- delete ctrl.inspector;
|
|
|
|
|
- }
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.log('flotcharts error', e);
|
|
|
|
|
- ctrl.error = e.message || "Render Error";
|
|
|
|
|
- ctrl.renderError = true;
|
|
|
|
|
- ctrl.inspector = {error: e};
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (incrementRenderCounter) {
|
|
|
|
|
- ctrl.renderingCompleted();
|
|
|
|
|
|
|
+ function callPlot(options, incrementRenderCounter) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ plot = $.plot(elem, sortedSeries, options);
|
|
|
|
|
+ if (ctrl.renderError) {
|
|
|
|
|
+ delete ctrl.error;
|
|
|
|
|
+ delete ctrl.inspector;
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.log('flotcharts error', e);
|
|
|
|
|
+ ctrl.error = e.message || "Render Error";
|
|
|
|
|
+ ctrl.renderError = true;
|
|
|
|
|
+ ctrl.inspector = {error: e};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (shouldDelayDraw(panel)) {
|
|
|
|
|
- // temp fix for legends on the side, need to render twice to get dimensions right
|
|
|
|
|
- callPlot(false);
|
|
|
|
|
- setTimeout(function() { callPlot(true); }, 50);
|
|
|
|
|
- legendSideLastValue = panel.legend.rightSide;
|
|
|
|
|
- } else {
|
|
|
|
|
- callPlot(true);
|
|
|
|
|
|
|
+ if (incrementRenderCounter) {
|
|
|
|
|
+ ctrl.renderingCompleted();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ function buildFlotOptions(panel) {
|
|
|
|
|
+ const stack = panel.stack ? true : null;
|
|
|
|
|
+ let options = {
|
|
|
|
|
+ hooks: {
|
|
|
|
|
+ draw: [drawHook],
|
|
|
|
|
+ processOffset: [processOffsetHook],
|
|
|
|
|
+ },
|
|
|
|
|
+ legend: { show: false },
|
|
|
|
|
+ series: {
|
|
|
|
|
+ stackpercent: panel.stack ? panel.percentage : false,
|
|
|
|
|
+ stack: panel.percentage ? null : stack,
|
|
|
|
|
+ lines: {
|
|
|
|
|
+ show: panel.lines,
|
|
|
|
|
+ zero: false,
|
|
|
|
|
+ fill: translateFillOption(panel.fill),
|
|
|
|
|
+ lineWidth: panel.dashes ? 0 : panel.linewidth,
|
|
|
|
|
+ steps: panel.steppedLine
|
|
|
|
|
+ },
|
|
|
|
|
+ dashes: {
|
|
|
|
|
+ show: panel.dashes,
|
|
|
|
|
+ lineWidth: panel.linewidth,
|
|
|
|
|
+ dashLength: [panel.dashLength, panel.spaceLength]
|
|
|
|
|
+ },
|
|
|
|
|
+ bars: {
|
|
|
|
|
+ show: panel.bars,
|
|
|
|
|
+ fill: 1,
|
|
|
|
|
+ barWidth: 1,
|
|
|
|
|
+ zero: false,
|
|
|
|
|
+ lineWidth: 0
|
|
|
|
|
+ },
|
|
|
|
|
+ points: {
|
|
|
|
|
+ show: panel.points,
|
|
|
|
|
+ fill: 1,
|
|
|
|
|
+ fillColor: false,
|
|
|
|
|
+ radius: panel.points ? panel.pointradius : 2
|
|
|
|
|
+ },
|
|
|
|
|
+ shadowSize: 0
|
|
|
|
|
+ },
|
|
|
|
|
+ yaxes: [],
|
|
|
|
|
+ xaxis: {},
|
|
|
|
|
+ grid: {
|
|
|
|
|
+ minBorderMargin: 0,
|
|
|
|
|
+ markings: [],
|
|
|
|
|
+ backgroundColor: null,
|
|
|
|
|
+ borderWidth: 0,
|
|
|
|
|
+ hoverable: true,
|
|
|
|
|
+ clickable: true,
|
|
|
|
|
+ color: '#c8c8c8',
|
|
|
|
|
+ margin: { left: 0, right: 0 },
|
|
|
|
|
+ labelMarginX: 0,
|
|
|
|
|
+ },
|
|
|
|
|
+ selection: {
|
|
|
|
|
+ mode: "x",
|
|
|
|
|
+ color: '#666'
|
|
|
|
|
+ },
|
|
|
|
|
+ crosshair: {
|
|
|
|
|
+ mode: 'x'
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ return options;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function sortSeries(series, panel) {
|
|
function sortSeries(series, panel) {
|
|
|
var sortBy = panel.legend.sort;
|
|
var sortBy = panel.legend.sort;
|
|
|
var sortOrder = panel.legend.sortDesc;
|
|
var sortOrder = panel.legend.sortDesc;
|
|
@@ -410,16 +371,6 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function shouldDelayDraw(panel) {
|
|
|
|
|
- if (panel.legend.rightSide) {
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- if (legendSideLastValue !== null && panel.legend.rightSide !== legendSideLastValue) {
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
function addTimeAxis(options) {
|
|
function addTimeAxis(options) {
|
|
|
var ticks = panelWidth / 100;
|
|
var ticks = panelWidth / 100;
|
|
|
var min = _.isUndefined(ctrl.range.from) ? null : ctrl.range.from.valueOf();
|
|
var min = _.isUndefined(ctrl.range.from) ? null : ctrl.range.from.valueOf();
|
|
@@ -519,7 +470,7 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function configureAxisOptions(data, options) {
|
|
|
|
|
|
|
+ function configureYAxisOptions(data, options) {
|
|
|
var defaults = {
|
|
var defaults = {
|
|
|
position: 'left',
|
|
position: 'left',
|
|
|
show: panel.yaxes[0].show,
|
|
show: panel.yaxes[0].show,
|