Merge branch 'issue-5812-x-axis' of https://github.com/alexanderzobnin/grafana into graph-panel-non-timeseries
This commit is contained in:
@@ -237,6 +237,23 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholdManExports) {
|
||||
var series = data[i];
|
||||
series.data = series.getFlotPairs(series.nullPointMode || panel.nullPointMode);
|
||||
|
||||
if (panel.xaxis.mode === 'series') {
|
||||
series.data = [
|
||||
[i + 1, series.stats[panel.xaxis.seriesValue]]
|
||||
];
|
||||
} else if (panel.xaxis.mode === 'table' ||
|
||||
panel.xaxis.mode === 'elastic') {
|
||||
series.data = [];
|
||||
for (var j = 0; j < series.datapoints.length; j++) {
|
||||
var dataIndex = i * series.datapoints.length + j;
|
||||
series.datapoints[j];
|
||||
series.data.push([
|
||||
dataIndex + 1,
|
||||
series.datapoints[j][0]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// if hidden remove points and disable stack
|
||||
if (ctrl.hiddenSeries[series.alias]) {
|
||||
series.data = [];
|
||||
@@ -244,11 +261,34 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholdManExports) {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.length && data[0].stats.timeStep) {
|
||||
options.series.bars.barWidth = data[0].stats.timeStep / 1.5;
|
||||
if (panel.xaxis.mode === 'series') {
|
||||
if (data.length) {
|
||||
options.series.bars.barWidth = 0.7;
|
||||
options.series.bars.align = 'center';
|
||||
options.series.bars.show = true;
|
||||
options.series.points.show = false;
|
||||
options.series.lines.show = false;
|
||||
}
|
||||
|
||||
addXSeriesAxis(options);
|
||||
|
||||
} else if (panel.xaxis.mode === 'table' ||
|
||||
panel.xaxis.mode === 'elastic') {
|
||||
if (data.length) {
|
||||
options.series.bars.barWidth = 0.7;
|
||||
options.series.bars.align = 'center';
|
||||
}
|
||||
|
||||
addXTableAxis(options);
|
||||
|
||||
} else {
|
||||
if (data.length && data[0].stats.timeStep) {
|
||||
options.series.bars.barWidth = data[0].stats.timeStep / 1.5;
|
||||
}
|
||||
|
||||
addTimeAxis(options);
|
||||
}
|
||||
|
||||
addTimeAxis(options);
|
||||
thresholdManager.addPlotOptions(options, panel);
|
||||
addAnnotations(options);
|
||||
configureAxisOptions(data, options);
|
||||
@@ -315,6 +355,42 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholdManExports) {
|
||||
};
|
||||
}
|
||||
|
||||
function addXSeriesAxis(options) {
|
||||
var ticks = _.map(data, function(series, index) {
|
||||
return [index + 1, series.alias];
|
||||
});
|
||||
|
||||
options.xaxis = {
|
||||
timezone: dashboard.getTimezone(),
|
||||
show: panel.xaxis.show,
|
||||
mode: null,
|
||||
min: 0,
|
||||
max: ticks.length + 1,
|
||||
label: "Datetime",
|
||||
ticks: ticks
|
||||
};
|
||||
}
|
||||
|
||||
function addXTableAxis(options) {
|
||||
var ticks = _.map(data, function(series, seriesIndex) {
|
||||
return _.map(series.datapoints, function(point, pointIndex) {
|
||||
var tickIndex = seriesIndex * series.datapoints.length + pointIndex;
|
||||
return [tickIndex + 1, point[1]];
|
||||
});
|
||||
});
|
||||
ticks = _.flatten(ticks, true);
|
||||
|
||||
options.xaxis = {
|
||||
timezone: dashboard.getTimezone(),
|
||||
show: panel.xaxis.show,
|
||||
mode: null,
|
||||
min: 0,
|
||||
max: ticks.length + 1,
|
||||
label: "Datetime",
|
||||
ticks: ticks
|
||||
};
|
||||
}
|
||||
|
||||
function addAnnotations(options) {
|
||||
if(!annotations || annotations.length === 0) {
|
||||
return;
|
||||
|
||||
@@ -22,6 +22,9 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
seriesList: any = [];
|
||||
logScales: any;
|
||||
unitFormats: any;
|
||||
xAxisModes: any;
|
||||
xAxisSeriesValues: any;
|
||||
xAxisColumns: any = [];
|
||||
annotationsPromise: any;
|
||||
datapointsCount: number;
|
||||
datapointsOutside: boolean;
|
||||
@@ -53,7 +56,9 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
}
|
||||
],
|
||||
xaxis: {
|
||||
show: true
|
||||
show: true,
|
||||
mode: 'time',
|
||||
seriesValue: 'avg'
|
||||
},
|
||||
alert: {
|
||||
warn: {op: '>', value: undefined},
|
||||
@@ -117,6 +122,7 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
_.defaults(this.panel.tooltip, this.panelDefaults.tooltip);
|
||||
_.defaults(this.panel.alert, this.panelDefaults.alert);
|
||||
_.defaults(this.panel.legend, this.panelDefaults.legend);
|
||||
_.defaults(this.panel.xaxis, this.panelDefaults.xaxis);
|
||||
|
||||
this.colors = $scope.$root.colors;
|
||||
|
||||
@@ -144,8 +150,16 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
'log (base 32)': 32,
|
||||
'log (base 1024)': 1024
|
||||
};
|
||||
|
||||
this.unitFormats = kbn.getUnitFormats();
|
||||
|
||||
this.xAxisModes = {
|
||||
'Time': 'time',
|
||||
'Series': 'series',
|
||||
'Table': 'table',
|
||||
'Elastic Raw Doc': 'elastic'
|
||||
};
|
||||
|
||||
this.xAxisSeriesValues = ['min', 'max', 'avg', 'current', 'total'];
|
||||
this.subTabIndex = 0;
|
||||
}
|
||||
|
||||
@@ -183,7 +197,40 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
this.datapointsWarning = false;
|
||||
this.datapointsCount = 0;
|
||||
this.datapointsOutside = false;
|
||||
this.seriesList = dataList.map(this.seriesHandler.bind(this));
|
||||
|
||||
let dataHandler: (seriesData, index)=>any;
|
||||
if (this.panel.xaxis.mode === 'table') {
|
||||
if (dataList.length) {
|
||||
// Table panel uses only first enabled tagret, so we can use dataList[0]
|
||||
// for table data representation
|
||||
dataList.splice(1, dataList.length - 1);
|
||||
this.xAxisColumns = _.map(dataList[0].columns, (column, index) => {
|
||||
return {
|
||||
text: column.text,
|
||||
index: index
|
||||
};
|
||||
});
|
||||
|
||||
// Set last column as default value
|
||||
if (!this.panel.xaxis.valueColumnIndex) {
|
||||
this.panel.xaxis.valueColumnIndex = this.xAxisColumns.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
dataHandler = this.tableHandler;
|
||||
} else if (this.panel.xaxis.mode === 'elastic') {
|
||||
if (dataList.length) {
|
||||
dataList.splice(1, dataList.length - 1);
|
||||
var point = _.first(dataList[0].datapoints);
|
||||
this.xAxisColumns = getFieldsFromESDoc(point);
|
||||
}
|
||||
|
||||
dataHandler = this.esRawDocHandler;
|
||||
} else {
|
||||
dataHandler = this.timeSeriesHandler;
|
||||
}
|
||||
|
||||
this.seriesList = dataList.map(dataHandler.bind(this));
|
||||
this.datapointsWarning = this.datapointsCount === 0 || this.datapointsOutside;
|
||||
|
||||
this.annotationsPromise.then(annotations => {
|
||||
@@ -196,9 +243,7 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
seriesHandler(seriesData, index) {
|
||||
var datapoints = seriesData.datapoints;
|
||||
var alias = seriesData.target;
|
||||
seriesHandler(seriesData, index, datapoints, alias) {
|
||||
var colorIndex = index % this.colors.length;
|
||||
var color = this.panel.aliasColors[alias] || this.colors[colorIndex];
|
||||
|
||||
@@ -220,10 +265,52 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
this.panel.tooltip.msResolution = this.panel.tooltip.msResolution || series.isMsResolutionNeeded();
|
||||
}
|
||||
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
timeSeriesHandler(seriesData, index) {
|
||||
var datapoints = seriesData.datapoints;
|
||||
var alias = seriesData.target;
|
||||
|
||||
return this.seriesHandler(seriesData, index, datapoints, alias);
|
||||
}
|
||||
|
||||
tableHandler(seriesData, index) {
|
||||
var xColumnIndex = Number(this.panel.xaxis.columnIndex);
|
||||
var valueColumnIndex = Number(this.panel.xaxis.valueColumnIndex);
|
||||
var datapoints = _.map(seriesData.rows, (row) => {
|
||||
var value = valueColumnIndex ? row[valueColumnIndex] : _.last(row);
|
||||
return [
|
||||
value, // Y value
|
||||
row[xColumnIndex] // X value
|
||||
];
|
||||
});
|
||||
|
||||
var alias = seriesData.columns[valueColumnIndex].text;
|
||||
|
||||
return this.seriesHandler(seriesData, index, datapoints, alias);
|
||||
}
|
||||
|
||||
esRawDocHandler(seriesData, index) {
|
||||
let xField = this.panel.xaxis.esField;
|
||||
let valueField = this.panel.xaxis.esValueField;
|
||||
let datapoints = _.map(seriesData.datapoints, (doc) => {
|
||||
return [
|
||||
pluckDeep(doc, valueField), // Y value
|
||||
pluckDeep(doc, xField) // X value
|
||||
];
|
||||
});
|
||||
|
||||
// Remove empty points
|
||||
datapoints = _.filter(datapoints, (point) => {
|
||||
return point[0] !== undefined;
|
||||
});
|
||||
|
||||
var alias = valueField;
|
||||
|
||||
return this.seriesHandler(seriesData, index, datapoints, alias);
|
||||
}
|
||||
|
||||
onRender() {
|
||||
if (!this.seriesList) { return; }
|
||||
|
||||
@@ -330,4 +417,38 @@ class GraphCtrl extends MetricsPanelCtrl {
|
||||
|
||||
}
|
||||
|
||||
function getFieldsFromESDoc(doc) {
|
||||
let fields = [];
|
||||
let fieldNameParts = [];
|
||||
|
||||
function getFieldsRecursive(obj) {
|
||||
_.forEach(obj, (value, key) => {
|
||||
if (_.isObject(value)) {
|
||||
fieldNameParts.push(key);
|
||||
getFieldsRecursive(value);
|
||||
} else {
|
||||
let field = fieldNameParts.concat(key).join('.');
|
||||
fields.push(field);
|
||||
}
|
||||
});
|
||||
fieldNameParts.pop();
|
||||
}
|
||||
|
||||
getFieldsRecursive(doc);
|
||||
return fields;
|
||||
}
|
||||
|
||||
function pluckDeep(obj: any, property: string) {
|
||||
let propertyParts = property.split('.');
|
||||
let value = obj;
|
||||
for (let i = 0; i < propertyParts.length; ++i) {
|
||||
if (value[propertyParts[i]]) {
|
||||
value = value[propertyParts[i]];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export {GraphCtrl, GraphCtrl as PanelCtrl}
|
||||
|
||||
@@ -40,6 +40,75 @@
|
||||
<div class="section gf-form-group">
|
||||
<h5 class="section-heading">X-Axis</h5>
|
||||
<gf-form-switch class="gf-form" label="Show" label-class="width-5" checked="ctrl.panel.xaxis.show" on-change="ctrl.render()"></gf-form-switch>
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-5">Mode</label>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.panel.xaxis.mode"
|
||||
ng-options="v as k for (k, v) in ctrl.xAxisModes"
|
||||
ng-change="ctrl.refresh()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Series mode -->
|
||||
<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'series'">
|
||||
<label class="gf-form-label width-5">Value</label>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.panel.xaxis.seriesValue"
|
||||
ng-options="v for v in ctrl.xAxisSeriesValues"
|
||||
ng-change="ctrl.render()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table mode -->
|
||||
<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'table'">
|
||||
<label class="gf-form-label width-5">Column</label>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.panel.xaxis.columnIndex"
|
||||
ng-options="col.index as col.text for col in ctrl.xAxisColumns"
|
||||
ng-change="ctrl.refresh()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'table'">
|
||||
<label class="gf-form-label width-5">Value</label>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.panel.xaxis.valueColumnIndex"
|
||||
ng-options="col.index as col.text for col in ctrl.xAxisColumns"
|
||||
ng-change="ctrl.refresh()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Elastic Raw Document mode -->
|
||||
<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'elastic'">
|
||||
<label class="gf-form-label width-5">Column</label>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.panel.xaxis.esField"
|
||||
ng-options="field for field in ctrl.xAxisColumns"
|
||||
ng-change="ctrl.refresh()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'elastic'">
|
||||
<label class="gf-form-label width-5">Value</label>
|
||||
<div class="gf-form-select-wrapper max-width-15">
|
||||
<select class="gf-form-input"
|
||||
ng-model="ctrl.panel.xaxis.esValueField"
|
||||
ng-options="field for field in ctrl.xAxisColumns"
|
||||
ng-change="ctrl.refresh()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user