module.js 11 KB

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