Skip to content

Commit

Permalink
filter geohash_grid agg with geo_bounding_box collar
Browse files Browse the repository at this point in the history
  • Loading branch information
nreese committed Oct 5, 2016
1 parent b9df49f commit 439200e
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 37 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Kibana ships with a functional tilemap visualization. This plugin provides an ad
### Add Markers to map
Allows for the placement of markers on the tilemap. Markers are displayed when in the visualization panel or the dashboard panel. Markers can only be added and removed when in the visualization panel.

### Filter geohash_grid aggregation by geo_bounding_box collar
Resolves issue [Filter geohash_grid aggregation to map view box with collar](https://github.com/elastic/kibana/issues/8087)

### Geo Polygon Query
Click the polygon icon and draw a polygon on the map. The enhanced tilemap plugin will create a geo_polygon filter.

Expand Down Expand Up @@ -49,9 +52,6 @@ The kibana tilemap plugin has been updated with several pull-requests but none o
* https://github.com/elastic/kibana/pull/8000
* https://github.com/elastic/kibana/pull/6835

### geo aggregation filtered by geo_bounding_box collar
[Filter geohash_grid aggregation to map view box with collar](https://github.com/elastic/kibana/issues/8087)

# Install
## Kibana 4.x
```bash
Expand Down
6 changes: 6 additions & 0 deletions public/callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ define(function (require) {
editableAgg.params.mapZoom = event.zoom;
editableAgg.params.mapCenter = center;
}

//Fetch new data if map bounds are outsize of collar
const bounds = utils.scaleBounds(event.mapBounds, 1);
if(!utils.contains(event.collar, bounds)) {
courier.fetch();
}
},
mapZoomEnd: function (event) {
const agg = _.get(event, 'chart.geohashGridAgg');
Expand Down
9 changes: 9 additions & 0 deletions public/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
</select>
</div>

<div class="form-group">
<label>
Map Collar Scale <kbn-info info="Use this input to increase or decrease the size of the geo aggregation filter. A value of 1 will size the filter to the map bounds. A value of 2 will size the filter to 2X the map bounds. A value too small could result in excessive fetches. A value too large could result in trimmed results and slow performance."></kbn-info>
</label>
<input type="number" class="form-control"
name="collarScale"
ng-model="vis.params.collarScale">
</div>

<div ng-if="vis.params.mapType !== 'Heatmap'" class="form-group">
<div class="form-group">
<label>Quantize scale type</label>
Expand Down
45 changes: 45 additions & 0 deletions public/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,51 @@
define(function (require) {
const _ = require('lodash');
return {
/*
* @param bounds {LatLngBounds}
* @param scale {number}
* @return {object}
*/
scaleBounds: function(bounds, scale) {
let safeScale = scale;
if(safeScale < 1) scale = 1;
if(safeScale > 5) scale = 5;

const topLeft = bounds.getNorthEast();
const bottomRight = bounds.getSouthWest();
let latDiff = Math.abs(topLeft.lat - bottomRight.lat);
let lonDiff = Math.abs(bottomRight.lng - topLeft.lng);
//map height can be zero when vis is first created
if(latDiff === 0) latDiff = lonDiff;

let topLeftLat = topLeft.lat + (latDiff * safeScale);
if(topLeftLat > 90) topLeftLat = 90;
let bottomRightLat = bottomRight.lat - (latDiff * safeScale);
if(bottomRightLat < -90) bottomRightLat = -90;
let topLeftLon = topLeft.lng - (lonDiff * safeScale);
if(topLeftLon < -180) topLeftLon = -180;
let bottomRightLon = bottomRight.lng + (lonDiff * safeScale);
if(bottomRightLon > 180) bottomRightLon = 180;

return {
"top_left": {lat: topLeftLat, lon: topLeftLon},
"bottom_right": {lat: bottomRightLat, lon: bottomRightLon}
};
},
contains: function(collar, bounds) {
//test if bounds top_left is inside collar
if(bounds.top_left.lat > collar.top_left.lat
|| bounds.top_left.lon < collar.top_left.lon)
return false;

//test if bounds bottom_right is inside collar
if(bounds.bottom_right.lat < collar.bottom_right.lat
|| bounds.bottom_right.lon > collar.bottom_right.lon)
return false;

//both corners are inside collar so collar contains
return true;
},
getMapStateFromVis: function(vis) {
const mapState = {
center: [15, 5],
Expand Down
1 change: 1 addition & 0 deletions public/vis.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ define(function (require) {
params: {
defaults: {
mapType: 'Scaled Circle Markers',
collarScale: 1.5,
scaleType: 'dynamic',
scaleBands: [{
low: 0,
Expand Down
41 changes: 40 additions & 1 deletion public/visController.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,48 @@ define(function (require) {
let TileMapMap = Private(MapProvider);
const geoJsonConverter = Private(AggResponseGeoJsonGeoJsonProvider);
let map = null;
let collar = null;
appendMap();

$scope.vis.aggs.origToDsl = $scope.vis.aggs.toDsl;
$scope.vis.aggs.toDsl = function() {
resizeArea();
const dsl = $scope.vis.aggs.origToDsl();

//append map collar filter to geohash_grid aggregation
_.keys(dsl).forEach(function(key) {
if(_.has(dsl[key], "geohash_grid")) {
const origAgg = dsl[key];
dsl[key] = {
filter: aggFilter(origAgg.geohash_grid.field),
aggs: {
filtered_geohash: origAgg
}
}
}
});
return dsl;
}
function aggFilter(field) {
collar = utils.scaleBounds(
map.mapBounds(),
$scope.vis.params.collarScale);
var filter = {geo_bounding_box: {}};
filter.geo_bounding_box[field] = collar;
return filter;
}

//Useful bits of ui/public/vislib_vis_type/buildChartData.js
function buildChartData(resp) {
const aggs = resp.aggregations;
_.keys(aggs).forEach(function(key) {
if(_.has(aggs[key], "filtered_geohash")) {
aggs[key].buckets = aggs[key].filtered_geohash.buckets;
delete aggs[key].filtered_geohash;
console.log("geogrids: " + aggs[key].buckets.length);
if(aggs[key].buckets.length === 0) return;
}
});
var tableGroup = aggResponse.tabify($scope.vis, resp, {
canSplit: true,
asAggConfigResults: true
Expand Down Expand Up @@ -59,7 +97,8 @@ define(function (require) {
chartData,
$scope.vis.params,
Private(require('ui/agg_response/geo_json/_tooltip_formatter')),
_.get(chartData, 'valueFormatter', _.identity));
_.get(chartData, 'valueFormatter', _.identity),
collar);
}
});

Expand Down
29 changes: 14 additions & 15 deletions public/vislib/_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,24 +215,18 @@ define(function (require) {
*
* @method _addMarkers
*/
TileMapMap.prototype.addMarkers = function (chartData, newParams, tooltipFormatter, valueFormatter) {
if(newParams) {
this._setMarkerType(newParams.mapType);
this._setAttr(newParams);
}
if(chartData) {
this._chartData = chartData;
this._geoJson = _.get(chartData, 'geoJson');
}
if(tooltipFormatter) this._tooltipFormatter = tooltipFormatter;
if(valueFormatter) this._valueFormatter = valueFormatter;
if(!this._tooltipFormatter) return;
TileMapMap.prototype.addMarkers = function (chartData, newParams, tooltipFormatter, valueFormatter, collar) {
this._setMarkerType(newParams.mapType);
this._setAttr(newParams);
this._chartData = chartData;
this._geoJson = _.get(chartData, 'geoJson');
this._collar = collar;

if (this._markers) this._markers.destroy();

this._markers = this._createMarkers({
tooltipFormatter: this._tooltipFormatter,
valueFormatter: this._valueFormatter,
tooltipFormatter: tooltipFormatter,
valueFormatter: valueFormatter,
attr: this._attr
});

Expand Down Expand Up @@ -280,6 +274,10 @@ define(function (require) {
this._layerControl.addOverlay(this._overlay, name);
};

TileMapMap.prototype.mapBounds = function () {
return this.map.getBounds();
};

/**
* Create the marker instance using the given options
*
Expand Down Expand Up @@ -326,10 +324,11 @@ define(function (require) {
// update internal center and zoom references
self._mapCenter = self.map.getCenter();
self._mapZoom = self.map.getZoom();
self.addMarkers();

self._callbacks.mapMoveEnd({
chart: self._chartData,
collar: self._collar,
mapBounds: self.mapBounds(),
map: self.map,
center: self._mapCenter,
zoom: self._mapZoom,
Expand Down
19 changes: 1 addition & 18 deletions public/vislib/marker_types/base_marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,7 @@ define(function (require) {
style: function (feature) {
let value = _.get(feature, 'properties.value');
return self.applyShadingStyle(value);
},
filter: self._filterToMapBounds()
}
};

if(self.geoJson.features.length <= 250) {
Expand Down Expand Up @@ -209,22 +208,6 @@ define(function (require) {
this._addToMap();
};

/**
* return whether feature is within map bounds
*
* @method _filterToMapBounds
* @param map {Leaflet Object}
* @return {boolean}
*/
BaseMarker.prototype._filterToMapBounds = function () {
let self = this;
return function (feature) {
let mapBounds = self.map.getBounds();
let bucketRectBounds = _.get(feature, 'properties.rectangle');
return mapBounds.intersects(bucketRectBounds);
};
};

/**
* Checks if event latlng is within bounds of mapData
* features and shows tooltip for that feature
Expand Down

0 comments on commit 439200e

Please sign in to comment.