From 954e00ad236b829e08607ce7fc57d884045e9dd8 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 29 Jul 2020 10:19:11 -0600 Subject: [PATCH] [Maps] fix fit to data for Point to Point layer (#73563) * [Maps] fix fit to data for Point to Point layer * tslint Co-authored-by: Elastic Machine --- .../public/actions/data_request_actions.ts | 10 +-- .../es_pew_pew_source/es_pew_pew_source.js | 72 +++++++++++++++---- .../classes/sources/es_source/es_source.js | 6 +- .../maps/public/elasticsearch_geo_utils.d.ts | 2 + .../maps/public/elasticsearch_geo_utils.js | 9 +++ .../functional/apps/maps/es_pew_pew_source.js | 9 +++ 6 files changed, 84 insertions(+), 24 deletions(-) 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 5919feadfcc2a..f91e272d625f6 100644 --- a/x-pack/plugins/maps/public/actions/data_request_actions.ts +++ b/x-pack/plugins/maps/public/actions/data_request_actions.ts @@ -40,7 +40,7 @@ import { ILayer } from '../classes/layers/layer'; import { IVectorLayer } from '../classes/layers/vector_layer/vector_layer'; import { DataMeta, MapExtent, MapFilters } from '../../common/descriptor_types'; import { DataRequestAbortError } from '../classes/util/data_request'; -import { scaleBounds } from '../elasticsearch_geo_utils'; +import { scaleBounds, turfBboxToBounds } from '../elasticsearch_geo_utils'; const FIT_TO_BOUNDS_SCALE_FACTOR = 0.1; @@ -368,13 +368,7 @@ export function fitToDataBounds() { return; } - const turfUnionBbox = turf.bbox(turf.multiPoint(corners)); - const dataBounds = { - minLon: turfUnionBbox[0], - minLat: turfUnionBbox[1], - maxLon: turfUnionBbox[2], - maxLat: turfUnionBbox[3], - }; + const dataBounds = turfBboxToBounds(turf.bbox(turf.multiPoint(corners))); dispatch(setGotoWithBounds(scaleBounds(dataBounds, FIT_TO_BOUNDS_SCALE_FACTOR))); }; diff --git a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js index 98db7bcdcc8a3..33d5deef2e39f 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js @@ -6,6 +6,7 @@ import React from 'react'; import uuid from 'uuid/v4'; +import turf from 'turf'; import { UpdateSourceEditor } from './update_source_editor'; import { i18n } from '@kbn/i18n'; @@ -13,8 +14,9 @@ import { SOURCE_TYPES, VECTOR_SHAPE_TYPE } from '../../../../common/constants'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { convertToLines } from './convert_to_lines'; import { AbstractESAggSource, DEFAULT_METRIC } from '../es_agg_source'; -import { indexPatterns } from '../../../../../../../src/plugins/data/public'; import { registerSource } from '../source_registry'; +import { turfBboxToBounds } from '../../../elasticsearch_geo_utils'; +import { DataRequestAbortError } from '../../util/data_request'; const MAX_GEOTILE_LEVEL = 29; @@ -158,19 +160,63 @@ export class ESPewPewSource extends AbstractESAggSource { }; } - async _getGeoField() { - const indexPattern = await this.getIndexPattern(); - const field = indexPattern.fields.getByName(this._descriptor.destGeoField); - const geoField = indexPatterns.isNestedField(field) ? undefined : field; - if (!geoField) { - throw new Error( - i18n.translate('xpack.maps.source.esSource.noGeoFieldErrorMessage', { - defaultMessage: `Index pattern {indexPatternTitle} no longer contains the geo field {geoField}`, - values: { indexPatternTitle: indexPattern.title, geoField: this._descriptor.geoField }, - }) - ); + getGeoFieldName() { + return this._descriptor.destGeoField; + } + + async getBoundsForFilters(boundsFilters, registerCancelCallback) { + const searchSource = await this.makeSearchSource(boundsFilters, 0); + searchSource.setField('aggs', { + destFitToBounds: { + geo_bounds: { + field: this._descriptor.destGeoField, + }, + }, + sourceFitToBounds: { + geo_bounds: { + field: this._descriptor.sourceGeoField, + }, + }, + }); + + const corners = []; + try { + const abortController = new AbortController(); + registerCancelCallback(() => abortController.abort()); + const esResp = await searchSource.fetch({ abortSignal: abortController.signal }); + if (esResp.aggregations.destFitToBounds.bounds) { + corners.push([ + esResp.aggregations.destFitToBounds.bounds.top_left.lon, + esResp.aggregations.destFitToBounds.bounds.top_left.lat, + ]); + corners.push([ + esResp.aggregations.destFitToBounds.bounds.bottom_right.lon, + esResp.aggregations.destFitToBounds.bounds.bottom_right.lat, + ]); + } + if (esResp.aggregations.sourceFitToBounds.bounds) { + corners.push([ + esResp.aggregations.sourceFitToBounds.bounds.top_left.lon, + esResp.aggregations.sourceFitToBounds.bounds.top_left.lat, + ]); + corners.push([ + esResp.aggregations.sourceFitToBounds.bounds.bottom_right.lon, + esResp.aggregations.sourceFitToBounds.bounds.bottom_right.lat, + ]); + } + } catch (error) { + if (error.name === 'AbortError') { + throw new DataRequestAbortError(); + } + + return null; + } + + if (corners.length === 0) { + return null; } - return geoField; + + return turfBboxToBounds(turf.bbox(turf.multiPoint(corners))); } canFormatFeatureProperties() { 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 450894d81485c..c043e6d6994ab 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 @@ -150,7 +150,7 @@ export class AbstractESSource extends AbstractVectorSource { searchSource.setField('aggs', { fitToBounds: { geo_bounds: { - field: this._descriptor.geoField, + field: this.getGeoFieldName(), }, }, }); @@ -230,12 +230,12 @@ export class AbstractESSource extends AbstractVectorSource { async _getGeoField() { const indexPattern = await this.getIndexPattern(); - const geoField = indexPattern.fields.getByName(this._descriptor.geoField); + const geoField = indexPattern.fields.getByName(this.getGeoFieldName()); if (!geoField) { throw new Error( i18n.translate('xpack.maps.source.esSource.noGeoFieldErrorMessage', { defaultMessage: `Index pattern {indexPatternTitle} no longer contains the geo field {geoField}`, - values: { indexPatternTitle: indexPattern.title, geoField: this._descriptor.geoField }, + values: { indexPatternTitle: indexPattern.title, geoField: this.getGeoFieldName() }, }) ); } diff --git a/x-pack/plugins/maps/public/elasticsearch_geo_utils.d.ts b/x-pack/plugins/maps/public/elasticsearch_geo_utils.d.ts index ad81b1980765d..964afb589187f 100644 --- a/x-pack/plugins/maps/public/elasticsearch_geo_utils.d.ts +++ b/x-pack/plugins/maps/public/elasticsearch_geo_utils.d.ts @@ -7,3 +7,5 @@ import { MapExtent } from '../common/descriptor_types'; export function scaleBounds(bounds: MapExtent, scaleFactor: number): MapExtent; + +export function turfBboxToBounds(turfBbox: unknown): MapExtent; diff --git a/x-pack/plugins/maps/public/elasticsearch_geo_utils.js b/x-pack/plugins/maps/public/elasticsearch_geo_utils.js index ba1477e4f8476..b32125e6eb614 100644 --- a/x-pack/plugins/maps/public/elasticsearch_geo_utils.js +++ b/x-pack/plugins/maps/public/elasticsearch_geo_utils.js @@ -480,3 +480,12 @@ export function scaleBounds(bounds, scaleFactor) { maxLat: bounds.maxLat + height * scaleFactor, }; } + +export function turfBboxToBounds(turfBbox) { + return { + minLon: turfBbox[0], + minLat: turfBbox[1], + maxLon: turfBbox[2], + maxLat: turfBbox[3], + }; +} diff --git a/x-pack/test/functional/apps/maps/es_pew_pew_source.js b/x-pack/test/functional/apps/maps/es_pew_pew_source.js index ec02dd2901c7d..382bde510170f 100644 --- a/x-pack/test/functional/apps/maps/es_pew_pew_source.js +++ b/x-pack/test/functional/apps/maps/es_pew_pew_source.js @@ -35,5 +35,14 @@ export default function ({ getPageObjects, getService }) { expect(features.length).to.equal(2); expect(features[0].geometry.type).to.equal('LineString'); }); + + it('should fit to bounds', async () => { + // Set view to other side of world so no matching results + await PageObjects.maps.setView(-70, 0, 6); + await PageObjects.maps.clickFitToBounds('connections'); + const { lat, lon } = await PageObjects.maps.getView(); + expect(Math.round(lat)).to.equal(41); + expect(Math.round(lon)).to.equal(-70); + }); }); }