diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 613e5074593899..8fa44c512df4b5 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -72,11 +72,12 @@ export enum FIELD_ORIGIN { } export const JOIN_FIELD_NAME_PREFIX = '__kbnjoin__'; -export const SOURCE_DATA_ID_ORIGIN = 'source'; -export const META_ID_ORIGIN_SUFFIX = 'meta'; -export const SOURCE_META_ID_ORIGIN = `${SOURCE_DATA_ID_ORIGIN}_${META_ID_ORIGIN_SUFFIX}`; -export const FORMATTERS_ID_ORIGIN_SUFFIX = 'formatters'; -export const SOURCE_FORMATTERS_ID_ORIGIN = `${SOURCE_DATA_ID_ORIGIN}_${FORMATTERS_ID_ORIGIN_SUFFIX}`; +export const META_DATA_REQUEST_ID_SUFFIX = 'meta'; +export const FORMATTERS_DATA_REQUEST_ID_SUFFIX = 'formatters'; +export const SOURCE_DATA_REQUEST_ID = 'source'; +export const SOURCE_META_DATA_REQUEST_ID = `${SOURCE_DATA_REQUEST_ID}_${META_DATA_REQUEST_ID_SUFFIX}`; +export const SOURCE_FORMATTERS_DATA_REQUEST_ID = `${SOURCE_DATA_REQUEST_ID}_${FORMATTERS_DATA_REQUEST_ID_SUFFIX}`; +export const SOURCE_BOUNDS_DATA_REQUEST_ID = `${SOURCE_DATA_REQUEST_ID}_bounds`; export const MIN_ZOOM = 0; export const MAX_ZOOM = 24; diff --git a/x-pack/plugins/maps/public/actions/data_request_actions.ts b/x-pack/plugins/maps/public/actions/data_request_actions.ts index d4182144169005..13b658af6a0f32 100644 --- a/x-pack/plugins/maps/public/actions/data_request_actions.ts +++ b/x-pack/plugins/maps/public/actions/data_request_actions.ts @@ -6,12 +6,15 @@ /* eslint-disable @typescript-eslint/consistent-type-definitions */ import { Dispatch } from 'redux'; +// @ts-ignore +import turf from 'turf'; import { FeatureCollection } from 'geojson'; import { MapStoreState } from '../reducers/store'; -import { LAYER_TYPE, SOURCE_DATA_ID_ORIGIN } from '../../common/constants'; +import { LAYER_TYPE, SOURCE_DATA_REQUEST_ID } from '../../common/constants'; import { getDataFilters, getDataRequestDescriptor, + getFittableLayers, getLayerById, getLayerList, } from '../selectors/map_selectors'; @@ -27,13 +30,15 @@ import { LAYER_DATA_LOAD_ENDED, LAYER_DATA_LOAD_ERROR, LAYER_DATA_LOAD_STARTED, + SET_GOTO, SET_LAYER_ERROR_STATUS, SET_LAYER_STYLE_META, UPDATE_LAYER_PROP, UPDATE_SOURCE_DATA_REQUEST, } from './map_action_constants'; import { ILayer } from '../classes/layers/layer'; -import { DataMeta, MapFilters } from '../../common/descriptor_types'; +import { DataMeta, MapExtent, MapFilters } from '../../common/descriptor_types'; +import { DataRequestAbortError } from '../classes/util/data_request'; export type DataRequestContext = { startLoading(dataId: string, requestToken: symbol, meta: DataMeta): void; @@ -269,7 +274,7 @@ export function updateSourceDataRequest(layerId: string, newData: unknown) { return (dispatch: Dispatch) => { dispatch({ type: UPDATE_SOURCE_DATA_REQUEST, - dataId: SOURCE_DATA_ID_ORIGIN, + dataId: SOURCE_DATA_REQUEST_ID, layerId, newData, }); @@ -277,3 +282,99 @@ export function updateSourceDataRequest(layerId: string, newData: unknown) { dispatch(updateStyleMeta(layerId)); }; } + +export function fitToLayerExtent(layerId: string) { + return async (dispatch: Dispatch, getState: () => MapStoreState) => { + const targetLayer = getLayerById(layerId, getState()); + + if (targetLayer) { + try { + const bounds = await targetLayer.getBounds( + getDataRequestContext(dispatch, getState, layerId) + ); + if (bounds) { + await dispatch(setGotoWithBounds(bounds)); + } + } catch (error) { + if (!(error instanceof DataRequestAbortError)) { + // eslint-disable-next-line no-console + console.warn( + 'Unhandled getBounds error for layer. Only DataRequestAbortError should be surfaced', + error + ); + } + // new fitToLayerExtent request has superseded this thread of execution. Results no longer needed. + return; + } + } + }; +} + +export function fitToDataBounds() { + return async (dispatch: Dispatch, getState: () => MapStoreState) => { + const layerList = getFittableLayers(getState()); + + if (!layerList.length) { + return; + } + + const boundsPromises = layerList.map(async (layer: ILayer) => { + return layer.getBounds(getDataRequestContext(dispatch, getState, layer.getId())); + }); + + let bounds; + try { + bounds = await Promise.all(boundsPromises); + } catch (error) { + if (!(error instanceof DataRequestAbortError)) { + // eslint-disable-next-line no-console + console.warn( + 'Unhandled getBounds error for layer. Only DataRequestAbortError should be surfaced', + error + ); + } + // new fitToDataBounds request has superseded this thread of execution. Results no longer needed. + return; + } + + const corners = []; + for (let i = 0; i < bounds.length; i++) { + const b = bounds[i]; + + // filter out undefined bounds (uses Infinity due to turf responses) + if ( + b === null || + b.minLon === Infinity || + b.maxLon === Infinity || + b.minLat === -Infinity || + b.maxLat === -Infinity + ) { + continue; + } + + corners.push([b.minLon, b.minLat]); + corners.push([b.maxLon, b.maxLat]); + } + + if (!corners.length) { + return; + } + + const turfUnionBbox = turf.bbox(turf.multiPoint(corners)); + const dataBounds = { + minLon: turfUnionBbox[0], + minLat: turfUnionBbox[1], + maxLon: turfUnionBbox[2], + maxLat: turfUnionBbox[3], + }; + + dispatch(setGotoWithBounds(dataBounds)); + }; +} + +function setGotoWithBounds(bounds: MapExtent) { + return { + type: SET_GOTO, + bounds, + }; +} diff --git a/x-pack/plugins/maps/public/actions/index.ts b/x-pack/plugins/maps/public/actions/index.ts index a2e90ff6e9f28c..5b153e37da5a85 100644 --- a/x-pack/plugins/maps/public/actions/index.ts +++ b/x-pack/plugins/maps/public/actions/index.ts @@ -9,7 +9,12 @@ export * from './ui_actions'; export * from './map_actions'; export * from './map_action_constants'; export * from './layer_actions'; -export { cancelAllInFlightRequests, DataRequestContext } from './data_request_actions'; +export { + cancelAllInFlightRequests, + DataRequestContext, + fitToLayerExtent, + fitToDataBounds, +} from './data_request_actions'; export { closeOnClickTooltip, openOnClickTooltip, diff --git a/x-pack/plugins/maps/public/actions/map_actions.ts b/x-pack/plugins/maps/public/actions/map_actions.ts index 02842edabbd2e5..75df8689a670ef 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.ts +++ b/x-pack/plugins/maps/public/actions/map_actions.ts @@ -12,11 +12,9 @@ import turfBooleanContains from '@turf/boolean-contains'; import { Filter, Query, TimeRange } from 'src/plugins/data/public'; import { MapStoreState } from '../reducers/store'; import { - getLayerById, getDataFilters, getWaitingForMapReadyLayerListRaw, getQuery, - getFittableLayers, } from '../selectors/map_selectors'; import { CLEAR_GOTO, @@ -184,76 +182,6 @@ export function disableScrollZoom() { return { type: SET_SCROLL_ZOOM, scrollZoom: false }; } -export function fitToLayerExtent(layerId: string) { - return async (dispatch: Dispatch, getState: () => MapStoreState) => { - const targetLayer = getLayerById(layerId, getState()); - - if (targetLayer) { - const dataFilters = getDataFilters(getState()); - const bounds = await targetLayer.getBounds(dataFilters); - if (bounds) { - await dispatch(setGotoWithBounds(bounds)); - } - } - }; -} - -export function fitToDataBounds() { - return async (dispatch: Dispatch, getState: () => MapStoreState) => { - const layerList = getFittableLayers(getState()); - - if (!layerList.length) { - return; - } - - const dataFilters = getDataFilters(getState()); - const boundsPromises = layerList.map(async (layer) => { - return layer.getBounds(dataFilters); - }); - - const bounds = await Promise.all(boundsPromises); - const corners = []; - for (let i = 0; i < bounds.length; i++) { - const b = bounds[i]; - - // filter out undefined bounds (uses Infinity due to turf responses) - if ( - b === null || - b.minLon === Infinity || - b.maxLon === Infinity || - b.minLat === -Infinity || - b.maxLat === -Infinity - ) { - continue; - } - - corners.push([b.minLon, b.minLat]); - corners.push([b.maxLon, b.maxLat]); - } - - if (!corners.length) { - return; - } - - const turfUnionBbox = turf.bbox(turf.multiPoint(corners)); - const dataBounds = { - minLon: turfUnionBbox[0], - minLat: turfUnionBbox[1], - maxLon: turfUnionBbox[2], - maxLat: turfUnionBbox[3], - }; - - dispatch(setGotoWithBounds(dataBounds)); - }; -} - -export function setGotoWithBounds(bounds: MapExtent) { - return { - type: SET_GOTO, - bounds, - }; -} - export function setGotoWithCenter({ lat, lon, zoom }: MapCenterAndZoom) { return { type: SET_GOTO, diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.js b/x-pack/plugins/maps/public/classes/joins/inner_join.js index 5f8bc7385d04cf..76afe2430b818e 100644 --- a/x-pack/plugins/maps/public/classes/joins/inner_join.js +++ b/x-pack/plugins/maps/public/classes/joins/inner_join.js @@ -6,7 +6,10 @@ import { ESTermSource } from '../sources/es_term_source'; import { getComputedFieldNamePrefix } from '../styles/vector/style_util'; -import { META_ID_ORIGIN_SUFFIX, FORMATTERS_ID_ORIGIN_SUFFIX } from '../../../common/constants'; +import { + META_DATA_REQUEST_ID_SUFFIX, + FORMATTERS_DATA_REQUEST_ID_SUFFIX, +} from '../../../common/constants'; export class InnerJoin { constructor(joinDescriptor, leftSource) { @@ -42,11 +45,11 @@ export class InnerJoin { } getSourceMetaDataRequestId() { - return `${this.getSourceDataRequestId()}_${META_ID_ORIGIN_SUFFIX}`; + return `${this.getSourceDataRequestId()}_${META_DATA_REQUEST_ID_SUFFIX}`; } getSourceFormattersDataRequestId() { - return `${this.getSourceDataRequestId()}_${FORMATTERS_ID_ORIGIN_SUFFIX}`; + return `${this.getSourceDataRequestId()}_${FORMATTERS_DATA_REQUEST_ID_SUFFIX}`; } getLeftField() { diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index 263e9888cd059e..19a0152a19df7c 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -17,21 +17,16 @@ import { MAX_ZOOM, MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER, MIN_ZOOM, - SOURCE_DATA_ID_ORIGIN, + SOURCE_DATA_REQUEST_ID, } from '../../../common/constants'; import { copyPersistentState } from '../../reducers/util'; -import { - LayerDescriptor, - MapExtent, - MapFilters, - StyleDescriptor, -} from '../../../common/descriptor_types'; +import { LayerDescriptor, MapExtent, StyleDescriptor } from '../../../common/descriptor_types'; import { Attribution, ImmutableSourceProperty, ISource, SourceEditorArgs } from '../sources/source'; import { DataRequestContext } from '../../actions'; import { IStyle } from '../styles/style'; export interface ILayer { - getBounds(mapFilters: MapFilters): Promise; + getBounds(dataRequestContext: DataRequestContext): Promise; getDataRequest(id: string): DataRequest | undefined; getDisplayName(source?: ISource): Promise; getId(): string; @@ -396,7 +391,7 @@ export class AbstractLayer implements ILayer { } getSourceDataRequest(): DataRequest | undefined { - return this.getDataRequest(SOURCE_DATA_ID_ORIGIN); + return this.getDataRequest(SOURCE_DATA_REQUEST_ID); } getDataRequest(id: string): DataRequest | undefined { @@ -450,13 +445,8 @@ export class AbstractLayer implements ILayer { return sourceDataRequest ? sourceDataRequest.hasData() : false; } - async getBounds(mapFilters: MapFilters): Promise { - return { - minLon: -180, - maxLon: 180, - minLat: -89, - maxLat: 89, - }; + async getBounds(dataRequestContext: DataRequestContext): Promise { + return null; } renderStyleEditor({ diff --git a/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js b/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js index 5108e5cd3e6a3e..cd8ca44d4478b7 100644 --- a/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js @@ -6,7 +6,7 @@ import { AbstractLayer } from '../layer'; import _ from 'lodash'; -import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../../../common/constants'; +import { SOURCE_DATA_REQUEST_ID, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../../../common/constants'; import { TileStyle } from '../../styles/tile/tile_style'; export class TileLayer extends AbstractLayer { @@ -31,12 +31,12 @@ export class TileLayer extends AbstractLayer { return; } const requestToken = Symbol(`layer-source-refresh:${this.getId()} - source`); - startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataFilters); + startLoading(SOURCE_DATA_REQUEST_ID, requestToken, dataFilters); try { const url = await this.getSource().getUrlTemplate(); - stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, url, {}); + stopLoading(SOURCE_DATA_REQUEST_ID, requestToken, url, {}); } catch (error) { - onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); + onLoadError(SOURCE_DATA_REQUEST_ID, requestToken, error.message); } } diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx index 812b7b409fe12a..a00639aa5fec54 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiIcon } from '@elastic/eui'; import { VectorStyle } from '../../styles/vector/vector_style'; -import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../../../common/constants'; +import { SOURCE_DATA_REQUEST_ID, LAYER_TYPE } from '../../../../common/constants'; import { VectorLayer, VectorLayerArguments } from '../vector_layer/vector_layer'; import { canSkipSourceUpdate } from '../../util/can_skip_fetch'; import { ITiledSingleLayerVectorSource } from '../../sources/vector_source'; @@ -56,7 +56,7 @@ export class TiledVectorLayer extends VectorLayer { onLoadError, dataFilters, }: DataRequestContext) { - const requestToken: symbol = Symbol(`layer-${this.getId()}-${SOURCE_DATA_ID_ORIGIN}`); + const requestToken: symbol = Symbol(`layer-${this.getId()}-${SOURCE_DATA_REQUEST_ID}`); const searchFilters: VectorSourceRequestMeta = this._getSearchFilters( dataFilters, this.getSource(), @@ -73,12 +73,12 @@ export class TiledVectorLayer extends VectorLayer { return null; } - startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, searchFilters); + startLoading(SOURCE_DATA_REQUEST_ID, requestToken, searchFilters); try { const templateWithMeta = await this._source.getUrlTemplateWithMeta(); - stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, templateWithMeta, {}); + stopLoading(SOURCE_DATA_REQUEST_ID, requestToken, templateWithMeta, {}); } catch (error) { - onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); + onLoadError(SOURCE_DATA_REQUEST_ID, requestToken, error.message); } } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js index a2a0e58e48fd21..524ab245c67601 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js @@ -9,9 +9,10 @@ import { AbstractLayer } from '../layer'; import { VectorStyle } from '../../styles/vector/vector_style'; import { FEATURE_ID_PROPERTY_NAME, - SOURCE_DATA_ID_ORIGIN, - SOURCE_META_ID_ORIGIN, - SOURCE_FORMATTERS_ID_ORIGIN, + SOURCE_DATA_REQUEST_ID, + SOURCE_META_DATA_REQUEST_ID, + SOURCE_FORMATTERS_DATA_REQUEST_ID, + SOURCE_BOUNDS_DATA_REQUEST_ID, FEATURE_VISIBLE_PROPERTY_NAME, EMPTY_FEATURE_COLLECTION, LAYER_TYPE, @@ -155,18 +156,41 @@ export class VectorLayer extends AbstractLayer { return this.getCurrentStyle().renderLegendDetails(); } - async getBounds(dataFilters) { + async getBounds({ startLoading, stopLoading, registerCancelCallback, dataFilters }) { const isStaticLayer = !this.getSource().isBoundsAware(); if (isStaticLayer) { return getFeatureCollectionBounds(this._getSourceFeatureCollection(), this._hasJoins()); } + const requestToken = Symbol(`${SOURCE_BOUNDS_DATA_REQUEST_ID}-${this.getId()}`); const searchFilters = this._getSearchFilters( dataFilters, this.getSource(), this.getCurrentStyle() ); - return await this.getSource().getBoundsForFilters(searchFilters); + // Do not pass all searchFilters to source.getBoundsForFilters(). + // For example, do not want to filter bounds request by extent and buffer. + const boundsFilters = { + sourceQuery: searchFilters.sourceQuery, + query: searchFilters.query, + timeFilters: searchFilters.timeFilters, + filters: searchFilters.filters, + applyGlobalQuery: searchFilters.applyGlobalQuery, + }; + + let bounds = null; + try { + startLoading(SOURCE_BOUNDS_DATA_REQUEST_ID, requestToken, boundsFilters); + bounds = await this.getSource().getBoundsForFilters( + boundsFilters, + registerCancelCallback.bind(null, requestToken) + ); + } finally { + // Use stopLoading callback instead of onLoadError callback. + // Function is loading bounds and not feature data. + stopLoading(SOURCE_BOUNDS_DATA_REQUEST_ID, requestToken, bounds, boundsFilters); + } + return bounds; } async getLeftJoinFields() { @@ -342,7 +366,7 @@ export class VectorLayer extends AbstractLayer { dataFilters, isRequestStillActive, } = syncContext; - const dataRequestId = SOURCE_DATA_ID_ORIGIN; + const dataRequestId = SOURCE_DATA_REQUEST_ID; const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`); const searchFilters = this._getSearchFilters(dataFilters, source, style); const prevDataRequest = this.getSourceDataRequest(); @@ -394,7 +418,7 @@ export class VectorLayer extends AbstractLayer { source, style, sourceQuery: this.getQuery(), - dataRequestId: SOURCE_META_ID_ORIGIN, + dataRequestId: SOURCE_META_DATA_REQUEST_ID, dynamicStyleProps: style.getDynamicPropertiesArray().filter((dynamicStyleProp) => { return ( dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE && @@ -470,7 +494,7 @@ export class VectorLayer extends AbstractLayer { layerName, style, dynamicStyleProps, - registerCancelCallback, + registerCancelCallback.bind(null, requestToken), nextMeta ); stopLoading(dataRequestId, requestToken, styleMeta, nextMeta); @@ -488,7 +512,7 @@ export class VectorLayer extends AbstractLayer { return this._syncFormatters({ source, - dataRequestId: SOURCE_FORMATTERS_ID_ORIGIN, + dataRequestId: SOURCE_FORMATTERS_DATA_REQUEST_ID, fields: style .getDynamicPropertiesArray() .filter((dynamicStyleProp) => { diff --git a/x-pack/plugins/maps/public/classes/layers/vector_tile_layer/vector_tile_layer.js b/x-pack/plugins/maps/public/classes/layers/vector_tile_layer/vector_tile_layer.js index 6f616afb64041d..61ec02e72adf22 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_tile_layer/vector_tile_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/vector_tile_layer/vector_tile_layer.js @@ -6,7 +6,7 @@ import { TileLayer } from '../tile_layer/tile_layer'; import _ from 'lodash'; -import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../../../common/constants'; +import { SOURCE_DATA_REQUEST_ID, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../../../common/constants'; import { isRetina } from '../../../meta'; import { addSpriteSheetToMapFromImageData, @@ -56,16 +56,16 @@ export class VectorTileLayer extends TileLayer { const requestToken = Symbol(`layer-source-refresh:${this.getId()} - source`); try { - startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataFilters); + startLoading(SOURCE_DATA_REQUEST_ID, requestToken, dataFilters); const styleAndSprites = await this.getSource().getVectorStyleSheetAndSpriteMeta(isRetina()); const spriteSheetImageData = await loadSpriteSheetImageData(styleAndSprites.spriteMeta.png); const data = { ...styleAndSprites, spriteSheetImageData, }; - stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data, nextMeta); + stopLoading(SOURCE_DATA_REQUEST_ID, requestToken, data, nextMeta); } catch (error) { - onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); + onLoadError(SOURCE_DATA_REQUEST_ID, requestToken, error.message); } } diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js index 072f952fb8a13c..450894d81485c2 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js @@ -145,11 +145,8 @@ export class AbstractESSource extends AbstractVectorSource { return searchSource; } - async getBoundsForFilters({ sourceQuery, query, timeFilters, filters, applyGlobalQuery }) { - const searchSource = await this.makeSearchSource( - { sourceQuery, query, timeFilters, filters, applyGlobalQuery }, - 0 - ); + async getBoundsForFilters(boundsFilters, registerCancelCallback) { + const searchSource = await this.makeSearchSource(boundsFilters, 0); searchSource.setField('aggs', { fitToBounds: { geo_bounds: { @@ -160,13 +157,19 @@ export class AbstractESSource extends AbstractVectorSource { let esBounds; try { - const esResp = await searchSource.fetch(); + const abortController = new AbortController(); + registerCancelCallback(() => abortController.abort()); + const esResp = await searchSource.fetch({ abortSignal: abortController.signal }); if (!esResp.aggregations.fitToBounds.bounds) { // aggregations.fitToBounds is empty object when there are no matching documents return null; } esBounds = esResp.aggregations.fitToBounds.bounds; } catch (error) { + if (error.name === 'AbortError') { + throw new DataRequestAbortError(); + } + return null; } diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts index 5f6061b38678c0..86a1589a7a0305 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; import { AbstractSource, ImmutableSourceProperty } from '../source'; -import { GeoJsonWithMeta, ITiledSingleLayerVectorSource } from '../vector_source'; +import { BoundsFilters, GeoJsonWithMeta, ITiledSingleLayerVectorSource } from '../vector_source'; import { MAX_ZOOM, MIN_ZOOM, SOURCE_TYPES } from '../../../../common/constants'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; import { IField } from '../../fields/field'; @@ -16,7 +16,6 @@ import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters import { MapExtent, TiledSingleLayerVectorSourceDescriptor, - VectorSourceRequestMeta, VectorSourceSyncMeta, } from '../../../../common/descriptor_types'; import { MVTSingleLayerVectorSourceConfig } from './mvt_single_layer_vector_source_editor'; @@ -133,13 +132,11 @@ export class MVTSingleLayerVectorSource extends AbstractSource return this._descriptor.maxSourceZoom; } - getBoundsForFilters(searchFilters: VectorSourceRequestMeta): MapExtent { - return { - maxLat: 90, - maxLon: 180, - minLat: -90, - minLon: -180, - }; + getBoundsForFilters( + boundsFilters: BoundsFilters, + registerCancelCallback: (requestToken: symbol, callback: () => void) => void + ): MapExtent | null { + return null; } getFieldByName(fieldName: string): IField | null { diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts index 2dd6bcd8581379..711b7d600d74d9 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts @@ -6,11 +6,13 @@ /* eslint-disable @typescript-eslint/consistent-type-definitions */ import { FeatureCollection } from 'geojson'; +import { Filter, TimeRange } from 'src/plugins/data/public'; import { AbstractSource, ISource } from '../source'; import { IField } from '../../fields/field'; import { ESSearchSourceResponseMeta, MapExtent, + MapQuery, VectorSourceRequestMeta, VectorSourceSyncMeta, } from '../../../../common/descriptor_types'; @@ -24,9 +26,20 @@ export type GeoJsonWithMeta = { meta?: GeoJsonFetchMeta; }; +export type BoundsFilters = { + applyGlobalQuery: boolean; + filters: Filter[]; + query: MapQuery; + sourceQuery: MapQuery; + timeFilters: TimeRange; +}; + export interface IVectorSource extends ISource { filterAndFormatPropertiesToHtml(properties: unknown): Promise; - getBoundsForFilters(searchFilters: VectorSourceRequestMeta): MapExtent; + getBoundsForFilters( + boundsFilters: BoundsFilters, + registerCancelCallback: (requestToken: symbol, callback: () => void) => void + ): MapExtent | null; getGeoJsonWithMeta( layerName: 'string', searchFilters: unknown[], @@ -42,7 +55,10 @@ export interface IVectorSource extends ISource { export class AbstractVectorSource extends AbstractSource implements IVectorSource { filterAndFormatPropertiesToHtml(properties: unknown): Promise; - getBoundsForFilters(searchFilters: VectorSourceRequestMeta): MapExtent; + getBoundsForFilters( + boundsFilters: BoundsFilters, + registerCancelCallback: (requestToken: symbol, callback: () => void) => void + ): MapExtent | null; getGeoJsonWithMeta( layerName: 'string', searchFilters: unknown[], diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js index 98d5d3feb60ea8..15d0b3c4bf9137 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js @@ -7,7 +7,11 @@ import _ from 'lodash'; import { AbstractStyleProperty } from './style_property'; import { DEFAULT_SIGMA } from '../vector_style_defaults'; -import { STYLE_TYPE, SOURCE_META_ID_ORIGIN, FIELD_ORIGIN } from '../../../../../common/constants'; +import { + STYLE_TYPE, + SOURCE_META_DATA_REQUEST_ID, + FIELD_ORIGIN, +} from '../../../../../common/constants'; import React from 'react'; import { OrdinalFieldMetaPopover } from '../components/field_meta/ordinal_field_meta_popover'; import { CategoricalFieldMetaPopover } from '../components/field_meta/categorical_field_meta_popover'; @@ -30,7 +34,7 @@ export class DynamicStyleProperty extends AbstractStyleProperty { _getStyleMetaDataRequestId(fieldName) { if (this.getFieldOrigin() === FIELD_ORIGIN.SOURCE) { - return SOURCE_META_ID_ORIGIN; + return SOURCE_META_DATA_REQUEST_ID; } const join = this._layer.getValidJoins().find((join) => { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.js b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.js index f3ed18bd1302ec..989ac268c05521 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.js @@ -13,7 +13,7 @@ import { GEO_JSON_TYPE, FIELD_ORIGIN, STYLE_TYPE, - SOURCE_FORMATTERS_ID_ORIGIN, + SOURCE_FORMATTERS_DATA_REQUEST_ID, LAYER_STYLE_TYPE, DEFAULT_ICON, VECTOR_STYLES, @@ -373,7 +373,7 @@ export class VectorStyle extends AbstractStyle { let dataRequestId; if (dynamicProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE) { - dataRequestId = SOURCE_FORMATTERS_ID_ORIGIN; + dataRequestId = SOURCE_FORMATTERS_DATA_REQUEST_ID; } else { const join = this._layer.getValidJoins().find((join) => { return join.getRightJoinSource().hasMatchingMetricField(fieldName); diff --git a/x-pack/plugins/maps/public/reducers/map.js b/x-pack/plugins/maps/public/reducers/map.js index c5f3968b749f12..a76768b4ba5077 100644 --- a/x-pack/plugins/maps/public/reducers/map.js +++ b/x-pack/plugins/maps/public/reducers/map.js @@ -54,7 +54,7 @@ import { import { getDefaultMapSettings } from './default_map_settings'; import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from './util'; -import { SOURCE_DATA_ID_ORIGIN } from '../../common/constants'; +import { SOURCE_DATA_REQUEST_ID } from '../../common/constants'; const getLayerIndex = (list, layerId) => list.findIndex(({ id }) => layerId === id); @@ -448,7 +448,7 @@ function updateSourceDataRequest(state, action) { return state; } const dataRequest = layerDescriptor.__dataRequests.find((dataRequest) => { - return dataRequest.dataId === SOURCE_DATA_ID_ORIGIN; + return dataRequest.dataId === SOURCE_DATA_REQUEST_ID; }); if (!dataRequest) { return state; diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 0789222b0bf386..28084cac19f1a7 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -26,7 +26,7 @@ import { getSourceByType } from '../classes/sources/source_registry'; import { GeojsonFileSource } from '../classes/sources/client_file_source'; import { LAYER_TYPE, - SOURCE_DATA_ID_ORIGIN, + SOURCE_DATA_REQUEST_ID, STYLE_TYPE, VECTOR_STYLES, SPATIAL_FILTERS_LAYER_ID, @@ -266,7 +266,7 @@ export const getSpatialFiltersLayer = createSelector( alpha: settings.spatialFiltersAlpa, __dataRequests: [ { - dataId: SOURCE_DATA_ID_ORIGIN, + dataId: SOURCE_DATA_REQUEST_ID, data: featureCollection, }, ],