module.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. define([
  2. 'angular',
  3. 'app',
  4. 'jquery',
  5. 'lodash',
  6. 'kbn',
  7. 'moment',
  8. 'components/timeSeries',
  9. 'components/panelmeta',
  10. './seriesOverridesCtrl',
  11. './graph',
  12. './legend',
  13. ],
  14. function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
  15. 'use strict';
  16. var module = angular.module('grafana.panels.graph');
  17. module.controller('GraphCtrl', function($scope, $rootScope, panelSrv, annotationsSrv, timeSrv) {
  18. $scope.panelMeta = new PanelMeta({
  19. description: 'Graph panel',
  20. fullscreen: true,
  21. metricsEditor: true
  22. });
  23. $scope.panelMeta.addEditorTab('Axes & Grid', 'app/panels/graph/axisEditor.html');
  24. $scope.panelMeta.addEditorTab('Display Styles', 'app/panels/graph/styleEditor.html');
  25. $scope.panelMeta.addExtendedMenuItem('Export CSV', '', 'exportCsv()');
  26. $scope.panelMeta.addExtendedMenuItem('Toggle legend', '', 'toggleLegend()');
  27. // Set and populate defaults
  28. var _d = {
  29. // datasource name, null = default datasource
  30. datasource: null,
  31. // sets client side (flot) or native graphite png renderer (png)
  32. renderer: 'flot',
  33. // Show/hide the x-axis
  34. 'x-axis' : true,
  35. // Show/hide y-axis
  36. 'y-axis' : true,
  37. // y axis formats, [left axis,right axis]
  38. y_formats : ['short', 'short'],
  39. // grid options
  40. grid : {
  41. leftMax: null,
  42. rightMax: null,
  43. leftMin: null,
  44. rightMin: null,
  45. threshold1: null,
  46. threshold2: null,
  47. threshold1Color: 'rgba(216, 200, 27, 0.27)',
  48. threshold2Color: 'rgba(234, 112, 112, 0.22)'
  49. },
  50. // show/hide lines
  51. lines : true,
  52. // fill factor
  53. fill : 0,
  54. // line width in pixels
  55. linewidth : 1,
  56. // show hide points
  57. points : false,
  58. // point radius in pixels
  59. pointradius : 5,
  60. // show hide bars
  61. bars : false,
  62. // enable/disable stacking
  63. stack : false,
  64. // stack percentage mode
  65. percentage : false,
  66. // legend options
  67. legend: {
  68. show: true, // disable/enable legend
  69. values: false, // disable/enable legend values
  70. min: false,
  71. max: false,
  72. current: false,
  73. total: false,
  74. avg: false
  75. },
  76. // how null points should be handled
  77. nullPointMode : 'connected',
  78. // staircase line mode
  79. steppedLine: false,
  80. // tooltip options
  81. tooltip : {
  82. value_type: 'cumulative',
  83. shared: false,
  84. },
  85. // metric queries
  86. targets: [{}],
  87. // series color overrides
  88. aliasColors: {},
  89. // other style overrides
  90. seriesOverrides: [],
  91. };
  92. _.defaults($scope.panel,_d);
  93. _.defaults($scope.panel.tooltip, _d.tooltip);
  94. _.defaults($scope.panel.annotate, _d.annotate);
  95. _.defaults($scope.panel.grid, _d.grid);
  96. _.defaults($scope.panel.legend, _d.legend);
  97. $scope.hiddenSeries = {};
  98. $scope.seriesList = [];
  99. $scope.unitFormats = kbn.getUnitFormats();
  100. $scope.setUnitFormat = function(axis, subItem) {
  101. $scope.panel.y_formats[axis] = subItem.value;
  102. $scope.render();
  103. };
  104. $scope.updateTimeRange = function () {
  105. $scope.range = timeSrv.timeRange();
  106. $scope.rangeUnparsed = timeSrv.timeRange(false);
  107. if ($scope.panel.maxDataPoints) {
  108. $scope.resolution = $scope.panel.maxDataPoints;
  109. }
  110. else {
  111. $scope.resolution = Math.ceil($(window).width() * ($scope.panel.span / 12));
  112. }
  113. $scope.interval = kbn.calculateInterval($scope.range, $scope.resolution, $scope.panel.interval);
  114. };
  115. $scope.get_data = function() {
  116. $scope.updateTimeRange();
  117. var metricsQuery = {
  118. range: $scope.rangeUnparsed,
  119. interval: $scope.interval,
  120. targets: $scope.panel.targets,
  121. format: $scope.panel.renderer === 'png' ? 'png' : 'json',
  122. maxDataPoints: $scope.resolution,
  123. cacheTimeout: $scope.panel.cacheTimeout
  124. };
  125. $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.rangeUnparsed, $scope.dashboard);
  126. return $scope.datasource.query(metricsQuery)
  127. .then($scope.dataHandler)
  128. .then(null, function(err) {
  129. $scope.panelMeta.loading = false;
  130. $scope.panelMeta.error = err.message || "Timeseries data request error";
  131. $scope.inspector.error = err;
  132. $scope.seriesList = [];
  133. $scope.render([]);
  134. });
  135. };
  136. $scope.dataHandler = function(results) {
  137. // png renderer returns just a url
  138. if (_.isString(results)) {
  139. $scope.panelMeta.loading = false;
  140. $scope.render(results);
  141. return;
  142. }
  143. $scope.datapointsWarning = false;
  144. $scope.datapointsCount = 0;
  145. $scope.datapointsOutside = false;
  146. $scope.seriesList = _.map(results.data, $scope.seriesHandler);
  147. $scope.datapointsWarning = $scope.datapointsCount === 0 || $scope.datapointsOutside;
  148. $scope.annotationsPromise
  149. .then(function(annotations) {
  150. $scope.panelMeta.loading = false;
  151. $scope.seriesList.annotations = annotations;
  152. $scope.render($scope.seriesList);
  153. }, function() {
  154. $scope.panelMeta.loading = false;
  155. $scope.render($scope.seriesList);
  156. });
  157. };
  158. $scope.seriesHandler = function(seriesData, index) {
  159. var datapoints = seriesData.datapoints;
  160. var alias = seriesData.target;
  161. var color = $scope.panel.aliasColors[alias] || $rootScope.colors[index];
  162. var series = new TimeSeries({
  163. datapoints: datapoints,
  164. alias: alias,
  165. color: color,
  166. });
  167. if (datapoints && datapoints.length > 0) {
  168. var last = moment.utc(datapoints[datapoints.length - 1][1]);
  169. var from = moment.utc($scope.range.from);
  170. if (last - from < -10000) {
  171. $scope.datapointsOutside = true;
  172. }
  173. $scope.datapointsCount += datapoints.length;
  174. }
  175. return series;
  176. };
  177. $scope.render = function(data) {
  178. $scope.$broadcast('render', data);
  179. };
  180. $scope.changeSeriesColor = function(series, color) {
  181. series.color = color;
  182. $scope.panel.aliasColors[series.alias] = series.color;
  183. $scope.render();
  184. };
  185. $scope.toggleSeries = function(serie, event) {
  186. if (event.ctrlKey || event.metaKey || event.shiftKey) {
  187. if ($scope.hiddenSeries[serie.alias]) {
  188. delete $scope.hiddenSeries[serie.alias];
  189. }
  190. else {
  191. $scope.hiddenSeries[serie.alias] = true;
  192. }
  193. } else {
  194. $scope.toggleSeriesExclusiveMode(serie);
  195. }
  196. $scope.render();
  197. };
  198. $scope.toggleSeriesExclusiveMode = function(serie) {
  199. var hidden = $scope.hiddenSeries;
  200. if (hidden[serie.alias]) {
  201. delete hidden[serie.alias];
  202. }
  203. // check if every other series is hidden
  204. var alreadyExclusive = _.every($scope.seriesList, function(value) {
  205. if (value.alias === serie.alias) {
  206. return true;
  207. }
  208. return hidden[value.alias];
  209. });
  210. if (alreadyExclusive) {
  211. // remove all hidden series
  212. _.each($scope.seriesList, function(value) {
  213. delete $scope.hiddenSeries[value.alias];
  214. });
  215. }
  216. else {
  217. // hide all but this serie
  218. _.each($scope.seriesList, function(value) {
  219. if (value.alias === serie.alias) {
  220. return;
  221. }
  222. $scope.hiddenSeries[value.alias] = true;
  223. });
  224. }
  225. };
  226. $scope.toggleYAxis = function(info) {
  227. var override = _.findWhere($scope.panel.seriesOverrides, { alias: info.alias });
  228. if (!override) {
  229. override = { alias: info.alias };
  230. $scope.panel.seriesOverrides.push(override);
  231. }
  232. override.yaxis = info.yaxis === 2 ? 1 : 2;
  233. $scope.render();
  234. };
  235. $scope.addSeriesOverride = function(override) {
  236. $scope.panel.seriesOverrides.push(override || {});
  237. };
  238. $scope.removeSeriesOverride = function(override) {
  239. $scope.panel.seriesOverrides = _.without($scope.panel.seriesOverrides, override);
  240. $scope.render();
  241. };
  242. // Called from panel menu
  243. $scope.toggleLegend = function() {
  244. $scope.panel.legend.show = !$scope.panel.legend.show;
  245. $scope.get_data();
  246. };
  247. $scope.legendValuesOptionChanged = function() {
  248. var legend = $scope.panel.legend;
  249. legend.values = legend.min || legend.max || legend.avg || legend.current || legend.total;
  250. $scope.render();
  251. };
  252. $scope.exportCsv = function() {
  253. kbn.exportSeriesListToCsv($scope.seriesList);
  254. };
  255. panelSrv.init($scope);
  256. });
  257. });