diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts index 5ff68c5426e34..f0ad595476486 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts @@ -17,9 +17,10 @@ * under the License. */ -import { geoHashBucketAgg, IBucketGeoHashGridAggConfig } from './geo_hash'; +import { geoHashBucketAgg } from './geo_hash'; import { AggConfigs, IAggConfigs } from '../agg_configs'; import { BUCKET_TYPES } from './bucket_agg_types'; +import { IBucketAggConfig } from './_bucket_agg_type'; jest.mock('ui/new_platform'); @@ -77,79 +78,26 @@ describe('Geohash Agg', () => { it('should select precision parameter', () => { expect(precisionParam.name).toEqual('precision'); }); - - describe('precision parameter write', () => { - const zoomToGeoHashPrecision: Record = { - 0: 1, - 1: 2, - 2: 2, - 3: 2, - 4: 3, - 5: 3, - 6: 4, - 7: 4, - 8: 4, - 9: 5, - 10: 5, - 11: 6, - 12: 6, - 13: 6, - 14: 7, - 15: 7, - 16: 8, - 17: 8, - 18: 8, - 19: 9, - 20: 9, - 21: 10, - }; - - Object.keys(zoomToGeoHashPrecision).forEach((zoomLevel: string) => { - it(`zoom level ${zoomLevel} should correspond to correct geohash-precision`, () => { - const aggConfigs = getAggConfigs({ - autoPrecision: true, - mapZoom: zoomLevel, - }); - - const { [BUCKET_TYPES.GEOHASH_GRID]: params } = aggConfigs.aggs[0].toDsl(); - - expect(params.precision).toEqual(zoomToGeoHashPrecision[zoomLevel]); - }); - }); - }); }); describe('getRequestAggs', () => { describe('initial aggregation creation', () => { let aggConfigs: IAggConfigs; - let geoHashGridAgg: IBucketGeoHashGridAggConfig; + let geoHashGridAgg: IBucketAggConfig; beforeEach(() => { aggConfigs = getAggConfigs(); - geoHashGridAgg = aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig; + geoHashGridAgg = aggConfigs.aggs[0] as IBucketAggConfig; }); it('should create filter, geohash_grid, and geo_centroid aggregations', () => { - const requestAggs = geoHashBucketAgg.getRequestAggs( - geoHashGridAgg - ) as IBucketGeoHashGridAggConfig[]; + const requestAggs = geoHashBucketAgg.getRequestAggs(geoHashGridAgg) as IBucketAggConfig[]; expect(requestAggs.length).toEqual(3); expect(requestAggs[0].type.name).toEqual('filter'); expect(requestAggs[1].type.name).toEqual('geohash_grid'); expect(requestAggs[2].type.name).toEqual('geo_centroid'); }); - - it('should set mapCollar in vis session state', () => { - const [, geoHashAgg] = geoHashBucketAgg.getRequestAggs( - geoHashGridAgg - ) as IBucketGeoHashGridAggConfig[]; - - expect(geoHashAgg).toHaveProperty('lastMapCollar'); - expect(geoHashAgg.lastMapCollar).toHaveProperty('top_left'); - expect(geoHashAgg.lastMapCollar).toHaveProperty('bottom_right'); - expect(geoHashAgg.lastMapCollar).toHaveProperty('zoom'); - }); }); }); @@ -157,8 +105,8 @@ describe('Geohash Agg', () => { it('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => { const aggConfigs = getAggConfigs({ isFilteredByCollar: false }); const requestAggs = geoHashBucketAgg.getRequestAggs( - aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; + aggConfigs.aggs[0] as IBucketAggConfig + ) as IBucketAggConfig[]; expect(requestAggs.length).toEqual(2); expect(requestAggs[0].type.name).toEqual('geohash_grid'); @@ -168,8 +116,8 @@ describe('Geohash Agg', () => { it('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => { const aggConfigs = getAggConfigs({ useGeocentroid: false }); const requestAggs = geoHashBucketAgg.getRequestAggs( - aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; + aggConfigs.aggs[0] as IBucketAggConfig + ) as IBucketAggConfig[]; expect(requestAggs.length).toEqual(2); expect(requestAggs[0].type.name).toEqual('filter'); @@ -178,23 +126,28 @@ describe('Geohash Agg', () => { }); describe('aggregation creation after map interaction', () => { - let originalRequestAggs: IBucketGeoHashGridAggConfig[]; + let originalRequestAggs: IBucketAggConfig[]; beforeEach(() => { originalRequestAggs = geoHashBucketAgg.getRequestAggs( - getAggConfigs().aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; + getAggConfigs({ + boundingBox: { + top_left: { lat: 1, lon: -1 }, + bottom_right: { lat: -1, lon: 1 }, + }, + }).aggs[0] as IBucketAggConfig + ) as IBucketAggConfig[]; }); it('should change geo_bounding_box filter aggregation and vis session state when map movement is outside map collar', () => { const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( getAggConfigs({ - mapBounds: { + boundingBox: { top_left: { lat: 10.0, lon: -10.0 }, bottom_right: { lat: 9.0, lon: -9.0 }, }, - }).aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; + }).aggs[0] as IBucketAggConfig + ) as IBucketAggConfig[]; expect(originalRequestAggs[1].params).not.toEqual(geoBoxingBox.params); }); @@ -202,24 +155,14 @@ describe('Geohash Agg', () => { it('should not change geo_bounding_box filter aggregation and vis session state when map movement is within map collar', () => { const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( getAggConfigs({ - mapBounds: { + boundingBox: { top_left: { lat: 1, lon: -1 }, bottom_right: { lat: -1, lon: 1 }, }, - }).aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; + }).aggs[0] as IBucketAggConfig + ) as IBucketAggConfig[]; expect(originalRequestAggs[1].params).toEqual(geoBoxingBox.params); }); - - it('should change geo_bounding_box filter aggregation and vis session state when map zoom level changes', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( - getAggConfigs({ - mapZoom: -1, - }).aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - - expect(originalRequestAggs[1].lastMapCollar).not.toEqual(geoBoxingBox.lastMapCollar); - }); }); }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts index afd4e18dd266c..8732f926b0fb2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -18,69 +18,22 @@ */ import { i18n } from '@kbn/i18n'; -import { geohashColumns } from 'ui/vis/map/decode_geo_hash'; -import chrome from 'ui/chrome'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; - -import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { AggGroupNames } from '../agg_groups'; -const config = chrome.getUiSettingsClient(); +const defaultBoundingBox = { + top_left: { lat: 1, lon: 1 }, + bottom_right: { lat: 0, lon: 0 }, +}; const defaultPrecision = 2; -const maxPrecision = parseInt(config.get('visualization:tileMap:maxPrecision'), 10) || 12; -/** - * Map Leaflet zoom levels to geohash precision levels. - * The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide. - */ -const zoomPrecision: any = {}; -const minGeohashPixels = 16; - -for (let zoom = 0; zoom <= 21; zoom += 1) { - const worldPixels = 256 * Math.pow(2, zoom); - zoomPrecision[zoom] = 1; - for (let precision = 2; precision <= maxPrecision; precision += 1) { - const columns = geohashColumns(precision); - if (worldPixels / columns >= minGeohashPixels) { - zoomPrecision[zoom] = precision; - } else { - break; - } - } -} - -function getPrecision(val: string) { - let precision = parseInt(val, 10); - - if (Number.isNaN(precision)) { - precision = defaultPrecision; - } - - if (precision > maxPrecision) { - return maxPrecision; - } - - return precision; -} - -const isOutsideCollar = (bounds: GeoBoundingBox, collar: MapCollar) => - bounds && collar && !geoContains(collar, bounds); const geohashGridTitle = i18n.translate('data.search.aggs.buckets.geohashGridTitle', { defaultMessage: 'Geohash', }); -interface MapCollar extends GeoBoundingBox { - zoom?: unknown; -} - -export interface IBucketGeoHashGridAggConfig extends IBucketAggConfig { - lastMapCollar: MapCollar; -} - -export const geoHashBucketAgg = new BucketAggType({ +export const geoHashBucketAgg = new BucketAggType({ name: BUCKET_TYPES.GEOHASH_GRID, title: geohashGridTitle, params: [ @@ -97,13 +50,8 @@ export const geoHashBucketAgg = new BucketAggType({ { name: 'precision', default: defaultPrecision, - deserialize: getPrecision, write(aggConfig, output) { - const currZoom = aggConfig.params.mapZoom; - const autoPrecisionVal = zoomPrecision[currZoom]; - output.params.precision = aggConfig.params.autoPrecision - ? autoPrecisionVal - : getPrecision(aggConfig.params.precision); + output.params.precision = aggConfig.params.precision; }, }, { @@ -117,17 +65,7 @@ export const geoHashBucketAgg = new BucketAggType({ write: () => {}, }, { - name: 'mapZoom', - default: 2, - write: () => {}, - }, - { - name: 'mapCenter', - default: [0, 0], - write: () => {}, - }, - { - name: 'mapBounds', + name: 'boundingBox', default: null, write: () => {}, }, @@ -137,46 +75,22 @@ export const geoHashBucketAgg = new BucketAggType({ const params = agg.params; if (params.isFilteredByCollar && agg.getField()) { - const { mapBounds, mapZoom } = params; - if (mapBounds) { - let mapCollar: MapCollar; - - if ( - mapBounds && - (!agg.lastMapCollar || - agg.lastMapCollar.zoom !== mapZoom || - isOutsideCollar(mapBounds, agg.lastMapCollar)) - ) { - mapCollar = scaleBounds(mapBounds); - mapCollar.zoom = mapZoom; - agg.lastMapCollar = mapCollar; - } else { - mapCollar = agg.lastMapCollar; - } - const boundingBox = { - ignore_unmapped: true, - [agg.getField().name]: { - top_left: mapCollar.top_left, - bottom_right: mapCollar.bottom_right, - }, - }; - aggs.push( - agg.aggConfigs.createAggConfig( - { - type: 'filter', - id: 'filter_agg', - enabled: true, - params: { - geo_bounding_box: boundingBox, - }, - schema: { - group: AggGroupNames.Buckets, + aggs.push( + agg.aggConfigs.createAggConfig( + { + type: 'filter', + id: 'filter_agg', + enabled: true, + params: { + geo_bounding_box: { + ignore_unmapped: true, + [agg.getField().name]: params.boundingBox || defaultBoundingBox, }, - } as any, - { addToAggConfigs: false } - ) - ); - } + }, + } as any, + { addToAggConfigs: false } + ) + ); } aggs.push(agg); @@ -196,6 +110,6 @@ export const geoHashBucketAgg = new BucketAggType({ ); } - return aggs as IBucketGeoHashGridAggConfig[]; + return aggs; }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts deleted file mode 100644 index 639b6d1fbb03e..0000000000000 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; - -interface GeoBoundingBoxCoordinate { - lat: number; - lon: number; -} - -export interface GeoBoundingBox { - top_left: GeoBoundingBoxCoordinate; - bottom_right: GeoBoundingBoxCoordinate; -} - -export function geoContains(collar: GeoBoundingBox, bounds: GeoBoundingBox) { - // test if bounds top_left is outside 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 outside 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 bounds - return true; -} - -export function scaleBounds(bounds: GeoBoundingBox): GeoBoundingBox { - const scale = 0.5; // scale bounds by 50% - - const topLeft = bounds.top_left; - const bottomRight = bounds.bottom_right; - let latDiff = _.round(Math.abs(topLeft.lat - bottomRight.lat), 5); - const lonDiff = _.round(Math.abs(bottomRight.lon - topLeft.lon), 5); - // map height can be zero when vis is first created - if (latDiff === 0) latDiff = lonDiff; - - const latDelta = latDiff * scale; - let topLeftLat = _.round(topLeft.lat, 5) + latDelta; - if (topLeftLat > 90) topLeftLat = 90; - let bottomRightLat = _.round(bottomRight.lat, 5) - latDelta; - if (bottomRightLat < -90) bottomRightLat = -90; - const lonDelta = lonDiff * scale; - let topLeftLon = _.round(topLeft.lon, 5) - lonDelta; - if (topLeftLon < -180) topLeftLon = -180; - let bottomRightLon = _.round(bottomRight.lon, 5) + lonDelta; - if (bottomRightLon > 180) bottomRightLon = 180; - - return { - top_left: { lat: topLeftLat, lon: topLeftLon }, - bottom_right: { lat: bottomRightLat, lon: bottomRightLon }, - }; -} diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts index 0d1b2472bb8e2..e24aca08271c7 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts @@ -18,13 +18,14 @@ */ import { i18n } from '@kbn/i18n'; -import { noop } from 'lodash'; +import { noop, identity } from 'lodash'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; import { Schemas } from '../../schemas'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; const metricAggFilter = [ '!top_hits', @@ -100,7 +101,7 @@ const parentPipelineAggHelper = { } else { subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); } - return subAgg.type.getFormat(subAgg); + return subAgg ? subAgg.type.getFormat(subAgg) : new (fieldFormats.FieldFormat.from(identity))(); }, }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts index 3956bda1812ad..e7c98e575fdb4 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts @@ -17,12 +17,14 @@ * under the License. */ +import { identity } from 'lodash'; import { i18n } from '@kbn/i18n'; import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; import { Schemas } from '../../schemas'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; const metricAggFilter: string[] = [ '!top_hits', @@ -115,8 +117,9 @@ const siblingPipelineAggHelper = { getFormat(agg: IMetricAggConfig) { const customMetric = agg.getParam('customMetric'); - - return customMetric.type.getFormat(customMetric); + return customMetric + ? customMetric.type.getFormat(customMetric) + : new (fieldFormats.FieldFormat.from(identity))(); }, }; diff --git a/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx b/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx index 4ceffbfc1c197..624d000dd8d7a 100644 --- a/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx +++ b/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx @@ -55,14 +55,12 @@ export const createInputControlVisController = (deps: InputControlVisDependencie } async render(visData: any, visParams: VisParams, status: any) { - if (status.params || (visParams.useTimeFilter && status.time)) { - this.visParams = visParams; - this.controls = []; - this.controls = await this.initControls(); - const [{ i18n }] = await deps.core.getStartServices(); - this.I18nContext = i18n.Context; - this.drawVis(); - } + this.visParams = visParams; + this.controls = []; + this.controls = await this.initControls(); + const [{ i18n }] = await deps.core.getStartServices(); + this.I18nContext = i18n.Context; + this.drawVis(); } destroy() { diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_fn.js b/src/legacy/core_plugins/tile_map/public/tile_map_fn.js index f5cb6fdf93002..2f54d23590c33 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_fn.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_fn.js @@ -43,6 +43,10 @@ export const createTileMapFn = () => ({ geocentroid, }); + if (geohash && geohash.accessor) { + convertedData.meta.geohash = context.columns[geohash.accessor].meta; + } + return { type: 'render', as: 'visualization', diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js b/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js index 772edaa4ff4f5..910def8a0c78e 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js @@ -23,6 +23,12 @@ import { BaseMapsVisualizationProvider } from './base_maps_visualization'; import { TileMapTooltipFormatterProvider } from './editors/_tooltip_formatter'; import { npStart } from 'ui/new_platform'; import { getFormat } from '../../../ui/public/visualize/loader/pipeline_helpers/utilities'; +import { + scaleBounds, + zoomPrecision, + getPrecision, + geoContains, +} from '../../../ui/public/vis/map/decode_geo_hash'; export const createTileMapVisualization = ({ serviceSettings, $injector }) => { const BaseMapsVisualization = new BaseMapsVisualizationProvider(serviceSettings); @@ -35,42 +41,47 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { this._geohashLayer = null; } + updateGeohashAgg = () => { + const geohashAgg = this._getGeoHashAgg(); + if (!geohashAgg) return; + const updateVarsObject = { + name: 'bounds', + data: {}, + }; + const bounds = this._kibanaMap.getBounds(); + const mapCollar = scaleBounds(bounds); + if (!geoContains(geohashAgg.aggConfigParams.boundingBox, mapCollar)) { + updateVarsObject.data.boundingBox = { + top_left: mapCollar.top_left, + bottom_right: mapCollar.bottom_right, + }; + } else { + updateVarsObject.data.boundingBox = geohashAgg.aggConfigParams.boundingBox; + } + // todo: autoPrecision should be vis parameter, not aggConfig one + updateVarsObject.data.precision = geohashAgg.aggConfigParams.autoPrecision + ? zoomPrecision[this.vis.getUiState().get('mapZoom')] + : getPrecision(geohashAgg.aggConfigParams.precision); + + this.vis.eventsSubject.next(updateVarsObject); + }; + async _makeKibanaMap() { await super._makeKibanaMap(); - const updateGeohashAgg = () => { - const geohashAgg = this._getGeoHashAgg(); - if (!geohashAgg) return; - geohashAgg.params.mapBounds = this._kibanaMap.getBounds(); - geohashAgg.params.mapZoom = this._kibanaMap.getZoomLevel(); - geohashAgg.params.mapCenter = this._kibanaMap.getCenter(); - }; - - updateGeohashAgg(); + let previousPrecision = this._kibanaMap.getGeohashPrecision(); + let precisionChange = false; const uiState = this.vis.getUiState(); uiState.on('change', prop => { if (prop === 'mapZoom' || prop === 'mapCenter') { - updateGeohashAgg(); + this.updateGeohashAgg(); } }); - let previousPrecision = this._kibanaMap.getGeohashPrecision(); - let precisionChange = false; this._kibanaMap.on('zoomchange', () => { - const geohashAgg = this._getGeoHashAgg(); precisionChange = previousPrecision !== this._kibanaMap.getGeohashPrecision(); previousPrecision = this._kibanaMap.getGeohashPrecision(); - if (!geohashAgg) { - return; - } - const isAutoPrecision = - typeof geohashAgg.params.autoPrecision === 'boolean' - ? geohashAgg.params.autoPrecision - : true; - if (isAutoPrecision) { - geohashAgg.params.precision = previousPrecision; - } }); this._kibanaMap.on('zoomend', () => { const geohashAgg = this._getGeoHashAgg(); @@ -78,15 +89,14 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { return; } const isAutoPrecision = - typeof geohashAgg.params.autoPrecision === 'boolean' - ? geohashAgg.params.autoPrecision + typeof geohashAgg.aggConfigParams.autoPrecision === 'boolean' + ? geohashAgg.aggConfigParams.autoPrecision : true; if (!isAutoPrecision) { return; } if (precisionChange) { - updateGeohashAgg(); - this.vis.updateState(); + this.updateGeohashAgg(); } else { //when we filter queries by collar this._updateData(this._geoJsonFeatureCollectionAndMeta); @@ -126,6 +136,14 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { return; } + if ( + !this._geoJsonFeatureCollectionAndMeta || + !geojsonFeatureCollectionAndMeta.featureCollection.features.length + ) { + this._geoJsonFeatureCollectionAndMeta = geojsonFeatureCollectionAndMeta; + this.updateGeohashAgg(); + } + this._geoJsonFeatureCollectionAndMeta = geojsonFeatureCollectionAndMeta; this._recreateGeohashLayer(); } @@ -181,7 +199,6 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { tooltipFormatter: this._geoJsonFeatureCollectionAndMeta ? boundTooltipFormatter : null, mapType: newParams.mapType, isFilteredByCollar: this._isFilteredByCollar(), - fetchBounds: () => this.vis.API.getGeohashBounds(), // TODO: Remove this (elastic/kibana#30593) colorRamp: newParams.colorSchema, heatmap: { heatClusterSize: newParams.heatClusterSize, @@ -194,8 +211,8 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { return; } - const indexPatternName = agg.getIndexPattern().id; - const field = agg.fieldName(); + const indexPatternName = agg.indexPatternId; + const field = agg.aggConfigParams.field; const filter = { meta: { negate: false, index: indexPatternName } }; filter[filterName] = { ignore_unmapped: true }; filter[filterName][field] = filterData; @@ -207,16 +224,16 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { } _getGeoHashAgg() { - return this.vis.getAggConfig().aggs.find(agg => { - return get(agg, 'type.dslName') === 'geohash_grid'; - }); + return ( + this._geoJsonFeatureCollectionAndMeta && this._geoJsonFeatureCollectionAndMeta.meta.geohash + ); } _isFilteredByCollar() { const DEFAULT = false; const agg = this._getGeoHashAgg(); if (agg) { - return get(agg, 'params.isFilteredByCollar', DEFAULT); + return get(agg, 'aggConfigParams.isFilteredByCollar', DEFAULT); } else { return DEFAULT; } diff --git a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx index 72838d2d97421..5729618b6ae07 100644 --- a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx +++ b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx @@ -17,8 +17,8 @@ * under the License. */ -import React, { useEffect, useMemo } from 'react'; import { get } from 'lodash'; +import React, { useEffect, useMemo } from 'react'; import { EuiIconTip, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -27,7 +27,7 @@ import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/publ import { tabifyGetColumns } from '../legacy_imports'; import { NumberInputOption, SwitchOption, SelectOption } from '../../../vis_type_vislib/public'; import { TableVisParams } from '../types'; -import { totalAggregations, isAggConfigNumeric } from './utils'; +import { totalAggregations } from './utils'; function TableOptions({ aggs, @@ -44,7 +44,7 @@ function TableOptions({ }), }, ...tabifyGetColumns(aggs.getResponseAggs(), true) - .filter(col => isAggConfigNumeric(get(col, 'aggConfig.type.name'), stateParams.dimensions)) + .filter(col => get(col.aggConfig.type.getFormat(col.aggConfig), 'type.id') === 'number') .map(({ name }) => ({ value: name, text: name })), ], [aggs, stateParams.percentageCol, stateParams.dimensions] diff --git a/src/legacy/core_plugins/vis_type_table/public/components/utils.ts b/src/legacy/core_plugins/vis_type_table/public/components/utils.ts index 365566503e25b..b97c7ccbac0f7 100644 --- a/src/legacy/core_plugins/vis_type_table/public/components/utils.ts +++ b/src/legacy/core_plugins/vis_type_table/public/components/utils.ts @@ -17,20 +17,8 @@ * under the License. */ -import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { AggTypes, Dimensions } from '../types'; - -function isAggConfigNumeric( - type: AggTypes, - { buckets, metrics }: Dimensions = { buckets: [], metrics: [] } -) { - const dimension = - buckets.find(({ aggType }) => aggType === type) || - metrics.find(({ aggType }) => aggType === type); - const formatType = get(dimension, 'format.id') || get(dimension, 'format.params.id'); - return formatType === 'number'; -} +import { AggTypes } from '../types'; const totalAggregations = [ { @@ -65,4 +53,4 @@ const totalAggregations = [ }, ]; -export { isAggConfigNumeric, totalAggregations }; +export { totalAggregations }; diff --git a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts index a792fc98842f1..2d27a99bdd8af 100644 --- a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts +++ b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts @@ -74,7 +74,7 @@ export class TableVisualizationController { return; } this.$scope.vis = this.vis; - this.$scope.visState = this.vis.getState(); + this.$scope.visState = { params: visParams }; this.$scope.esResponse = esResponse; if (!isEqual(this.$scope.visParams, visParams)) { diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_fn.ts b/src/legacy/core_plugins/vis_type_vega/public/vega_fn.ts index afb476472a273..2a0da81a31a96 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_fn.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_fn.ts @@ -73,7 +73,7 @@ export const createVegaFn = ( as: 'visualization', value: { visData: response, - visType: name, + visType: 'vega', visConfig: { spec: args.spec, }, diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts index 126e9d769f0a2..5e593398333c9 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -17,7 +17,7 @@ * under the License. */ -import _ from 'lodash'; +import _, { get } from 'lodash'; import { PersistedState } from 'ui/persisted_state'; import { Subscription } from 'rxjs'; import * as Rx from 'rxjs'; @@ -46,7 +46,6 @@ import { import { dispatchRenderComplete } from '../../../../../plugins/kibana_utils/public'; import { SavedSearch } from '../../../kibana/public/discover/np_ready/types'; import { Vis } from '../np_ready/public'; -import { queryGeohashBounds } from './query_geohash_bounds'; const getKeys = (o: T): Array => Object.keys(o) as Array; @@ -253,17 +252,6 @@ export class VisualizeEmbeddable extends Embeddable { - return queryGeohashBounds(this.savedVisualization.vis, { - filters: this.filters, - query: this.query, - searchSource: this.savedVisualization.searchSource, - }); - }; - // this is a hack to make editor still work, will be removed once we clean up editor this.vis.hasInspector = () => { const visTypesWithoutInspector = [ @@ -290,6 +278,22 @@ export class VisualizeEmbeddable extends Embeddable { + // maps hack, remove once esaggs function is cleaned up and ready to accept variables + if (event.name === 'bounds') { + const agg = this.vis.getAggConfig().aggs.find((a: any) => { + return get(a, 'type.dslName') === 'geohash_grid'; + }); + if ( + agg.params.precision !== event.data.precision || + !_.isEqual(agg.params.boundingBox, event.data.boundingBox) + ) { + agg.params.boundingBox = event.data.boundingBox; + agg.params.precision = event.data.precision; + this.reload(); + } + return; + } + const eventName = event.name === 'brush' ? SELECT_RANGE_TRIGGER : VALUE_CLICK_TRIGGER; npStart.plugins.uiActions.executeTriggerActions(eventName, { @@ -355,7 +359,6 @@ export class VisualizeEmbeddable extends Embeddable ({ render: async (domNode: HTMLElement, config: any, handlers: any) => { const { visData, visConfig, params } = config; const visType = config.visType || visConfig.type; - const $injector = await legacyChrome.dangerouslyGetActiveInjector(); - const $rootScope = $injector.get('$rootScope') as any; - if (handlers.vis) { - // special case in visualize, we need to render first (without executing the expression), for maps to work - if (visConfig) { - $rootScope.$apply(() => { - handlers.vis.setCurrentState({ - type: visType, - params: visConfig, - title: handlers.vis.title, - }); - }); - } - } else { - handlers.vis = new Vis({ - type: visType, - params: visConfig, - }); - } + const vis = new Vis({ + type: visType, + params: visConfig, + }); - handlers.vis.eventsSubject = { next: handlers.event }; + vis.eventsSubject = { next: handlers.event }; - const uiState = handlers.uiState || handlers.vis.getUiState(); + const uiState = handlers.uiState || vis.getUiState(); handlers.onDestroy(() => { unmountComponentAtNode(domNode); @@ -63,9 +47,9 @@ export const visualization = () => ({ const listenOnChange = params ? params.listenOnChange : false; render( = minGeohashPixels) { + zoomPrecision[zoom] = precision; + } else { + break; + } + } +} + +export function getPrecision(val: string) { + let precision = parseInt(val, 10); + + if (Number.isNaN(precision)) { + precision = defaultPrecision; + } + + if (precision > maxPrecision) { + return maxPrecision; + } + + return precision; +} + +interface GeoBoundingBoxCoordinate { + lat: number; + lon: number; +} + +interface GeoBoundingBox { + top_left: GeoBoundingBoxCoordinate; + bottom_right: GeoBoundingBoxCoordinate; +} + +export function scaleBounds(bounds: GeoBoundingBox): GeoBoundingBox { + const scale = 0.5; // scale bounds by 50% + + const topLeft = bounds.top_left; + const bottomRight = bounds.bottom_right; + let latDiff = _.round(Math.abs(topLeft.lat - bottomRight.lat), 5); + const lonDiff = _.round(Math.abs(bottomRight.lon - topLeft.lon), 5); + // map height can be zero when vis is first created + if (latDiff === 0) latDiff = lonDiff; + + const latDelta = latDiff * scale; + let topLeftLat = _.round(topLeft.lat, 5) + latDelta; + if (topLeftLat > 90) topLeftLat = 90; + let bottomRightLat = _.round(bottomRight.lat, 5) - latDelta; + if (bottomRightLat < -90) bottomRightLat = -90; + const lonDelta = lonDiff * scale; + let topLeftLon = _.round(topLeft.lon, 5) - lonDelta; + if (topLeftLon < -180) topLeftLon = -180; + let bottomRightLon = _.round(bottomRight.lon, 5) + lonDelta; + if (bottomRightLon > 180) bottomRightLon = 180; + + return { + top_left: { lat: topLeftLat, lon: topLeftLon }, + bottom_right: { lat: bottomRightLat, lon: bottomRightLon }, + }; +} + +export function geoContains(collar?: GeoBoundingBox, bounds?: GeoBoundingBox) { + if (!bounds || !collar) return false; + // test if bounds top_left is outside 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 outside 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 bounds + return true; +}