module.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. ## Better maps
  3. So the cavaet for this panel is that, for better or worse, it does NOT use the terms facet and it
  4. DOES query sequentially. This however means that
  5. ### Parameters
  6. * query :: A single query string, not and array. This panel can only handle one
  7. query at a time.
  8. * size :: How many results to show, more results = slower
  9. * field :: field containing a 2 element array in the format [lon,lat]
  10. * tooltip :: field to extract the tool tip value from
  11. * spyable :: Show the 'eye' icon that reveals the last ES query
  12. ### Group Events
  13. #### Sends
  14. * get_time :: On panel initialization get time range to query
  15. #### Receives
  16. * time :: An object containing the time range to use and the index(es) to query
  17. * query :: An Array of queries, this panel uses only the first one
  18. */
  19. angular.module('kibana.bettermap', [])
  20. .controller('bettermap', function($scope, eventBus) {
  21. // Set and populate defaults
  22. var _d = {
  23. status : "Experimental",
  24. query : "*",
  25. size : 1000,
  26. spyable : true,
  27. tooltip : "_id",
  28. field : null,
  29. group : "default"
  30. }
  31. _.defaults($scope.panel,_d)
  32. $scope.init = function() {
  33. eventBus.register($scope,'time', function(event,time){set_time(time)});
  34. eventBus.register($scope,'query', function(event, query) {
  35. $scope.panel.query = _.isArray(query) ? query[0] : query;
  36. $scope.get_data();
  37. });
  38. // Now that we're all setup, request the time from our group
  39. eventBus.broadcast($scope.$id,$scope.panel.group,'get_time')
  40. }
  41. $scope.get_data = function(segment,query_id) {
  42. $scope.panel.error = false;
  43. // Make sure we have everything for the request to complete
  44. if(_.isUndefined($scope.index) || _.isUndefined($scope.time))
  45. return
  46. if(_.isUndefined($scope.panel.field)) {
  47. $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format"
  48. return
  49. }
  50. //$scope.panel.loading = true;
  51. var _segment = _.isUndefined(segment) ? 0 : segment
  52. $scope.segment = _segment;
  53. var request = $scope.ejs.Request().indices($scope.index[_segment])
  54. .query(ejs.FilteredQuery(
  55. ejs.QueryStringQuery(($scope.panel.query || '*') + " AND _exists_:"+$scope.panel.field),
  56. ejs.RangeFilter($scope.time.field)
  57. .from($scope.time.from)
  58. .to($scope.time.to)
  59. )
  60. )
  61. .fields([$scope.panel.field,$scope.panel.tooltip])
  62. .size($scope.panel.size)
  63. .sort($scope.time.field,'desc');
  64. $scope.populate_modal(request)
  65. var results = request.doSearch()
  66. // Populate scope when we have results
  67. results.then(function(results) {
  68. $scope.panel.loading = false;
  69. if(_segment === 0) {
  70. $scope.hits = 0;
  71. $scope.data = [];
  72. query_id = $scope.query_id = new Date().getTime()
  73. }
  74. // Check for error and abort if found
  75. if(!(_.isUndefined(results.error))) {
  76. $scope.panel.error = $scope.parse_error(results.error);
  77. return;
  78. }
  79. // Check that we're still on the same query, if not stop
  80. if($scope.query_id === query_id) {
  81. var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait()
  82. scripts.wait(function(){
  83. $scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) {
  84. return {
  85. coordinates : new L.LatLng(hit.fields[$scope.panel.field][1],hit.fields[$scope.panel.field][0]),
  86. tooltip : hit.fields[$scope.panel.tooltip]
  87. }
  88. }));
  89. });
  90. // Keep only what we need for the set
  91. $scope.data = $scope.data.slice(0,$scope.panel.size)
  92. } else {
  93. return;
  94. }
  95. $scope.$emit('draw')
  96. // Get $size results then stop querying
  97. if($scope.data.length < $scope.panel.size && _segment+1 < $scope.index.length)
  98. $scope.get_data(_segment+1,$scope.query_id)
  99. });
  100. }
  101. // I really don't like this function, too much dom manip. Break out into directive?
  102. $scope.populate_modal = function(request) {
  103. $scope.modal = {
  104. title: "Inspector",
  105. body : "<h5>Last Elasticsearch Query</h5><pre>"+
  106. 'curl -XGET '+config.elasticsearch+'/'+$scope.index+"/_search?pretty -d'\n"+
  107. angular.toJson(JSON.parse(request.toString()),true)+
  108. "'</pre>",
  109. }
  110. }
  111. function set_time(time) {
  112. $scope.time = time;
  113. $scope.index = _.isUndefined(time.index) ? $scope.index : time.index
  114. $scope.get_data();
  115. }
  116. $scope.build_search = function(field,value) {
  117. $scope.panel.query = add_to_query($scope.panel.query,field,value,false)
  118. $scope.get_data();
  119. eventBus.broadcast($scope.$id,$scope.panel.group,'query',[$scope.panel.query]);
  120. }
  121. })
  122. .directive('bettermap', function() {
  123. return {
  124. restrict: 'A',
  125. link: function(scope, elem, attrs) {
  126. elem.html('<center><img src="common/img/load_big.gif"></center>')
  127. // Receive render events
  128. scope.$on('draw',function(){
  129. render_panel();
  130. });
  131. scope.$on('render', function(){
  132. if(!_.isUndefined(map)) {
  133. map.invalidateSize();
  134. var panes = map.getPanes()
  135. }
  136. })
  137. var map, markers, layerGroup, mcg;
  138. function render_panel() {
  139. scope.panel.loading = false;
  140. var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait()
  141. .script("panels/bettermap/lib/plugins.js")
  142. //add markers dynamically
  143. scripts.wait(function(){
  144. if(_.isUndefined(map)) {
  145. map = L.map(attrs.id, {
  146. scrollWheelZoom: false,
  147. center: [40, -86],
  148. zoom: 10
  149. });
  150. L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/22677/256/{z}/{x}/{y}.png', {
  151. maxZoom: 18,
  152. minZoom: 2
  153. }).addTo(map);
  154. layerGroup = new L.MarkerClusterGroup({maxClusterRadius:30});
  155. } else {
  156. layerGroup.clearLayers();
  157. }
  158. _.each(scope.data, function(p) {
  159. if(!_.isUndefined(p.tooltip) && p.tooltip !== '')
  160. layerGroup.addLayer(L.marker(p.coordinates).bindLabel(p.tooltip))
  161. else
  162. layerGroup.addLayer(L.marker(p.coordinates))
  163. })
  164. layerGroup.addTo(map)
  165. map.fitBounds(_.pluck(scope.data,'coordinates'));
  166. })
  167. }
  168. }
  169. };
  170. });