From 1d7a0db54ba92671ce2a604c2d62c9075ee63643 Mon Sep 17 00:00:00 2001 From: Carl Bergquist Date: Thu, 19 Oct 2017 13:04:02 +0200 Subject: [PATCH] Sort series in the same order as legend in graph panel (#9563) * graph: sort series in the same order as legend closes #9538 * style: use function arrows * graph: remove sort by legend option sort series based on legend by default is sort order is set and stack is enabled * graph: remove useless sort * graph: make code simpler --- public/app/plugins/panel/graph/graph.ts | 37 +++++++++- public/app/plugins/panel/graph/legend.js | 4 +- .../plugins/panel/graph/specs/graph_specs.ts | 67 ++++++++++++++++--- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index f378e52a111..8ad6e999833 100755 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -343,7 +343,7 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) { eventManager.addFlotEvents(annotations, options); configureAxisOptions(data, options); - sortedSeries = _.sortBy(data, function(series) { return series.zindex; }); + sortedSeries = sortSeries(data, ctrl.panel); function callPlot(incrementRenderCounter) { try { @@ -374,6 +374,41 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) { } } + function sortSeries(series, panel) { + var sortBy = panel.legend.sort; + var sortOrder = panel.legend.sortDesc; + var haveSortBy = sortBy !== null || sortBy !== undefined; + var haveSortOrder = sortOrder !== null || sortOrder !== undefined; + + if (panel.stack && haveSortBy && haveSortOrder) { + var desc = desc = panel.legend.sortDesc === true ? 1 : -1; + series.sort((x, y) => { + if (x.stats[sortBy] > y.stats[sortBy]) { + return 1 * desc; + } + if (x.stats[sortBy] < y.stats[sortBy]) { + return -1 * desc; + } + + return 0; + }); + } + + series.sort((x, y) => { + if (x.zindex > y.zindex) { + return 1; + } + + if (x.zindex < y.zindex) { + return -1; + } + + return 0; + }); + + return series; + } + function translateFillOption(fill) { if (panel.percentage && panel.stack) { return fill === 0 ? 0.001 : fill/10; diff --git a/public/app/plugins/panel/graph/legend.js b/public/app/plugins/panel/graph/legend.js index b8c2970b8cd..1a29743b09d 100644 --- a/public/app/plugins/panel/graph/legend.js +++ b/public/app/plugins/panel/graph/legend.js @@ -80,13 +80,13 @@ function (angular, _, $) { if (panel.legend.sortDesc === false) { panel.legend.sort = null; panel.legend.sortDesc = null; - render(); + ctrl.render(); return; } panel.legend.sortDesc = !panel.legend.sortDesc; panel.legend.sort = stat; - render(); + ctrl.render(); } function getTableHeaderHtml(statName) { diff --git a/public/app/plugins/panel/graph/specs/graph_specs.ts b/public/app/plugins/panel/graph/specs/graph_specs.ts index 1c240bb2967..cf31121e81d 100644 --- a/public/app/plugins/panel/graph/specs/graph_specs.ts +++ b/public/app/plugins/panel/graph/specs/graph_specs.ts @@ -15,16 +15,16 @@ describe('grafanaGraph', function() { beforeEach(angularMocks.module('grafana.core')); function graphScenario(desc, func, elementWidth = 500) { - describe(desc, function() { + describe(desc, () => { var ctx: any = {}; - ctx.setup = function(setupFunc) { + ctx.setup = (setupFunc) => { - beforeEach(angularMocks.module(function($provide) { + beforeEach(angularMocks.module(($provide) => { $provide.value("timeSrv", new helpers.TimeSrvStub()); })); - beforeEach(angularMocks.inject(function($rootScope, $compile) { + beforeEach(angularMocks.inject(($rootScope, $compile) => { var ctrl: any = { events: new Emitter(), height: 200, @@ -75,7 +75,7 @@ describe('grafanaGraph', function() { alias: 'series1' })); ctx.data.push(new TimeSeries({ - datapoints: [[1,1],[2,2]], + datapoints: [[1,10],[2,20]], alias: 'series2' })); @@ -96,15 +96,15 @@ describe('grafanaGraph', function() { }); } - graphScenario('simple lines options', function(ctx) { - ctx.setup(function(ctrl) { + graphScenario('simple lines options', (ctx) => { + ctx.setup((ctrl) => { ctrl.panel.lines = true; ctrl.panel.fill = 5; ctrl.panel.linewidth = 3; ctrl.panel.steppedLine = true; }); - it('should configure plot with correct options', function() { + it('should configure plot with correct options', () => { expect(ctx.plotOptions.series.lines.show).to.be(true); expect(ctx.plotOptions.series.lines.fill).to.be(0.5); expect(ctx.plotOptions.series.lines.lineWidth).to.be(3); @@ -112,6 +112,55 @@ describe('grafanaGraph', function() { }); }); + graphScenario('sort series as legend', (ctx) => { + describe("with sort as legend undefined", () => { + ctx.setup((ctrl) => { + ctrl.panel.legend.sort = undefined; + }); + + it("should not modify order of time series", () => { + expect(ctx.plotData[0].alias).to.be('series1'); + expect(ctx.plotData[1].alias).to.be('series2'); + }); + }); + + describe("with sort as legend set to min. descending order", () => { + ctx.setup((ctrl) => { + ctrl.panel.legend.sort = 'min'; + ctrl.panel.legend.sortDesc = true; + }); + + it("highest value should be first", () => { + expect(ctx.plotData[1].alias).to.be('series2'); + expect(ctx.plotData[0].alias).to.be('series1'); + }); + }); + + describe("with sort as legend set to min. ascending order", () => { + ctx.setup((ctrl) => { + ctrl.panel.legend.sort = 'min'; + ctrl.panel.legend.sortDesc = true; + }); + + it("lowest value should be first", () => { + expect(ctx.plotData[0].alias).to.be('series1'); + expect(ctx.plotData[1].alias).to.be('series2'); + }); + }); + + describe("with sort as legend set to current. ascending order", () => { + ctx.setup((ctrl) => { + ctrl.panel.legend.sort = 'current'; + ctrl.panel.legend.sortDesc = false; + }); + + it("highest last value should be first", () => { + expect(ctx.plotData[1].alias).to.be('series2'); + expect(ctx.plotData[0].alias).to.be('series1'); + }); + }); + }); + graphScenario('when logBase is log 10', function(ctx) { ctx.setup(function(ctrl, data) { ctrl.panel.yaxes[0].logBase = 10; @@ -251,7 +300,7 @@ describe('grafanaGraph', function() { }); it('should set barWidth', function() { - expect(ctx.plotOptions.series.bars.barWidth).to.be(1/1.5); + expect(ctx.plotOptions.series.bars.barWidth).to.be(10/1.5); }); });