diff --git a/public/app/plugins/panel/graph/graph.js b/public/app/plugins/panel/graph/graph.js index 0a8df0d51ef..5657d1eb9d2 100755 --- a/public/app/plugins/panel/graph/graph.js +++ b/public/app/plugins/panel/graph/graph.js @@ -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; diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 05da5652b74..f616bb28f70 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -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} diff --git a/public/app/plugins/panel/graph/tab_axes.html b/public/app/plugins/panel/graph/tab_axes.html index bb051649424..3a2135cd360 100644 --- a/public/app/plugins/panel/graph/tab_axes.html +++ b/public/app/plugins/panel/graph/tab_axes.html @@ -40,6 +40,75 @@