module.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. ## Map
  3. LOL. Should this even be documented? Zach's map panel is going to ruin this one.
  4. For serious. This shades a map of the world, the US or Europe with the number of
  5. events that match the query. Uses 2 letter country codes and nothing else. This uses
  6. a terms facet. Its probably safe as long as you point it at the right field. Nach.
  7. There's no way to query sequentially here, so I'm going to hit them all at once!
  8. ### Parameters
  9. * query :: A single query string, not and array. This panel can only handle one
  10. query at a time.
  11. * map :: 'world', 'us' or 'europe'
  12. * colors :: an array of colors to use for the regions of the map. If this is a 2
  13. element array, jquerymap will generate shades between these colors
  14. * size :: How big to make the facet. Higher = more countries
  15. * exclude :: Exlude the array of counties
  16. * spyable :: Show the 'eye' icon that reveals the last ES query
  17. * index_limit :: This does nothing yet. Eventually will limit the query to the first
  18. N indices
  19. ### Group Events
  20. #### Sends
  21. * get_time :: On panel initialization get time range to query
  22. #### Receives
  23. * time :: An object containing the time range to use and the index(es) to query
  24. * query :: An Array of queries, this panel uses only the first one
  25. */
  26. angular.module('kibana.map', [])
  27. .controller('map', function($scope, $rootScope, eventBus, query, dashboard, filterSrv) {
  28. // Set and populate defaults
  29. var _d = {
  30. status : "Beta",
  31. query : "*",
  32. map : "world",
  33. colors : ['#A0E2E2', '#265656'],
  34. size : 100,
  35. exclude : [],
  36. spyable : true,
  37. group : "default",
  38. index_limit : 0
  39. }
  40. _.defaults($scope.panel,_d)
  41. $scope.init = function() {
  42. $scope.$on('refresh',function(){$scope.get_data()})
  43. $scope.get_data();
  44. }
  45. $scope.get_data = function() {
  46. // Make sure we have everything for the request to complete
  47. if(dashboard.indices.length == 0) {
  48. return
  49. }
  50. $scope.panel.loading = true;
  51. var request = $scope.ejs.Request().indices(dashboard.indices);
  52. var boolQuery = ejs.BoolQuery();
  53. _.each(query.list,function(q) {
  54. boolQuery = boolQuery.should(ejs.QueryStringQuery(q.query || '*'))
  55. })
  56. // Then the insert into facet and make the request
  57. var request = request
  58. .facet(ejs.TermsFacet('map')
  59. .field($scope.panel.field)
  60. .size($scope.panel['size'])
  61. .exclude($scope.panel.exclude)
  62. .facetFilter(ejs.QueryFilter(
  63. ejs.FilteredQuery(
  64. boolQuery,
  65. filterSrv.getBoolFilter(filterSrv.ids)
  66. )))).size(0);
  67. $scope.populate_modal(request);
  68. var results = request.doSearch();
  69. // Populate scope when we have results
  70. results.then(function(results) {
  71. $scope.panel.loading = false;
  72. $scope.hits = results.hits.total;
  73. $scope.data = {};
  74. _.each(results.facets.map.terms, function(v) {
  75. $scope.data[v.term.toUpperCase()] = v.count;
  76. });
  77. $scope.$emit('render')
  78. });
  79. }
  80. // I really don't like this function, too much dom manip. Break out into directive?
  81. $scope.populate_modal = function(request) {
  82. $scope.modal = {
  83. title: "Inspector",
  84. body : "<h5>Last Elasticsearch Query</h5><pre>"+
  85. 'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+
  86. angular.toJson(JSON.parse(request.toString()),true)+
  87. "'</pre>",
  88. }
  89. }
  90. $scope.build_search = function(field,value) {
  91. _.each(query.list,function(q) {
  92. q.query = add_to_query(q.query,field,value,false);
  93. })
  94. dashboard.refresh();
  95. }
  96. })
  97. .directive('map', function() {
  98. return {
  99. restrict: 'A',
  100. link: function(scope, elem, attrs) {
  101. elem.html('<center><img src="common/img/load_big.gif"></center>')
  102. // Receive render events
  103. scope.$on('render',function(){
  104. render_panel();
  105. });
  106. // Or if the window is resized
  107. angular.element(window).bind('resize', function(){
  108. render_panel();
  109. });
  110. function render_panel() {
  111. // Using LABjs, wait until all scripts are loaded before rendering panel
  112. var scripts = $LAB.script("panels/map/lib/jquery.jvectormap.min.js").wait()
  113. .script("panels/map/lib/map."+scope.panel.map+".js")
  114. // Populate element. Note that jvectormap appends, does not replace.
  115. scripts.wait(function(){
  116. elem.text('');
  117. $('.jvectormap-zoomin,.jvectormap-zoomout,.jvectormap-label').remove();
  118. var map = elem.vectorMap({
  119. map: scope.panel.map,
  120. regionStyle: {initial: {fill: '#8c8c8c'}},
  121. zoomOnScroll: false,
  122. backgroundColor: null,
  123. series: {
  124. regions: [{
  125. values: scope.data,
  126. scale: scope.panel.colors,
  127. normalizeFunction: 'polynomial'
  128. }]
  129. },
  130. onRegionLabelShow: function(event, label, code){
  131. elem.children('.map-legend').show()
  132. var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
  133. elem.children('.map-legend').text(label.text() + ": " + count);
  134. },
  135. onRegionOut: function(event, code) {
  136. $('.map-legend').hide();
  137. },
  138. onRegionClick: function(event, code) {
  139. var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
  140. if (count != 0)
  141. scope.build_search(scope.panel.field,code)
  142. }
  143. });
  144. elem.prepend('<span class="map-legend"></span>');
  145. $('.map-legend').hide();
  146. })
  147. }
  148. }
  149. };
  150. });