mirror of https://github.com/grafana/grafana
Merge pull request #167 from rashidkpc/master
Added bettermap panel and plugin status messagespull/7/head
commit
1dbedff432
@ -0,0 +1,42 @@ |
||||
<div class="row-fluid"> |
||||
<div class="span11"> |
||||
This panel uses geoJSON points in a field to place markers on a map. |
||||
Coordinates <strong>must be stored as an array in Elasticsearch</strong>. |
||||
Also note that geoJSON is <strong>long,lat NOT lat,long</strong>. |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="row-fluid"> |
||||
<div class="span11"> |
||||
<h6>Query</h6> |
||||
<input type="text" style="width:100%" ng-model="panel.query"> |
||||
</div> |
||||
</div> |
||||
<div class="row-fluid"> |
||||
<div class="span4"> |
||||
<form> |
||||
<h6>Coordinate Field</h6> |
||||
<input bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.field"> |
||||
</form> |
||||
</div> |
||||
<div class="span4"> |
||||
<form> |
||||
<h6>Tooltip Field</h6> |
||||
<input bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.tooltip"> |
||||
</form> |
||||
</div> |
||||
<div class="span2"><h6>Max Points</h6> |
||||
<input type="number" class="input-small" ng-model="panel.size"> |
||||
</div> |
||||
</div> |
||||
<h5>Panel Spy</h5> |
||||
<div class="row-fluid"> |
||||
<div class="span2"> |
||||
<label class="small"> Spyable </label><input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable"> |
||||
</div> |
||||
<div class="span9 small"> |
||||
The panel spy shows 'behind the scenes' information about a panel. It can |
||||
be accessed by clicking the <i class='icon-eye-open'></i> in the top right |
||||
of the panel. |
||||
</div> |
||||
</div> |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 797 B |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,463 @@ |
||||
/* required styles */ |
||||
|
||||
.leaflet-map-pane, |
||||
.leaflet-tile, |
||||
.leaflet-marker-icon, |
||||
.leaflet-marker-shadow, |
||||
.leaflet-tile-pane, |
||||
.leaflet-tile-container, |
||||
.leaflet-overlay-pane, |
||||
.leaflet-shadow-pane, |
||||
.leaflet-marker-pane, |
||||
.leaflet-popup-pane, |
||||
.leaflet-overlay-pane svg, |
||||
.leaflet-zoom-box, |
||||
.leaflet-image-layer, |
||||
.leaflet-layer { |
||||
position: absolute; |
||||
left: 0; |
||||
top: 0; |
||||
} |
||||
.leaflet-container { |
||||
overflow: hidden; |
||||
-ms-touch-action: none; |
||||
} |
||||
.leaflet-tile, |
||||
.leaflet-marker-icon, |
||||
.leaflet-marker-shadow { |
||||
-webkit-user-select: none; |
||||
-moz-user-select: none; |
||||
user-select: none; |
||||
-webkit-user-drag: none; |
||||
} |
||||
.leaflet-marker-icon, |
||||
.leaflet-marker-shadow { |
||||
display: block; |
||||
} |
||||
/* map is broken in FF if you have max-width: 100% on tiles */ |
||||
.leaflet-container img { |
||||
max-width: none !important; |
||||
} |
||||
/* stupid Android 2 doesn't understand "max-width: none" properly */ |
||||
.leaflet-container img.leaflet-image-layer { |
||||
max-width: 15000px !important; |
||||
} |
||||
.leaflet-tile { |
||||
filter: inherit; |
||||
visibility: hidden; |
||||
} |
||||
.leaflet-tile-loaded { |
||||
visibility: inherit; |
||||
} |
||||
.leaflet-zoom-box { |
||||
width: 0; |
||||
height: 0; |
||||
} |
||||
|
||||
.leaflet-tile-pane { z-index: 2; } |
||||
.leaflet-objects-pane { z-index: 3; } |
||||
.leaflet-overlay-pane { z-index: 4; } |
||||
.leaflet-shadow-pane { z-index: 5; } |
||||
.leaflet-marker-pane { z-index: 6; } |
||||
.leaflet-popup-pane { z-index: 7; } |
||||
|
||||
|
||||
/* control positioning */ |
||||
|
||||
.leaflet-control { |
||||
position: relative; |
||||
z-index: 7; |
||||
pointer-events: auto; |
||||
} |
||||
.leaflet-top, |
||||
.leaflet-bottom { |
||||
position: absolute; |
||||
z-index: 1000; |
||||
pointer-events: none; |
||||
} |
||||
.leaflet-top { |
||||
top: 0; |
||||
} |
||||
.leaflet-right { |
||||
right: 0; |
||||
} |
||||
.leaflet-bottom { |
||||
bottom: 0; |
||||
} |
||||
.leaflet-left { |
||||
left: 0; |
||||
} |
||||
.leaflet-control { |
||||
float: left; |
||||
clear: both; |
||||
} |
||||
.leaflet-right .leaflet-control { |
||||
float: right; |
||||
} |
||||
.leaflet-top .leaflet-control { |
||||
margin-top: 10px; |
||||
} |
||||
.leaflet-bottom .leaflet-control { |
||||
margin-bottom: 10px; |
||||
} |
||||
.leaflet-left .leaflet-control { |
||||
margin-left: 10px; |
||||
} |
||||
.leaflet-right .leaflet-control { |
||||
margin-right: 10px; |
||||
} |
||||
|
||||
|
||||
/* zoom and fade animations */ |
||||
|
||||
.leaflet-fade-anim .leaflet-tile, |
||||
.leaflet-fade-anim .leaflet-popup { |
||||
opacity: 0; |
||||
-webkit-transition: opacity 0.2s linear; |
||||
-moz-transition: opacity 0.2s linear; |
||||
-o-transition: opacity 0.2s linear; |
||||
transition: opacity 0.2s linear; |
||||
} |
||||
.leaflet-fade-anim .leaflet-tile-loaded, |
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { |
||||
opacity: 1; |
||||
} |
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated { |
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); |
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); |
||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); |
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1); |
||||
} |
||||
.leaflet-zoom-anim .leaflet-tile, |
||||
.leaflet-pan-anim .leaflet-tile, |
||||
.leaflet-touching .leaflet-zoom-animated { |
||||
-webkit-transition: none; |
||||
-moz-transition: none; |
||||
-o-transition: none; |
||||
transition: none; |
||||
} |
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
|
||||
/* cursors */ |
||||
|
||||
.leaflet-clickable { |
||||
cursor: pointer; |
||||
} |
||||
.leaflet-container { |
||||
cursor: -webkit-grab; |
||||
cursor: -moz-grab; |
||||
} |
||||
.leaflet-popup-pane, |
||||
.leaflet-control { |
||||
cursor: auto; |
||||
} |
||||
.leaflet-dragging, |
||||
.leaflet-dragging .leaflet-clickable, |
||||
.leaflet-dragging .leaflet-container { |
||||
cursor: move; |
||||
cursor: -webkit-grabbing; |
||||
cursor: -moz-grabbing; |
||||
} |
||||
|
||||
|
||||
/* visual tweaks */ |
||||
|
||||
.leaflet-container { |
||||
background: #ddd; |
||||
outline: 0; |
||||
} |
||||
.leaflet-container a { |
||||
color: #0078A8; |
||||
} |
||||
.leaflet-container a.leaflet-active { |
||||
outline: 2px solid orange; |
||||
} |
||||
.leaflet-zoom-box { |
||||
border: 2px dotted #05f; |
||||
background: white; |
||||
opacity: 0.5; |
||||
} |
||||
|
||||
|
||||
/* general typography */ |
||||
.leaflet-container { |
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; |
||||
} |
||||
|
||||
|
||||
/* general toolbar styles */ |
||||
|
||||
.leaflet-bar { |
||||
box-shadow: 0 1px 7px rgba(0,0,0,0.65); |
||||
-webkit-border-radius: 4px; |
||||
border-radius: 4px; |
||||
} |
||||
.leaflet-bar a { |
||||
background-color: #fff; |
||||
border-bottom: 1px solid #ccc; |
||||
width: 26px; |
||||
height: 26px; |
||||
line-height: 26px; |
||||
display: block; |
||||
text-align: center; |
||||
text-decoration: none; |
||||
color: black; |
||||
} |
||||
.leaflet-bar a, |
||||
.leaflet-control-layers-toggle { |
||||
background-position: 50% 50%; |
||||
background-repeat: no-repeat; |
||||
display: block; |
||||
} |
||||
.leaflet-bar a:hover { |
||||
background-color: #f4f4f4; |
||||
} |
||||
.leaflet-bar a:first-child { |
||||
-webkit-border-top-left-radius: 4px; |
||||
border-top-left-radius: 4px; |
||||
-webkit-border-top-right-radius: 4px; |
||||
border-top-right-radius: 4px; |
||||
} |
||||
.leaflet-bar a:last-child { |
||||
-webkit-border-bottom-left-radius: 4px; |
||||
border-bottom-left-radius: 4px; |
||||
-webkit-border-bottom-right-radius: 4px; |
||||
border-bottom-right-radius: 4px; |
||||
border-bottom: none; |
||||
} |
||||
.leaflet-bar a.leaflet-disabled { |
||||
cursor: default; |
||||
background-color: #f4f4f4; |
||||
color: #bbb; |
||||
} |
||||
|
||||
.leaflet-touch .leaflet-bar { |
||||
-webkit-border-radius: 10px; |
||||
border-radius: 10px; |
||||
} |
||||
.leaflet-touch .leaflet-bar a { |
||||
width: 30px; |
||||
height: 30px; |
||||
} |
||||
.leaflet-touch .leaflet-bar a:first-child { |
||||
-webkit-border-top-left-radius: 7px; |
||||
border-top-left-radius: 7px; |
||||
-webkit-border-top-right-radius: 7px; |
||||
border-top-right-radius: 7px; |
||||
} |
||||
.leaflet-touch .leaflet-bar a:last-child { |
||||
-webkit-border-bottom-left-radius: 7px; |
||||
border-bottom-left-radius: 7px; |
||||
-webkit-border-bottom-right-radius: 7px; |
||||
border-bottom-right-radius: 7px; |
||||
border-bottom: none; |
||||
} |
||||
|
||||
|
||||
/* zoom control */ |
||||
|
||||
.leaflet-control-zoom-in { |
||||
font: bold 18px 'Lucida Console', Monaco, monospace; |
||||
} |
||||
.leaflet-control-zoom-out { |
||||
font: bold 22px 'Lucida Console', Monaco, monospace; |
||||
} |
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in { |
||||
font-size: 22px; |
||||
line-height: 30px; |
||||
} |
||||
.leaflet-touch .leaflet-control-zoom-out { |
||||
font-size: 28px; |
||||
line-height: 30px; |
||||
} |
||||
|
||||
|
||||
/* layers control */ |
||||
|
||||
.leaflet-control-layers { |
||||
box-shadow: 0 1px 7px rgba(0,0,0,0.4); |
||||
background: #f8f8f9; |
||||
-webkit-border-radius: 5px; |
||||
border-radius: 5px; |
||||
} |
||||
.leaflet-control-layers-toggle { |
||||
background-image: url(images/layers.png); |
||||
width: 36px; |
||||
height: 36px; |
||||
} |
||||
.leaflet-retina .leaflet-control-layers-toggle { |
||||
background-image: url(images/layers-2x.png); |
||||
background-size: 26px 26px; |
||||
} |
||||
.leaflet-touch .leaflet-control-layers-toggle { |
||||
width: 44px; |
||||
height: 44px; |
||||
} |
||||
.leaflet-control-layers .leaflet-control-layers-list, |
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle { |
||||
display: none; |
||||
} |
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list { |
||||
display: block; |
||||
position: relative; |
||||
} |
||||
.leaflet-control-layers-expanded { |
||||
padding: 6px 10px 6px 6px; |
||||
color: #333; |
||||
background: #fff; |
||||
} |
||||
.leaflet-control-layers-selector { |
||||
margin-top: 2px; |
||||
position: relative; |
||||
top: 1px; |
||||
} |
||||
.leaflet-control-layers label { |
||||
display: block; |
||||
} |
||||
.leaflet-control-layers-separator { |
||||
height: 0; |
||||
border-top: 1px solid #ddd; |
||||
margin: 5px -10px 5px -6px; |
||||
} |
||||
|
||||
|
||||
/* attribution and scale controls */ |
||||
|
||||
.leaflet-container .leaflet-control-attribution { |
||||
background-color: rgba(255, 255, 255, 0.7); |
||||
box-shadow: 0 0 5px #bbb; |
||||
margin: 0; |
||||
} |
||||
.leaflet-control-attribution, |
||||
.leaflet-control-scale-line { |
||||
padding: 0 5px; |
||||
color: #333; |
||||
} |
||||
.leaflet-container .leaflet-control-attribution, |
||||
.leaflet-container .leaflet-control-scale { |
||||
font-size: 11px; |
||||
} |
||||
.leaflet-left .leaflet-control-scale { |
||||
margin-left: 5px; |
||||
} |
||||
.leaflet-bottom .leaflet-control-scale { |
||||
margin-bottom: 5px; |
||||
} |
||||
.leaflet-control-scale-line { |
||||
border: 2px solid #777; |
||||
border-top: none; |
||||
color: black; |
||||
line-height: 1.1; |
||||
padding: 2px 5px 1px; |
||||
font-size: 11px; |
||||
text-shadow: 1px 1px 1px #fff; |
||||
background-color: rgba(255, 255, 255, 0.5); |
||||
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2); |
||||
white-space: nowrap; |
||||
overflow: hidden; |
||||
} |
||||
.leaflet-control-scale-line:not(:first-child) { |
||||
border-top: 2px solid #777; |
||||
border-bottom: none; |
||||
margin-top: -2px; |
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); |
||||
} |
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) { |
||||
border-bottom: 2px solid #777; |
||||
} |
||||
|
||||
.leaflet-touch .leaflet-control-attribution, |
||||
.leaflet-touch .leaflet-control-layers, |
||||
.leaflet-touch .leaflet-control-zoom { |
||||
box-shadow: none; |
||||
} |
||||
.leaflet-touch .leaflet-control-layers, |
||||
.leaflet-touch .leaflet-control-zoom { |
||||
border: 4px solid rgba(0,0,0,0.3); |
||||
} |
||||
|
||||
|
||||
/* popup */ |
||||
|
||||
.leaflet-popup { |
||||
position: absolute; |
||||
text-align: center; |
||||
} |
||||
.leaflet-popup-content-wrapper { |
||||
padding: 1px; |
||||
text-align: left; |
||||
-webkit-border-radius: 12px; |
||||
border-radius: 12px; |
||||
} |
||||
.leaflet-popup-content { |
||||
margin: 13px 19px; |
||||
line-height: 1.4; |
||||
} |
||||
.leaflet-popup-content p { |
||||
margin: 18px 0; |
||||
} |
||||
.leaflet-popup-tip-container { |
||||
margin: 0 auto; |
||||
width: 40px; |
||||
height: 20px; |
||||
position: relative; |
||||
overflow: hidden; |
||||
} |
||||
.leaflet-popup-tip { |
||||
width: 17px; |
||||
height: 17px; |
||||
padding: 1px; |
||||
|
||||
margin: -10px auto 0; |
||||
|
||||
-webkit-transform: rotate(45deg); |
||||
-moz-transform: rotate(45deg); |
||||
-ms-transform: rotate(45deg); |
||||
-o-transform: rotate(45deg); |
||||
transform: rotate(45deg); |
||||
} |
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip { |
||||
background: white; |
||||
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4); |
||||
} |
||||
.leaflet-container a.leaflet-popup-close-button { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
padding: 4px 4px 0 0; |
||||
text-align: center; |
||||
width: 18px; |
||||
height: 14px; |
||||
font: 16px/14px Tahoma, Verdana, sans-serif; |
||||
color: #c3c3c3; |
||||
text-decoration: none; |
||||
font-weight: bold; |
||||
background: transparent; |
||||
} |
||||
.leaflet-container a.leaflet-popup-close-button:hover { |
||||
color: #999; |
||||
} |
||||
.leaflet-popup-scrolled { |
||||
overflow: auto; |
||||
border-bottom: 1px solid #ddd; |
||||
border-top: 1px solid #ddd; |
||||
} |
||||
|
||||
|
||||
/* div icon */ |
||||
|
||||
.leaflet-div-icon { |
||||
background: #fff; |
||||
border: 1px solid #666; |
||||
} |
||||
.leaflet-editing-icon { |
||||
-webkit-border-radius: 2px; |
||||
border-radius: 2px; |
||||
} |
@ -0,0 +1,51 @@ |
||||
.leaflet-vml-shape { |
||||
width: 1px; |
||||
height: 1px; |
||||
} |
||||
.lvml { |
||||
behavior: url(#default#VML); |
||||
display: inline-block; |
||||
position: absolute; |
||||
} |
||||
|
||||
.leaflet-control { |
||||
display: inline; |
||||
} |
||||
|
||||
.leaflet-popup-tip { |
||||
width: 21px; |
||||
_width: 27px; |
||||
margin: 0 auto; |
||||
_margin-top: -3px; |
||||
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); |
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; |
||||
} |
||||
.leaflet-popup-tip-container { |
||||
margin-top: -1px; |
||||
} |
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip { |
||||
border: 1px solid #999; |
||||
} |
||||
.leaflet-popup-content-wrapper { |
||||
zoom: 1; |
||||
} |
||||
|
||||
.leaflet-control-zoom, |
||||
.leaflet-control-layers { |
||||
border: 3px solid #999; |
||||
} |
||||
.leaflet-control-layers-toggle { |
||||
} |
||||
.leaflet-control-attribution, |
||||
.leaflet-control-layers, |
||||
.leaflet-control-scale-line { |
||||
background: white; |
||||
} |
||||
.leaflet-zoom-box { |
||||
filter: alpha(opacity=50); |
||||
} |
||||
.leaflet-control-attribution { |
||||
border-top: 1px solid #bbb; |
||||
border-left: 1px solid #bbb; |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,75 @@ |
||||
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { |
||||
-webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in; |
||||
-moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in; |
||||
-o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in; |
||||
transition: transform 0.2s ease-out, opacity 0.2s ease-in; |
||||
} |
||||
.marker-cluster-small { |
||||
background-color: rgba(181, 226, 140, 0.6); |
||||
} |
||||
.marker-cluster-small div { |
||||
background-color: rgba(110, 204, 57, 0.6); |
||||
} |
||||
|
||||
.marker-cluster-medium { |
||||
background-color: rgba(241, 211, 87, 0.6); |
||||
} |
||||
.marker-cluster-medium div { |
||||
background-color: rgba(240, 194, 12, 0.6); |
||||
} |
||||
|
||||
.marker-cluster-large { |
||||
background-color: rgba(253, 156, 115, 0.6); |
||||
} |
||||
.marker-cluster-large div { |
||||
background-color: rgba(241, 128, 23, 0.6); |
||||
} |
||||
|
||||
.marker-cluster { |
||||
background-clip: padding-box; |
||||
border-radius: 20px; |
||||
} |
||||
.marker-cluster div { |
||||
width: 30px; |
||||
height: 30px; |
||||
margin-left: 5px; |
||||
margin-top: 5px; |
||||
|
||||
text-align: center; |
||||
border-radius: 15px; |
||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; |
||||
} |
||||
.marker-cluster span { |
||||
line-height: 30px; |
||||
} |
||||
|
||||
.leaflet-label { |
||||
background: #1f1f1f; |
||||
background-clip: padding-box; |
||||
border-radius: 4px; |
||||
border-style: solid; |
||||
border-width: 0px; |
||||
display: block; |
||||
font-weight: 200; |
||||
font-size: 11pt; |
||||
padding: 5px; |
||||
position: absolute; |
||||
-webkit-user-select: none; |
||||
-moz-user-select: none; |
||||
-ms-user-select: none; |
||||
user-select: none; |
||||
white-space: nowrap; |
||||
z-index: 99999 !important; |
||||
} |
||||
|
||||
.leaflet-label:before { |
||||
border-right: 6px solid black; |
||||
border-right-color: inherit; |
||||
border-top: 6px solid transparent; |
||||
border-bottom: 6px solid transparent; |
||||
content: ""; |
||||
position: absolute; |
||||
top: 5px; |
||||
left: -10px; |
||||
display: none; |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,13 @@ |
||||
<kibana-panel ng-controller='bettermap' ng-init="init()"> |
||||
<!-- questionable if this is allowed in HTML5 --> |
||||
<link rel="stylesheet" href="panels/bettermap/lib/leaflet.css" /> |
||||
<link rel="stylesheet" href="panels/bettermap/lib/plugins.css" /> |
||||
|
||||
<span ng-show="panel.spyable" style="position:absolute;right:0px;top:0px" class='panelextra pointer'> |
||||
<i bs-modal="'partials/modal.html'" class="icon-eye-open"></i> |
||||
</span> |
||||
<!-- This solution might work well for other panels that have trouble with heights --> |
||||
<div style="padding-right:10px;padding-top:10px;height:{{panel.height|| row.height}};overflow:hidden"> |
||||
<div bettermap id='bettermap' params="{{panel}}" style="height:100%"></div> |
||||
</div> |
||||
</kibana-panel> |
@ -0,0 +1,211 @@ |
||||
/* |
||||
|
||||
## Better maps |
||||
|
||||
So the cavaet for this panel is that, for better or worse, it does NOT use the terms facet and it |
||||
DOES query sequentially. This however means that |
||||
|
||||
### Parameters |
||||
* query :: A single query string, not and array. This panel can only handle one |
||||
query at a time.
|
||||
* size :: How many results to show, more results = slower |
||||
* field :: field containing a 2 element array in the format [lon,lat] |
||||
* tooltip :: field to extract the tool tip value from |
||||
* spyable :: Show the 'eye' icon that reveals the last ES query |
||||
|
||||
### Group Events |
||||
#### Sends |
||||
* get_time :: On panel initialization get time range to query |
||||
#### Receives |
||||
* time :: An object containing the time range to use and the index(es) to query |
||||
* query :: An Array of queries, this panel uses only the first one |
||||
*/ |
||||
|
||||
angular.module('kibana.bettermap', []) |
||||
.controller('bettermap', function($scope, eventBus) { |
||||
|
||||
// Set and populate defaults
|
||||
var _d = { |
||||
status : "Experimental", |
||||
query : "*", |
||||
size : 1000, |
||||
spyable : true, |
||||
tooltip : "_id", |
||||
field : null, |
||||
group : "default" |
||||
} |
||||
_.defaults($scope.panel,_d) |
||||
|
||||
$scope.init = function() { |
||||
eventBus.register($scope,'time', function(event,time){set_time(time)}); |
||||
eventBus.register($scope,'query', function(event, query) { |
||||
$scope.panel.query = _.isArray(query) ? query[0] : query; |
||||
$scope.get_data(); |
||||
}); |
||||
|
||||
// Now that we're all setup, request the time from our group
|
||||
eventBus.broadcast($scope.$id,$scope.panel.group,'get_time') |
||||
} |
||||
|
||||
$scope.get_data = function(segment,query_id) { |
||||
$scope.panel.error = false; |
||||
|
||||
// Make sure we have everything for the request to complete
|
||||
if(_.isUndefined($scope.index) || _.isUndefined($scope.time)) |
||||
return |
||||
|
||||
if(_.isUndefined($scope.panel.field)) { |
||||
$scope.panel.error = "Please select a field that contains geo point in [lon,lat] format" |
||||
return |
||||
} |
||||
|
||||
//$scope.panel.loading = true;
|
||||
|
||||
var _segment = _.isUndefined(segment) ? 0 : segment |
||||
$scope.segment = _segment; |
||||
|
||||
var request = $scope.ejs.Request().indices($scope.index[_segment]) |
||||
.query(ejs.FilteredQuery( |
||||
ejs.QueryStringQuery(($scope.panel.query || '*') + " AND _exists_:"+$scope.panel.field), |
||||
ejs.RangeFilter($scope.time.field) |
||||
.from($scope.time.from) |
||||
.to($scope.time.to) |
||||
) |
||||
) |
||||
.fields([$scope.panel.field,$scope.panel.tooltip]) |
||||
.size($scope.panel.size) |
||||
.sort($scope.time.field,'desc'); |
||||
|
||||
$scope.populate_modal(request) |
||||
|
||||
var results = request.doSearch() |
||||
|
||||
// Populate scope when we have results
|
||||
results.then(function(results) { |
||||
$scope.panel.loading = false; |
||||
|
||||
if(_segment === 0) { |
||||
$scope.hits = 0; |
||||
$scope.data = []; |
||||
query_id = $scope.query_id = new Date().getTime() |
||||
} |
||||
|
||||
// Check for error and abort if found
|
||||
if(!(_.isUndefined(results.error))) { |
||||
$scope.panel.error = $scope.parse_error(results.error); |
||||
return; |
||||
} |
||||
|
||||
// Check that we're still on the same query, if not stop
|
||||
if($scope.query_id === query_id) { |
||||
|
||||
var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait() |
||||
|
||||
scripts.wait(function(){ |
||||
$scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) { |
||||
return { |
||||
coordinates : new L.LatLng(hit.fields[$scope.panel.field][1],hit.fields[$scope.panel.field][0]), |
||||
tooltip : hit.fields[$scope.panel.tooltip] |
||||
} |
||||
})); |
||||
}); |
||||
// Keep only what we need for the set
|
||||
$scope.data = $scope.data.slice(0,$scope.panel.size) |
||||
|
||||
} else { |
||||
return; |
||||
} |
||||
|
||||
$scope.$emit('draw') |
||||
|
||||
// Get $size results then stop querying
|
||||
if($scope.data.length < $scope.panel.size && _segment+1 < $scope.index.length) |
||||
$scope.get_data(_segment+1,$scope.query_id) |
||||
|
||||
}); |
||||
} |
||||
|
||||
// I really don't like this function, too much dom manip. Break out into directive?
|
||||
$scope.populate_modal = function(request) { |
||||
$scope.modal = { |
||||
title: "Inspector", |
||||
body : "<h5>Last Elasticsearch Query</h5><pre>"+ |
||||
'curl -XGET '+config.elasticsearch+'/'+$scope.index+"/_search?pretty -d'\n"+ |
||||
angular.toJson(JSON.parse(request.toString()),true)+ |
||||
"'</pre>",
|
||||
}
|
||||
} |
||||
|
||||
function set_time(time) { |
||||
$scope.time = time; |
||||
$scope.index = _.isUndefined(time.index) ? $scope.index : time.index |
||||
$scope.get_data(); |
||||
} |
||||
|
||||
$scope.build_search = function(field,value) { |
||||
$scope.panel.query = add_to_query($scope.panel.query,field,value,false) |
||||
$scope.get_data(); |
||||
eventBus.broadcast($scope.$id,$scope.panel.group,'query',[$scope.panel.query]); |
||||
} |
||||
|
||||
}) |
||||
.directive('bettermap', function() { |
||||
return { |
||||
restrict: 'A', |
||||
link: function(scope, elem, attrs) { |
||||
|
||||
elem.html('<center><img src="common/img/load_big.gif"></center>') |
||||
|
||||
// Receive render events
|
||||
scope.$on('draw',function(){ |
||||
render_panel(); |
||||
}); |
||||
|
||||
scope.$on('render', function(){ |
||||
if(!_.isUndefined(map)) { |
||||
map.invalidateSize(); |
||||
var panes = map.getPanes() |
||||
} |
||||
}) |
||||
|
||||
var map, markers, layerGroup, mcg; |
||||
|
||||
function render_panel() {
|
||||
scope.panel.loading = false; |
||||
|
||||
var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait() |
||||
.script("panels/bettermap/lib/plugins.js") |
||||
|
||||
//add markers dynamically
|
||||
scripts.wait(function(){ |
||||
if(_.isUndefined(map)) { |
||||
map = L.map(attrs.id, { |
||||
scrollWheelZoom: false, |
||||
center: [40, -86], |
||||
zoom: 10 |
||||
}); |
||||
|
||||
L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/22677/256/{z}/{x}/{y}.png', { |
||||
maxZoom: 18, |
||||
minZoom: 2 |
||||
}).addTo(map); |
||||
layerGroup = new L.MarkerClusterGroup({maxClusterRadius:30}); |
||||
} else { |
||||
layerGroup.clearLayers(); |
||||
} |
||||
|
||||
_.each(scope.data, function(p) { |
||||
if(!_.isUndefined(p.tooltip) && p.tooltip !== '') |
||||
layerGroup.addLayer(L.marker(p.coordinates).bindLabel(p.tooltip)) |
||||
else |
||||
layerGroup.addLayer(L.marker(p.coordinates)) |
||||
}) |
||||
|
||||
layerGroup.addTo(map) |
||||
|
||||
map.fitBounds(_.pluck(scope.data,'coordinates')); |
||||
}) |
||||
} |
||||
} |
||||
}; |
||||
}); |
Loading…
Reference in new issue