diff --git a/CHANGELOG.md b/CHANGELOG.md index 793a0740e4e..0c6d39929f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [Issue #578](https://github.com/grafana/grafana/issues/578). Dashboard: Row option to display row title even when the row is visible - [Issue #672](https://github.com/grafana/grafana/issues/672). Dashboard: panel fullscreen & edit state is present in url, can now link to graph in edit & fullscreen mode. - [Issue #709](https://github.com/grafana/grafana/issues/709). Dashboard: Small UI look polish to search results, made dashboard title link are larger +- [Issue #425](https://github.com/grafana/grafana/issues/425). Graph: New section in 'Display Styles' tab to override any display setting on per series bases (mix and match lines, bars, points, fill, stack, line width etc) **Fixes** - [Issue #696](https://github.com/grafana/grafana/issues/696). Graph: Fix for y-axis format 'none' when values are in scientific notation (ex 2.3e-13) diff --git a/package.json b/package.json index 31c552fe6c2..eecf826776e 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "grunt-string-replace": "~0.2.4", "grunt-usemin": "^2.1.1", "jshint-stylish": "~0.1.5", - "karma": "~0.12.16", + "karma": "~0.12.21", "karma-chrome-launcher": "~0.1.4", "karma-coffee-preprocessor": "~0.1.2", "karma-coverage": "^0.2.5", diff --git a/src/app/components/kbn.js b/src/app/components/kbn.js index 71fe1b4b75a..46a1b8dfa79 100644 --- a/src/app/components/kbn.js +++ b/src/app/components/kbn.js @@ -231,36 +231,36 @@ function($, _, moment) { if (type === 0) { roundUp ? dateTime.endOf('year') : dateTime.startOf('year'); } else if (type === 1) { - dateTime.add('years',num); + dateTime.add(num, 'years'); } else if (type === 2) { - dateTime.subtract('years',num); + dateTime.subtract(num, 'years'); } break; case 'M': if (type === 0) { roundUp ? dateTime.endOf('month') : dateTime.startOf('month'); } else if (type === 1) { - dateTime.add('months',num); + dateTime.add(num, 'months'); } else if (type === 2) { - dateTime.subtract('months',num); + dateTime.subtract(num, 'months'); } break; case 'w': if (type === 0) { roundUp ? dateTime.endOf('week') : dateTime.startOf('week'); } else if (type === 1) { - dateTime.add('weeks',num); + dateTime.add(num, 'weeks'); } else if (type === 2) { - dateTime.subtract('weeks',num); + dateTime.subtract(num, 'weeks'); } break; case 'd': if (type === 0) { roundUp ? dateTime.endOf('day') : dateTime.startOf('day'); } else if (type === 1) { - dateTime.add('days',num); + dateTime.add(num, 'days'); } else if (type === 2) { - dateTime.subtract('days',num); + dateTime.subtract(num, 'days'); } break; case 'h': @@ -268,27 +268,27 @@ function($, _, moment) { if (type === 0) { roundUp ? dateTime.endOf('hour') : dateTime.startOf('hour'); } else if (type === 1) { - dateTime.add('hours',num); + dateTime.add(num, 'hours'); } else if (type === 2) { - dateTime.subtract('hours',num); + dateTime.subtract(num,'hours'); } break; case 'm': if (type === 0) { roundUp ? dateTime.endOf('minute') : dateTime.startOf('minute'); } else if (type === 1) { - dateTime.add('minutes',num); + dateTime.add(num, 'minutes'); } else if (type === 2) { - dateTime.subtract('minutes',num); + dateTime.subtract(num, 'minutes'); } break; case 's': if (type === 0) { roundUp ? dateTime.endOf('second') : dateTime.startOf('second'); } else if (type === 1) { - dateTime.add('seconds',num); + dateTime.add(num, 'seconds'); } else if (type === 2) { - dateTime.subtract('seconds',num); + dateTime.subtract(num, 'seconds'); } break; default: diff --git a/src/app/components/settings.js b/src/app/components/settings.js index 3edafc5a407..b43237224b4 100644 --- a/src/app/components/settings.js +++ b/src/app/components/settings.js @@ -19,7 +19,7 @@ function (_, crypto) { default_route : '/dashboard/file/default.json', playlist_timespan : "1m", unsaved_changes_warning : true, - search : { max_results: 20 }, + search : { max_results: 16 }, admin : {} }; diff --git a/src/app/panels/graph/timeSeries.js b/src/app/components/timeSeries.js similarity index 51% rename from src/app/panels/graph/timeSeries.js rename to src/app/components/timeSeries.js index f1794cd6a30..85c27f1da88 100644 --- a/src/app/panels/graph/timeSeries.js +++ b/src/app/components/timeSeries.js @@ -5,15 +5,57 @@ define([ function (_, kbn) { 'use strict'; - var ts = {}; - - ts.ZeroFilled = function (opts) { + function TimeSeries(opts) { this.datapoints = opts.datapoints; this.info = opts.info; this.label = opts.info.alias; + } + + function matchSeriesOverride(aliasOrRegex, seriesAlias) { + if (!aliasOrRegex) { return false; } + + if (aliasOrRegex[0] === '/') { + var match = aliasOrRegex.match(new RegExp('^/(.*?)/(g?i?m?y?)$')); + var regex = new RegExp(match[1], match[2]); + return seriesAlias.match(regex) != null; + } + + return aliasOrRegex === seriesAlias; + } + + function translateFillOption(fill) { + return fill === 0 ? 0.001 : fill/10; + } + + TimeSeries.prototype.applySeriesOverrides = function(overrides) { + this.lines = {}; + this.points = {}; + this.bars = {}; + this.info.yaxis = 1; + this.zindex = 0; + delete this.stack; + + for (var i = 0; i < overrides.length; i++) { + var override = overrides[i]; + if (!matchSeriesOverride(override.alias, this.info.alias)) { + continue; + } + if (override.lines !== void 0) { this.lines.show = override.lines; } + if (override.points !== void 0) { this.points.show = override.points; } + if (override.bars !== void 0) { this.bars.show = override.bars; } + if (override.fill !== void 0) { this.lines.fill = translateFillOption(override.fill); } + if (override.stack !== void 0) { this.stack = override.stack; } + if (override.linewidth !== void 0) { this.lines.lineWidth = override.linewidth; } + if (override.pointradius !== void 0) { this.points.radius = override.pointradius; } + if (override.steppedLine !== void 0) { this.lines.steps = override.steppedLine; } + if (override.zindex !== void 0) { this.zindex = override.zindex; } + if (override.yaxis !== void 0) { + this.info.yaxis = override.yaxis; + } + } }; - ts.ZeroFilled.prototype.getFlotPairs = function (fillStyle, yFormats) { + TimeSeries.prototype.getFlotPairs = function (fillStyle, yFormats) { var result = []; this.color = this.info.color; @@ -74,5 +116,6 @@ function (_, kbn) { return result; }; - return ts; -}); \ No newline at end of file + return TimeSeries; + +}); diff --git a/src/app/controllers/dashboardCtrl.js b/src/app/controllers/dashboardCtrl.js index 5620b7305a2..7132ca8a571 100644 --- a/src/app/controllers/dashboardCtrl.js +++ b/src/app/controllers/dashboardCtrl.js @@ -13,7 +13,7 @@ function (angular, $, config, _) { module.controller('DashboardCtrl', function( $scope, $rootScope, dashboardKeybindings, filterSrv, dashboardSrv, dashboardViewStateSrv, - panelMoveSrv, timer) { + panelMoveSrv, timer, $timeout) { $scope.editor = { index: 0 }; $scope.panelNames = config.panels; @@ -21,6 +21,13 @@ function (angular, $, config, _) { $scope.init = function() { $scope.availablePanels = config.panels; $scope.onAppEvent('setup-dashboard', $scope.setupDashboard); + + angular.element(window).bind('resize', function() { + $timeout(function() { + $scope.$broadcast('render'); + }); + }); + }; $scope.setupDashboard = function(event, dashboardData) { diff --git a/src/app/directives/addGraphiteFunc.js b/src/app/directives/addGraphiteFunc.js index ca5943da508..6898b838845 100644 --- a/src/app/directives/addGraphiteFunc.js +++ b/src/app/directives/addGraphiteFunc.js @@ -97,4 +97,4 @@ function (angular, app, _, $, gfunc) { }; }); } -}); \ No newline at end of file +}); diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index a91967b967b..222bde78b26 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -46,11 +46,6 @@ function (angular, $, kbn, moment, _) { render_panel(); }); - // Re-render if the window is resized - angular.element(window).bind('resize', function() { - render_panel(); - }); - function setElementHeight() { try { var height = scope.height || scope.panel.height || scope.row.height; @@ -118,7 +113,7 @@ function (angular, $, kbn, moment, _) { lines: { show: panel.lines, zero: false, - fill: panel.fill === 0 ? 0.001 : panel.fill/10, + fill: translateFillOption(panel.fill), lineWidth: panel.linewidth, steps: panel.steppedLine }, @@ -154,11 +149,12 @@ function (angular, $, kbn, moment, _) { }; for (var i = 0; i < data.length; i++) { - var _d = data[i].getFlotPairs(panel.nullPointMode, panel.y_formats); - data[i].data = _d; + var series = data[i]; + series.applySeriesOverrides(panel.seriesOverrides); + series.data = series.getFlotPairs(panel.nullPointMode, panel.y_formats); } - if (panel.bars && data.length && data[0].info.timeStep) { + if (data.length && data[0].info.timeStep) { options.series.bars.barWidth = data[0].info.timeStep / 1.5; } @@ -167,21 +163,27 @@ function (angular, $, kbn, moment, _) { addAnnotations(options); configureAxisOptions(data, options); + var sortedSeries = _.sortBy(data, function(series) { return series.zindex; }); + // if legend is to the right delay plot draw a few milliseconds // so the legend width calculation can be done if (shouldDelayDraw(panel)) { legendSideLastValue = panel.legend.rightSide; setTimeout(function() { - plot = $.plot(elem, data, options); + plot = $.plot(elem, sortedSeries, options); addAxisLabels(); }, 50); } else { - plot = $.plot(elem, data, options); + plot = $.plot(elem, sortedSeries, options); addAxisLabels(); } } + function translateFillOption(fill) { + return fill === 0 ? 0.001 : fill/10; + } + function shouldDelayDraw(panel) { if (panel.legend.rightSide) { return true; diff --git a/src/app/panels/graph/legend.html b/src/app/panels/graph/legend.html index 5524a8047fe..0e5edc459ce 100755 --- a/src/app/panels/graph/legend.html +++ b/src/app/panels/graph/legend.html @@ -34,12 +34,12 @@