module.js 5.9 KB

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