diff --git a/src/fixtures/vislib/mock_data/geohash/_geo_json.js b/src/fixtures/vislib/mock_data/geohash/_geo_json.js index 04e147974e922..b0889a9ed0279 100644 --- a/src/fixtures/vislib/mock_data/geohash/_geo_json.js +++ b/src/fixtures/vislib/mock_data/geohash/_geo_json.js @@ -2,6 +2,7 @@ import _ from 'lodash'; module.exports = { 'valueFormatter': _.identity, + 'geohashGridAgg': { 'vis': { 'params': {} } }, 'geoJson': { 'type': 'FeatureCollection', 'features': [ diff --git a/src/plugins/kbn_vislib_vis_types/public/tile_map.js b/src/plugins/kbn_vislib_vis_types/public/tile_map.js index acc7e45918485..cb6ae028cf2bc 100644 --- a/src/plugins/kbn_vislib_vis_types/public/tile_map.js +++ b/src/plugins/kbn_vislib_vis_types/public/tile_map.js @@ -27,6 +27,8 @@ export default function TileMapVisType(Private, getAppState, courier, config) { heatRadius: 25, heatBlur: 15, heatNormalizeData: true, + mapZoom: 2, + mapCenter: [15, 5], wms: config.get('visualization:tileMap:WMSdefaults') }, mapTypes: ['Scaled Circle Markers', 'Shaded Circle Markers', 'Shaded Geohash Grid', 'Heatmap'], @@ -46,54 +48,16 @@ export default function TileMapVisType(Private, getAppState, courier, config) { pushFilter(filter, false, indexPatternName); }, - mapMoveEnd: function (event) { - const agg = _.get(event, 'chart.geohashGridAgg'); - if (!agg) return; - - agg.params.mapZoom = event.zoom; - agg.params.mapCenter = [event.center.lat, event.center.lng]; - - const editableVis = agg.vis.getEditableVis(); - if (!editableVis) return; - - const editableAgg = editableVis.aggs.byId[agg.id]; - if (editableAgg) { - editableAgg.params.mapZoom = event.zoom; - editableAgg.params.mapCenter = [event.center.lat, event.center.lng]; - } + mapMoveEnd: function (event, uiState) { + uiState.set('mapCenter', event.center); }, - mapZoomEnd: function (event) { - const agg = _.get(event, 'chart.geohashGridAgg'); - if (!agg || !agg.params.autoPrecision) return; - - // zoomPrecision maps event.zoom to a geohash precision value - // event.limit is the configurable max geohash precision - // default max precision is 7, configurable up to 12 - const zoomPrecision = { - 1: 2, - 2: 2, - 3: 2, - 4: 3, - 5: 3, - 6: 4, - 7: 4, - 8: 5, - 9: 5, - 10: 6, - 11: 6, - 12: 7, - 13: 7, - 14: 8, - 15: 9, - 16: 10, - 17: 11, - 18: 12 - }; + mapZoomEnd: function (event, uiState) { + uiState.set('mapZoom', event.zoom); - const precision = config.get('visualization:tileMap:maxPrecision'); - agg.params.precision = Math.min(zoomPrecision[event.zoom], precision); - - courier.fetch(); + const autoPrecision = _.get(event, 'chart.geohashGridAgg.params.autoPrecision'); + if (autoPrecision) { + courier.fetch(); + } } }, responseConverter: geoJsonConverter, diff --git a/src/plugins/kibana/public/dashboard/components/panel/panel.js b/src/plugins/kibana/public/dashboard/components/panel/panel.js index 4befb5c353bcf..940948d31d291 100644 --- a/src/plugins/kibana/public/dashboard/components/panel/panel.js +++ b/src/plugins/kibana/public/dashboard/components/panel/panel.js @@ -55,6 +55,10 @@ uiModules // create child ui state from the savedObj const uiState = panelConfig.uiState || {}; $scope.uiState = $scope.parentUiState.createChild(getPanelId(panelConfig.panel), uiState, true); + const panelSavedVis = _.get(panelConfig, 'savedObj.vis'); // Sometimes this will be a search, and undef + if (panelSavedVis) { + panelSavedVis.setUiState($scope.uiState); + } $scope.filter = function (field, value, operator) { const index = $scope.savedObj.searchSource.get('index').id; diff --git a/src/plugins/kibana/public/visualize/editor/agg.js b/src/plugins/kibana/public/visualize/editor/agg.js index d7c2b42daca21..5cbd884e24be1 100644 --- a/src/plugins/kibana/public/visualize/editor/agg.js +++ b/src/plugins/kibana/public/visualize/editor/agg.js @@ -21,7 +21,6 @@ uiModules template: aggTemplate, require: 'form', link: function ($scope, $el, attrs, kbnForm) { - $scope.$bind('outputAgg', 'outputVis.aggs.byId[agg.id]', $scope); $scope.editorOpen = !!$scope.agg.brandNew; $scope.$watch('editorOpen', function (open) { diff --git a/src/plugins/kibana/public/visualize/editor/editor.js b/src/plugins/kibana/public/visualize/editor/editor.js index 2b9341f86a886..9edc7bbc1a241 100644 --- a/src/plugins/kibana/public/visualize/editor/editor.js +++ b/src/plugins/kibana/public/visualize/editor/editor.js @@ -139,6 +139,7 @@ uiModules $scope.editableVis = editableVis; $scope.state = $state; $scope.uiState = $state.makeStateful('uiState'); + vis.setUiState($scope.uiState); $scope.timefilter = timefilter; $scope.opts = _.pick($scope, 'doSave', 'savedVis', 'shareData', 'timefilter'); diff --git a/src/plugins/kibana/public/visualize/editor/sidebar.js b/src/plugins/kibana/public/visualize/editor/sidebar.js index e9a6541aec994..40187ba84bed9 100644 --- a/src/plugins/kibana/public/visualize/editor/sidebar.js +++ b/src/plugins/kibana/public/visualize/editor/sidebar.js @@ -15,7 +15,6 @@ uiModules controllerAs: 'sidebar', controller: function ($scope) { $scope.$bind('vis', 'editableVis'); - $scope.$bind('outputVis', 'vis'); $scope.$watch('vis.type', (visType) => { if (visType) { this.showData = visType.schemas.buckets || visType.schemas.metrics; diff --git a/src/ui/public/agg_response/geo_json/geo_json.js b/src/ui/public/agg_response/geo_json/geo_json.js index 6c01ac567792b..aac0fba222985 100644 --- a/src/ui/public/agg_response/geo_json/geo_json.js +++ b/src/ui/public/agg_response/geo_json/geo_json.js @@ -34,8 +34,8 @@ export default function TileMapConverterFn(Private, timefilter, $compile, $rootS properties: { min: _.min(values), max: _.max(values), - zoom: _.get(geoAgg, 'params.mapZoom'), - center: _.get(geoAgg, 'params.mapCenter') + zoom: geoAgg && geoAgg.vis.uiStateVal('mapZoom'), + center: geoAgg && geoAgg.vis.uiStateVal('mapCenter') } } }; diff --git a/src/ui/public/agg_types/buckets/geo_hash.js b/src/ui/public/agg_types/buckets/geo_hash.js index d27d6bf338d87..ebc96eae78c42 100644 --- a/src/ui/public/agg_types/buckets/geo_hash.js +++ b/src/ui/public/agg_types/buckets/geo_hash.js @@ -6,6 +6,30 @@ export default function GeoHashAggDefinition(Private, config) { let BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider); let defaultPrecision = 2; + // zoomPrecision maps event.zoom to a geohash precision value + // event.limit is the configurable max geohash precision + // default max precision is 7, configurable up to 12 + const zoomPrecision = { + 1: 2, + 2: 2, + 3: 2, + 4: 3, + 5: 3, + 6: 4, + 7: 4, + 8: 5, + 9: 5, + 10: 6, + 11: 6, + 12: 7, + 13: 7, + 14: 8, + 15: 9, + 16: 10, + 17: 11, + 18: 12 + }; + function getPrecision(precision) { let maxPrecision = _.parseInt(config.get('visualization:tileMap:maxPrecision')); @@ -45,19 +69,15 @@ export default function GeoHashAggDefinition(Private, config) { }, { name: 'precision', - default: defaultPrecision, editor: precisionTemplate, + deserialize: getPrecision, controller: function ($scope) { - $scope.$watchMulti([ - 'agg.params.autoPrecision', - 'outputAgg.params.precision' - ], function (cur, prev) { - if (cur[1]) $scope.agg.params.precision = cur[1]; - }); }, - deserialize: getPrecision, write: function (aggConfig, output) { - output.params.precision = getPrecision(aggConfig.params.precision); + const vis = aggConfig.vis; + const currZoom = vis.hasUiState() && vis.uiStateVal('mapZoom'); + const autoPrecisionVal = zoomPrecision[(currZoom || vis.params.mapZoom)]; + output.params.precision = aggConfig.params.autoPrecision ? autoPrecisionVal : getPrecision(aggConfig.params.precision); } } ] diff --git a/src/ui/public/vis/vis.js b/src/ui/public/vis/vis.js index dbf29fe416429..864d221de0917 100644 --- a/src/ui/public/vis/vis.js +++ b/src/ui/public/vis/vis.js @@ -2,16 +2,18 @@ import _ from 'lodash'; import AggTypesIndexProvider from 'ui/agg_types/index'; import RegistryVisTypesProvider from 'ui/registry/vis_types'; import VisAggConfigsProvider from 'ui/vis/agg_configs'; +import PersistedStateProvider from 'ui/persisted_state/persisted_state'; export default function VisFactory(Notifier, Private) { let aggTypes = Private(AggTypesIndexProvider); let visTypes = Private(RegistryVisTypesProvider); let AggConfigs = Private(VisAggConfigsProvider); + const PersistedState = Private(PersistedStateProvider); let notify = new Notifier({ location: 'Vis' }); - function Vis(indexPattern, state) { + function Vis(indexPattern, state, uiState) { state = state || {}; if (_.isString(state)) { @@ -24,6 +26,7 @@ export default function VisFactory(Notifier, Private) { // http://aphyr.com/data/posts/317/state.gif this.setState(state); + this.setUiState(uiState); } Vis.convertOldState = function (type, oldState) { @@ -102,7 +105,8 @@ export default function VisFactory(Notifier, Private) { }; Vis.prototype.clone = function () { - return new Vis(this.indexPattern, this.getState()); + const uiJson = this.hasUiState() ? this.getUiState().toJSON() : {}; + return new Vis(this.indexPattern, this.getState(), uiJson); }; Vis.prototype.requesting = function () { @@ -125,5 +129,26 @@ export default function VisFactory(Notifier, Private) { }); }; + Vis.prototype.hasUiState = function () { + return !!this.__uiState; + }; + Vis.prototype.setUiState = function (uiState) { + if (uiState instanceof PersistedState) { + this.__uiState = uiState; + } + }; + Vis.prototype.getUiState = function () { + return this.__uiState; + }; + Vis.prototype.uiStateVal = function (key, val) { + if (this.hasUiState()) { + if (_.isUndefined(val)) { + return this.__uiState.get(key); + } + return this.__uiState.set(key, val); + } + return val; + }; + return Vis; }; diff --git a/src/ui/public/vislib/__tests__/visualizations/tile_maps/tile_map.js b/src/ui/public/vislib/__tests__/visualizations/tile_maps/tile_map.js index d1f4c3235fd08..411b924265c48 100644 --- a/src/ui/public/vislib/__tests__/visualizations/tile_maps/tile_map.js +++ b/src/ui/public/vislib/__tests__/visualizations/tile_maps/tile_map.js @@ -81,6 +81,7 @@ describe('TileMap Tests', function () { it('should only add controls if data exists', function () { let noData = { + geohashGridAgg: { vis: { params: {} } }, geoJson: { features: [], properties: {}, diff --git a/src/ui/public/vislib/lib/handler/handler.js b/src/ui/public/vislib/lib/handler/handler.js index a74c627931860..e496c1b39271f 100644 --- a/src/ui/public/vislib/lib/handler/handler.js +++ b/src/ui/public/vislib/lib/handler/handler.js @@ -55,7 +55,7 @@ export default function HandlerBaseClass(Private) { this.getProxyHandler = _.memoize(function (event) { let self = this; return function (e) { - self.vis.emit(event, e); + self.vis.emit(event, e, vis.uiState); }; }); } diff --git a/src/ui/public/vislib/visualizations/_map.js b/src/ui/public/vislib/visualizations/_map.js index 3a893c38fd8fe..080f3ba73c28a 100644 --- a/src/ui/public/vislib/visualizations/_map.js +++ b/src/ui/public/vislib/visualizations/_map.js @@ -47,6 +47,8 @@ export default function MapFactory(Private) { this._valueFormatter = params.valueFormatter || _.identity; this._tooltipFormatter = params.tooltipFormatter || _.identity; this._geoJson = _.get(this._chartData, 'geoJson'); + this._mapZoom = params.zoom || defaultMapZoom; + this._mapCenter = params.center || defaultMapCenter; this._attr = params.attr || {}; let mapOptions = { @@ -211,7 +213,8 @@ export default function MapFactory(Private) { this.map.on('moveend', function setZoomCenter(ev) { if (!self.map) return; // update internal center and zoom references - self._mapCenter = self.map.getCenter(); + const uglyCenter = self.map.getCenter(); + self._mapCenter = [uglyCenter.lat, uglyCenter.lng]; self._mapZoom = self.map.getZoom(); self._addMarkers(); @@ -264,10 +267,6 @@ export default function MapFactory(Private) { TileMapMap.prototype._createMap = function (mapOptions) { if (this.map) this.destroy(); - // get center and zoom from mapdata, or use defaults - this._mapCenter = _.get(this._geoJson, 'properties.center') || defaultMapCenter; - this._mapZoom = _.get(this._geoJson, 'properties.zoom') || defaultMapZoom; - // add map tiles layer, using the mapTiles object settings if (this._attr.wms && this._attr.wms.enabled) { this._tileLayer = L.tileLayer.wms(this._attr.wms.url, this._attr.wms.options); diff --git a/src/ui/public/vislib/visualizations/tile_map.js b/src/ui/public/vislib/visualizations/tile_map.js index 9d19d927b82e3..bc3d3bab83a75 100644 --- a/src/ui/public/vislib/visualizations/tile_map.js +++ b/src/ui/public/vislib/visualizations/tile_map.js @@ -98,11 +98,17 @@ export default function TileMapFactory(Private) { * @param selection {Object} d3 selection */ TileMap.prototype._appendMap = function (selection) { - let container = $(selection).addClass('tilemap'); + const container = $(selection).addClass('tilemap'); + const uiStateParams = this.handler.vis ? { + mapCenter: this.handler.vis.uiState.get('mapCenter'), + mapZoom: this.handler.vis.uiState.get('mapZoom') + } : {}; - let map = new TileMapMap(container, this._chartData, { - // center: this._attr.mapCenter, - // zoom: this._attr.mapZoom, + const params = _.assign({}, _.get(this._chartData, 'geoAgg.vis.params'), uiStateParams); + + const map = new TileMapMap(container, this._chartData, { + center: params.mapCenter, + zoom: params.mapZoom, events: this.events, markerType: this._attr.mapType, tooltipFormatter: this.tooltipFormatter,