module.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. define([
  2. 'angular',
  3. 'app',
  4. 'jquery',
  5. 'lodash',
  6. 'kbn',
  7. 'moment',
  8. 'components/timeSeries',
  9. './seriesOverridesCtrl',
  10. 'services/panelSrv',
  11. 'services/annotationsSrv',
  12. 'services/datasourceSrv',
  13. 'jquery.flot',
  14. 'jquery.flot.events',
  15. 'jquery.flot.selection',
  16. 'jquery.flot.time',
  17. 'jquery.flot.stack',
  18. 'jquery.flot.stackpercent',
  19. 'jquery.flot.crosshair'
  20. ],
  21. function (angular, app, $, _, kbn, moment, TimeSeries) {
  22. 'use strict';
  23. var module = angular.module('grafana.panels.graph');
  24. app.useModule(module);
  25. module.controller('GraphCtrl', function($scope, $rootScope, panelSrv, annotationsSrv, timeSrv) {
  26. $scope.panelMeta = {
  27. modals : [],
  28. editorTabs: [],
  29. fullEditorTabs : [
  30. {
  31. title: 'General',
  32. src:'app/partials/panelgeneral.html'
  33. },
  34. {
  35. title: 'Metrics',
  36. src:'app/partials/metrics.html'
  37. },
  38. {
  39. title:'Axes & Grid',
  40. src:'app/panels/graph/axisEditor.html'
  41. },
  42. {
  43. title:'Display Styles',
  44. src:'app/panels/graph/styleEditor.html'
  45. }
  46. ],
  47. fullscreenEdit: true,
  48. fullscreenView: true,
  49. description : "Graphing"
  50. };
  51. // Set and populate defaults
  52. var _d = {
  53. datasource: null,
  54. /** @scratch /panels/histogram/3
  55. * renderer:: sets client side (flot) or native graphite png renderer (png)
  56. */
  57. renderer: 'flot',
  58. /** @scratch /panels/histogram/3
  59. * x-axis:: Show the x-axis
  60. */
  61. 'x-axis' : true,
  62. /** @scratch /panels/histogram/3
  63. * y-axis:: Show the y-axis
  64. */
  65. 'y-axis' : true,
  66. /** @scratch /panels/histogram/3
  67. * scale:: Scale the y-axis by this factor
  68. */
  69. scale : 1,
  70. /** @scratch /panels/histogram/3
  71. * y_formats :: 'none','bytes','bits','bps','short', 's', 'ms'
  72. */
  73. y_formats : ['short', 'short'],
  74. /** @scratch /panels/histogram/5
  75. * grid object:: Min and max y-axis values
  76. * grid.min::: Minimum y-axis value
  77. * grid.ma1::: Maximum y-axis value
  78. */
  79. grid : {
  80. leftMax: null,
  81. rightMax: null,
  82. leftMin: null,
  83. rightMin: null,
  84. threshold1: null,
  85. threshold2: null,
  86. threshold1Color: 'rgba(216, 200, 27, 0.27)',
  87. threshold2Color: 'rgba(234, 112, 112, 0.22)'
  88. },
  89. annotate : {
  90. enable : false,
  91. },
  92. /** @scratch /panels/histogram/3
  93. * resolution:: If auto_int is true, shoot for this many bars.
  94. */
  95. resolution : 100,
  96. /** @scratch /panels/histogram/3
  97. * ==== Drawing options
  98. * lines:: Show line chart
  99. */
  100. lines : true,
  101. /** @scratch /panels/histogram/3
  102. * fill:: Area fill factor for line charts, 1-10
  103. */
  104. fill : 0,
  105. /** @scratch /panels/histogram/3
  106. * linewidth:: Weight of lines in pixels
  107. */
  108. linewidth : 1,
  109. /** @scratch /panels/histogram/3
  110. * points:: Show points on chart
  111. */
  112. points : false,
  113. /** @scratch /panels/histogram/3
  114. * pointradius:: Size of points in pixels
  115. */
  116. pointradius : 5,
  117. /** @scratch /panels/histogram/3
  118. * bars:: Show bars on chart
  119. */
  120. bars : false,
  121. /** @scratch /panels/histogram/3
  122. * stack:: Stack multiple series
  123. */
  124. stack : false,
  125. /** @scratch /panels/histogram/3
  126. * legend:: Display the legend
  127. */
  128. legend: {
  129. show: true, // disable/enable legend
  130. values: false, // disable/enable legend values
  131. min: false,
  132. max: false,
  133. current: false,
  134. total: false,
  135. avg: false
  136. },
  137. /** @scratch /panels/histogram/3
  138. * ==== Transformations
  139. /** @scratch /panels/histogram/3
  140. * percentage:: Show the y-axis as a percentage of the axis total. Only makes sense for multiple
  141. * queries
  142. */
  143. percentage : false,
  144. /** @scratch /panels/histogram/3
  145. * zerofill:: Improves the accuracy of line charts at a small performance cost.
  146. */
  147. zerofill : true,
  148. nullPointMode : 'connected',
  149. steppedLine: false,
  150. tooltip : {
  151. value_type: 'cumulative',
  152. shared: false,
  153. },
  154. targets: [{}],
  155. aliasColors: {},
  156. seriesOverrides: [],
  157. };
  158. _.defaults($scope.panel,_d);
  159. _.defaults($scope.panel.tooltip, _d.tooltip);
  160. _.defaults($scope.panel.annotate, _d.annotate);
  161. _.defaults($scope.panel.grid, _d.grid);
  162. _.defaults($scope.panel.legend, _d.legend);
  163. $scope.hiddenSeries = {};
  164. $scope.updateTimeRange = function () {
  165. $scope.range = timeSrv.timeRange();
  166. $scope.rangeUnparsed = timeSrv.timeRange(false);
  167. $scope.resolution = Math.ceil($(window).width() * ($scope.panel.span / 12));
  168. $scope.interval = kbn.calculateInterval($scope.range, $scope.resolution, $scope.panel.interval);
  169. };
  170. $scope.get_data = function() {
  171. $scope.updateTimeRange();
  172. var metricsQuery = {
  173. range: $scope.rangeUnparsed,
  174. interval: $scope.interval,
  175. targets: $scope.panel.targets,
  176. format: $scope.panel.renderer === 'png' ? 'png' : 'json',
  177. maxDataPoints: $scope.resolution,
  178. cacheTimeout: $scope.panel.cacheTimeout
  179. };
  180. $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.rangeUnparsed, $scope.dashboard);
  181. return $scope.datasource.query(metricsQuery)
  182. .then($scope.dataHandler)
  183. .then(null, function(err) {
  184. $scope.panelMeta.loading = false;
  185. $scope.panelMeta.error = err.message || "Timeseries data request error";
  186. $scope.inspector.error = err;
  187. $scope.render([]);
  188. });
  189. };
  190. $scope.dataHandler = function(results) {
  191. $scope.panelMeta.loading = false;
  192. $scope.legend = [];
  193. // png renderer returns just a url
  194. if (_.isString(results)) {
  195. $scope.render(results);
  196. return;
  197. }
  198. $scope.datapointsWarning = false;
  199. $scope.datapointsCount = 0;
  200. $scope.datapointsOutside = false;
  201. var data = _.map(results.data, $scope.seriesHandler);
  202. $scope.datapointsWarning = $scope.datapointsCount === 0 || $scope.datapointsOutside;
  203. $scope.annotationsPromise
  204. .then(function(annotations) {
  205. data.annotations = annotations;
  206. $scope.render(data);
  207. }, function() {
  208. $scope.render(data);
  209. });
  210. };
  211. $scope.seriesHandler = function(seriesData, index) {
  212. var datapoints = seriesData.datapoints;
  213. var alias = seriesData.target;
  214. var color = $scope.panel.aliasColors[alias] || $rootScope.colors[index];
  215. var seriesInfo = {
  216. alias: alias,
  217. color: color,
  218. };
  219. $scope.legend.push(seriesInfo);
  220. var series = new TimeSeries({
  221. datapoints: datapoints,
  222. info: seriesInfo,
  223. });
  224. if (datapoints && datapoints.length > 0) {
  225. var last = moment.utc(datapoints[datapoints.length - 1][1] * 1000);
  226. var from = moment.utc($scope.range.from);
  227. if (last - from < -10000) {
  228. $scope.datapointsOutside = true;
  229. }
  230. $scope.datapointsCount += datapoints.length;
  231. }
  232. return series;
  233. };
  234. $scope.render = function(data) {
  235. $scope.$emit('render', data);
  236. };
  237. $scope.changeSeriesColor = function(series, color) {
  238. series.color = color;
  239. $scope.panel.aliasColors[series.alias] = series.color;
  240. $scope.render();
  241. };
  242. $scope.toggleSeries = function(serie, event) {
  243. if ($scope.hiddenSeries[serie.alias]) {
  244. delete $scope.hiddenSeries[serie.alias];
  245. }
  246. else {
  247. $scope.hiddenSeries[serie.alias] = true;
  248. }
  249. if (event.ctrlKey || event.metaKey || event.shiftKey) {
  250. $scope.toggleSeriesExclusiveMode(serie);
  251. }
  252. $scope.$emit('toggleLegend', $scope.legend);
  253. };
  254. $scope.toggleSeriesExclusiveMode = function(serie) {
  255. var hidden = $scope.hiddenSeries;
  256. if (hidden[serie.alias]) {
  257. delete hidden[serie.alias];
  258. }
  259. // check if every other series is hidden
  260. var alreadyExclusive = _.every($scope.legend, function(value) {
  261. if (value.alias === serie.alias) {
  262. return true;
  263. }
  264. return hidden[value.alias];
  265. });
  266. if (alreadyExclusive) {
  267. // remove all hidden series
  268. _.each($scope.legend, function(value) {
  269. delete $scope.hiddenSeries[value.alias];
  270. });
  271. }
  272. else {
  273. // hide all but this serie
  274. _.each($scope.legend, function(value) {
  275. if (value.alias === serie.alias) {
  276. return;
  277. }
  278. $scope.hiddenSeries[value.alias] = true;
  279. });
  280. }
  281. };
  282. $scope.toggleYAxis = function(info) {
  283. var override = _.findWhere($scope.panel.seriesOverrides, { alias: info.alias });
  284. if (!override) {
  285. override = { alias: info.alias };
  286. $scope.panel.seriesOverrides.push(override);
  287. }
  288. override.yaxis = info.yaxis === 2 ? 1 : 2;
  289. $scope.render();
  290. };
  291. $scope.toggleGridMinMax = function(key) {
  292. $scope.panel.grid[key] = _.toggle($scope.panel.grid[key], null, 0);
  293. $scope.render();
  294. };
  295. $scope.addSeriesOverride = function() {
  296. $scope.panel.seriesOverrides.push({});
  297. };
  298. $scope.removeSeriesOverride = function(override) {
  299. $scope.panel.seriesOverrides = _.without($scope.panel.seriesOverrides, override);
  300. $scope.render();
  301. };
  302. $scope.toggleEditorHelp = function(index) {
  303. if ($scope.editorHelpIndex === index) {
  304. $scope.editorHelpIndex = null;
  305. return;
  306. }
  307. $scope.editorHelpIndex = index;
  308. };
  309. panelSrv.init($scope);
  310. });
  311. });