module.js 9.6 KB

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