From 2fba041c930c419e8cfe4851840afdeffe3d123c Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 7 Jan 2021 11:10:20 -0700 Subject: [PATCH] [Maps] labels for polygons and lines (#86191) * [Maps] labels for polygons and lines * remove x-pack yarn.lock * add labels to choropleth map wizard * clean up comment * add mvt tile support * only add centroids if there may be lines or polygons * tslint * tslint * do not add centroid to too many features polygon * update get_tile expect statements * move turf dependencies from devDependencies to dependencies * update jest snapshot and functional test expects * fix functional test expect * another functional test expect update * functional test updates * expect * pew pew source expect updates * update joins expect * update mapbox style expects * update join visibility expects for geocentroids * update join visibility expects for geocentroids * another functional test expect update * review feedback * update yarn.lock * tslint Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- package.json | 14 +- x-pack/plugins/maps/common/constants.ts | 5 + .../maps/common/get_centroid_features.test.ts | 282 ++++++++++++ .../maps/common/get_centroid_features.ts | 88 ++++ .../create_choropleth_layer_descriptor.ts | 10 + .../tiled_vector_layer/tiled_vector_layer.tsx | 1 + .../layers/vector_layer/vector_layer.tsx | 47 ++ .../vector_style_editor.test.tsx.snap | 400 ++++++++++++++++++ .../vector/components/vector_style_editor.tsx | 6 + .../styles/vector/vector_style.test.js | 8 + .../classes/styles/vector/vector_style.tsx | 7 + .../classes/util/mb_filter_expressions.ts | 19 +- .../plugins/maps/server/mvt/get_tile.test.ts | 34 +- x-pack/plugins/maps/server/mvt/get_tile.ts | 2 + .../apps/maps/es_geo_grid_source.js | 28 +- .../functional/apps/maps/es_pew_pew_source.js | 2 +- x-pack/test/functional/apps/maps/joins.js | 26 +- .../functional/apps/maps/mapbox_styles.js | 3 + yarn.lock | 154 ++++++- 19 files changed, 1098 insertions(+), 38 deletions(-) create mode 100644 x-pack/plugins/maps/common/get_centroid_features.test.ts create mode 100644 x-pack/plugins/maps/common/get_centroid_features.ts diff --git a/package.json b/package.json index 56db7cbc38dc8..58495c49d295b 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,16 @@ "@loaders.gl/json": "^2.3.1", "@slack/webhook": "^5.0.0", "@storybook/addons": "^6.0.16", + "@turf/along": "6.0.1", + "@turf/area": "6.0.1", + "@turf/bbox": "6.0.1", + "@turf/bbox-polygon": "6.0.1", + "@turf/boolean-contains": "6.0.1", + "@turf/center-of-mass": "6.0.1", "@turf/circle": "6.0.1", + "@turf/distance": "6.0.1", + "@turf/helpers": "6.0.1", + "@turf/length": "^6.0.2", "JSONStream": "1.3.5", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.4.0", @@ -396,11 +405,6 @@ "@testing-library/react": "^11.0.4", "@testing-library/react-hooks": "^3.4.1", "@testing-library/user-event": "^12.1.6", - "@turf/bbox": "6.0.1", - "@turf/bbox-polygon": "6.0.1", - "@turf/boolean-contains": "6.0.1", - "@turf/distance": "6.0.1", - "@turf/helpers": "6.0.1", "@types/accept": "3.1.1", "@types/angular": "^1.6.56", "@types/angular-mocks": "^1.7.0", diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 6a7448ddc8448..b86d48bfccdab 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -43,8 +43,13 @@ export const API_ROOT_PATH = `/${GIS_API_PATH}`; export const MVT_GETTILE_API_PATH = 'mvt/getTile'; export const MVT_GETGRIDTILE_API_PATH = 'mvt/getGridTile'; export const MVT_SOURCE_LAYER_NAME = 'source_layer'; +// Identifies vector tile "too many features" feature. +// "too many features" feature is a box showing area that contains too many features for single ES search response export const KBN_TOO_MANY_FEATURES_PROPERTY = '__kbn_too_many_features__'; export const KBN_TOO_MANY_FEATURES_IMAGE_ID = '__kbn_too_many_features_image_id__'; +// Identifies centroid feature. +// Centroids are a single point for representing lines, multiLines, polygons, and multiPolygons +export const KBN_IS_CENTROID_FEATURE = '__kbn_is_centroid_feature__'; const MAP_BASE_URL = `/${MAPS_APP_PATH}/${MAP_PATH}`; export function getNewMapPath() { diff --git a/x-pack/plugins/maps/common/get_centroid_features.test.ts b/x-pack/plugins/maps/common/get_centroid_features.test.ts new file mode 100644 index 0000000000000..e7250203ac3b8 --- /dev/null +++ b/x-pack/plugins/maps/common/get_centroid_features.test.ts @@ -0,0 +1,282 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Feature, FeatureCollection } from 'geojson'; +import { getCentroidFeatures } from './get_centroid_features'; + +test('should not create centroid feature for point and multipoint', () => { + const pointFeature: Feature = { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [30, 10], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const multiPointFeature: Feature = { + type: 'Feature', + geometry: { + type: 'MultiPoint', + coordinates: [ + [10, 40], + [40, 30], + [20, 20], + [30, 10], + ], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [pointFeature, multiPointFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(0); +}); + +test('should not create centroid for too many features polygon', () => { + const polygonFeature: Feature = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [35, 10], + [45, 45], + [15, 40], + [10, 20], + [35, 10], + ], + ], + }, + properties: { + __kbn_too_many_features__: true, + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [polygonFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(0); +}); + +test('should create centroid feature for line (even number of points)', () => { + const lineFeature: Feature = { + type: 'Feature', + id: 'myfeature', + geometry: { + type: 'LineString', + coordinates: [ + [102.0, 0.0], + [103.0, 1.0], + [104.0, 0.0], + [105.0, 1.0], + ], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [lineFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(1); + expect(centroidFeatures[0]).toEqual({ + type: 'Feature', + id: 'myfeature', + geometry: { + type: 'Point', + coordinates: [103.50003808007737, 0.5000190382261022], + }, + properties: { + __kbn_is_centroid_feature__: true, + prop0: 'value0', + prop1: 0.0, + }, + }); +}); + +test('should create centroid feature for line (odd number of points)', () => { + const lineFeature: Feature = { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [ + [102.0, 0.0], + [103.0, 1.0], + [104.0, 0.0], + ], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [lineFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(1); + expect(centroidFeatures[0]).toEqual({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [103.0, 1.0], + }, + properties: { + __kbn_is_centroid_feature__: true, + prop0: 'value0', + prop1: 0.0, + }, + }); +}); + +test('should create centroid feature for multi line', () => { + const multiLineFeature: Feature = { + type: 'Feature', + geometry: { + type: 'MultiLineString', + coordinates: [ + [ + [10, 10], + [20, 20], + [10, 40], + ], + [ + [40, 40], + [30, 30], + [40, 20], + [30, 10], + ], + ], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [multiLineFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(1); + expect(centroidFeatures[0]).toEqual({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [35.56701982106548, 24.717594944805672], + }, + properties: { + __kbn_is_centroid_feature__: true, + prop0: 'value0', + prop1: 0.0, + }, + }); +}); + +test('should create centroid feature for polygon', () => { + const polygonFeature: Feature = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [35, 10], + [45, 45], + [15, 40], + [10, 20], + [35, 10], + ], + ], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [polygonFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(1); + expect(centroidFeatures[0]).toEqual({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [27.526881720430108, 28.70967741935484], + }, + properties: { + __kbn_is_centroid_feature__: true, + prop0: 'value0', + prop1: 0.0, + }, + }); +}); + +test('should create centroid feature for multi polygon', () => { + const multiPolygonFeature: Feature = { + type: 'Feature', + geometry: { + type: 'MultiPolygon', + coordinates: [ + [ + [ + [30, 20], + [45, 40], + [10, 40], + [30, 20], + ], + ], + [ + [ + [15, 5], + [40, 10], + [10, 20], + [5, 10], + [15, 5], + ], + ], + ], + }, + properties: { + prop0: 'value0', + prop1: 0.0, + }, + }; + const featureCollection: FeatureCollection = { + type: 'FeatureCollection', + features: [multiPolygonFeature], + }; + const centroidFeatures = getCentroidFeatures(featureCollection); + expect(centroidFeatures.length).toBe(1); + expect(centroidFeatures[0]).toEqual({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [28.333333333333332, 33.333333333333336], + }, + properties: { + __kbn_is_centroid_feature__: true, + prop0: 'value0', + prop1: 0.0, + }, + }); +}); diff --git a/x-pack/plugins/maps/common/get_centroid_features.ts b/x-pack/plugins/maps/common/get_centroid_features.ts new file mode 100644 index 0000000000000..9b49b1f7653dc --- /dev/null +++ b/x-pack/plugins/maps/common/get_centroid_features.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + Feature, + FeatureCollection, + Geometry, + LineString, + MultiLineString, + MultiPolygon, +} from 'geojson'; +import turfAlong from '@turf/along'; +import turfArea from '@turf/area'; +// @ts-expect-error +import turfCenterOfMass from '@turf/center-of-mass'; +import turfLength from '@turf/length'; +import { lineString, polygon } from '@turf/helpers'; +import { + GEO_JSON_TYPE, + KBN_IS_CENTROID_FEATURE, + KBN_TOO_MANY_FEATURES_PROPERTY, +} from './constants'; + +export function getCentroidFeatures(featureCollection: FeatureCollection): Feature[] { + const centroidFeatures = []; + for (let i = 0; i < featureCollection.features.length; i++) { + const feature = featureCollection.features[i]; + + // do not add centroid for kibana added features + if (feature.properties?.[KBN_TOO_MANY_FEATURES_PROPERTY]) { + continue; + } + + let centroidGeometry: Geometry | null = null; + if (feature.geometry.type === GEO_JSON_TYPE.LINE_STRING) { + centroidGeometry = getLineCentroid(feature); + } else if (feature.geometry.type === GEO_JSON_TYPE.MULTI_LINE_STRING) { + const coordinates = (feature.geometry as MultiLineString).coordinates; + let longestLine = coordinates[0]; + let longestLength = turfLength(lineString(longestLine)); + for (let j = 1; j < coordinates.length; j++) { + const nextLine = coordinates[j]; + const nextLength = turfLength(lineString(nextLine)); + if (nextLength > longestLength) { + longestLine = nextLine; + longestLength = nextLength; + } + } + centroidGeometry = getLineCentroid(lineString(longestLine) as Feature); + } else if (feature.geometry.type === GEO_JSON_TYPE.POLYGON) { + centroidGeometry = turfCenterOfMass(feature).geometry; + } else if (feature.geometry.type === GEO_JSON_TYPE.MULTI_POLYGON) { + const coordinates = (feature.geometry as MultiPolygon).coordinates; + let largestPolygon = coordinates[0]; + let largestArea = turfArea(polygon(largestPolygon)); + for (let j = 1; j < coordinates.length; j++) { + const nextPolygon = coordinates[j]; + const nextArea = turfArea(polygon(nextPolygon)); + if (nextArea > largestArea) { + largestPolygon = nextPolygon; + largestArea = nextArea; + } + } + centroidGeometry = turfCenterOfMass(polygon(largestPolygon)).geometry; + } + + if (centroidGeometry) { + centroidFeatures.push({ + type: 'Feature', + id: feature.id, + properties: { + ...feature.properties, + [KBN_IS_CENTROID_FEATURE]: true, + }, + geometry: centroidGeometry, + } as Feature); + } + } + return centroidFeatures; +} + +function getLineCentroid(feature: Feature): Geometry { + const length = turfLength(feature); + return turfAlong((feature as unknown) as LineString, length / 2).geometry!; +} diff --git a/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts index fa82b9dc3b542..63834d5685e78 100644 --- a/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts @@ -86,6 +86,16 @@ function createChoroplethLayerDescriptor({ color: '#3d3d3d', }, }, + [VECTOR_STYLES.LABEL_TEXT]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...defaultDynamicProperties[VECTOR_STYLES.LABEL_TEXT].options, + field: { + name: joinKey, + origin: FIELD_ORIGIN.JOIN, + }, + }, + }, }), }); } 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 95a452c7ce376..5f2771ea2ffed 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 @@ -147,6 +147,7 @@ export class TiledVectorLayer extends VectorLayer { this._setMbPointsProperties(mbMap, sourceMeta.layerName); this._setMbLinePolygonProperties(mbMap, sourceMeta.layerName); + this._setMbCentroidProperties(mbMap, sourceMeta.layerName); } _requiresPrevSourceCleanup(mbMap: MbMap): boolean { diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index add5a980258f3..f72d2c0e6ead9 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -12,6 +12,7 @@ import { EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AbstractLayer } from '../layer'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; +import { getCentroidFeatures } from '../../../../common/get_centroid_features'; import { FEATURE_ID_PROPERTY_NAME, SOURCE_DATA_REQUEST_ID, @@ -26,6 +27,7 @@ import { LAYER_STYLE_TYPE, KBN_TOO_MANY_FEATURES_IMAGE_ID, FieldFormatter, + VECTOR_SHAPE_TYPE, } from '../../../../common/constants'; import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property'; import { DataRequestAbortError } from '../../util/data_request'; @@ -37,6 +39,7 @@ import { import { assignFeatureIds } from '../../util/assign_feature_ids'; import { getFeatureCollectionBounds } from '../../util/get_feature_collection_bounds'; import { + getCentroidFilterExpression, getFillFilterExpression, getLineFilterExpression, getPointFilterExpression, @@ -519,6 +522,13 @@ export class VectorLayer extends AbstractLayer { } ); const layerFeatureCollection = assignFeatureIds(sourceFeatureCollection); + const supportedShapes = await source.getSupportedShapeTypes(); + if ( + supportedShapes.includes(VECTOR_SHAPE_TYPE.LINE) || + supportedShapes.includes(VECTOR_SHAPE_TYPE.POLYGON) + ) { + layerFeatureCollection.features.push(...getCentroidFeatures(layerFeatureCollection)); + } stopLoading(dataRequestId, requestToken, layerFeatureCollection, meta); return { refreshed: true, @@ -995,9 +1005,41 @@ export class VectorLayer extends AbstractLayer { mbMap.setLayerZoomRange(tooManyFeaturesLayerId, this.getMinZoom(), this.getMaxZoom()); } + _setMbCentroidProperties(mbMap: MbMap, mvtSourceLayer?: string) { + const centroidLayerId = this._getMbCentroidLayerId(); + const centroidLayer = mbMap.getLayer(centroidLayerId); + if (!centroidLayer) { + const mbLayer: MbLayer = { + id: centroidLayerId, + type: 'symbol', + source: this.getId(), + }; + if (mvtSourceLayer) { + mbLayer['source-layer'] = mvtSourceLayer; + } + mbMap.addLayer(mbLayer); + } + + const filterExpr = getCentroidFilterExpression(this.hasJoins()); + if (filterExpr !== mbMap.getFilter(centroidLayerId)) { + mbMap.setFilter(centroidLayerId, filterExpr); + } + + this.getCurrentStyle().setMBPropertiesForLabelText({ + alpha: this.getAlpha(), + mbMap, + textLayerId: centroidLayerId, + }); + + this.syncVisibilityWithMb(mbMap, centroidLayerId); + mbMap.setLayerZoomRange(centroidLayerId, this.getMinZoom(), this.getMaxZoom()); + } + _syncStylePropertiesWithMb(mbMap: MbMap) { this._setMbPointsProperties(mbMap); this._setMbLinePolygonProperties(mbMap); + // centroid layers added after polygon layers to ensure they are on top of polygon layers + this._setMbCentroidProperties(mbMap); } _syncSourceBindingWithMb(mbMap: MbMap) { @@ -1037,6 +1079,10 @@ export class VectorLayer extends AbstractLayer { return this.makeMbLayerId('text'); } + _getMbCentroidLayerId() { + return this.makeMbLayerId('centroid'); + } + _getMbSymbolLayerId() { return this.makeMbLayerId('symbol'); } @@ -1057,6 +1103,7 @@ export class VectorLayer extends AbstractLayer { return [ this._getMbPointLayerId(), this._getMbTextLayerId(), + this._getMbCentroidLayerId(), this._getMbSymbolLayerId(), this._getMbLineLayerId(), this._getMbPolygonLayerId(), diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap b/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap index 312f8e5d91ffa..be8c9b0750b94 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/__snapshots__/vector_style_editor.test.tsx.snap @@ -151,6 +151,221 @@ exports[`should render 1`] = ` } } /> + + + + + + + + + + + + + + + + + + + + + + { {this._renderLineWidth()} + + + {this._renderLabelProperties()} ); } @@ -481,6 +484,9 @@ export class VectorStyleEditor extends Component { {this._renderLineWidth()} + + + {this._renderLabelProperties()} ); } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js index 94090c8abfe4f..acbf2cc8e72ba 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js @@ -221,6 +221,14 @@ describe('pluckStyleMetaFromSourceDataRequest', () => { }, properties: {}, }, + { + geometry: { + type: 'Point', + }, + properties: { + __kbn_is_centroid_feature__: true, + }, + }, ], }, }); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 1c36961aae1b1..9bf4cafd66407 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -14,6 +14,7 @@ import { DEFAULT_ICON, FIELD_ORIGIN, GEO_JSON_TYPE, + KBN_IS_CENTROID_FEATURE, LAYER_STYLE_TYPE, SOURCE_FORMATTERS_DATA_REQUEST_ID, STYLE_TYPE, @@ -493,6 +494,12 @@ export class VectorStyle implements IVectorStyle { if (supportedFeatures.length > 1) { for (let i = 0; i < features.length; i++) { const feature = features[i]; + + // ignore centroid features as they are added for styling and not part of the real data set + if (feature.properties[KBN_IS_CENTROID_FEATURE]) { + continue; + } + if (!hasFeatureType[VECTOR_SHAPE_TYPE.POINT] && POINTS.includes(feature.geometry.type)) { hasFeatureType[VECTOR_SHAPE_TYPE.POINT] = true; } diff --git a/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts b/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts index 0da6f632eb4a8..5b82305cd84a1 100644 --- a/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts +++ b/x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts @@ -7,16 +7,19 @@ import { GEO_JSON_TYPE, FEATURE_VISIBLE_PROPERTY_NAME, + KBN_IS_CENTROID_FEATURE, KBN_TOO_MANY_FEATURES_PROPERTY, } from '../../../common/constants'; export const EXCLUDE_TOO_MANY_FEATURES_BOX = ['!=', ['get', KBN_TOO_MANY_FEATURES_PROPERTY], true]; +const EXCLUDE_CENTROID_FEATURES = ['!=', ['get', KBN_IS_CENTROID_FEATURE], true]; const VISIBILITY_FILTER_CLAUSE = ['all', ['==', ['get', FEATURE_VISIBLE_PROPERTY_NAME], true]]; -const TOO_MANY_FEATURES_FILTER = ['all', EXCLUDE_TOO_MANY_FEATURES_BOX]; +// Kibana features are features added by kibana that do not exist in real data +const EXCLUDE_KBN_FEATURES = ['all', EXCLUDE_TOO_MANY_FEATURES_BOX, EXCLUDE_CENTROID_FEATURES]; const CLOSED_SHAPE_MB_FILTER = [ - ...TOO_MANY_FEATURES_FILTER, + ...EXCLUDE_KBN_FEATURES, [ 'any', ['==', ['geometry-type'], GEO_JSON_TYPE.POLYGON], @@ -27,7 +30,7 @@ const CLOSED_SHAPE_MB_FILTER = [ const VISIBLE_CLOSED_SHAPE_MB_FILTER = [...VISIBILITY_FILTER_CLAUSE, CLOSED_SHAPE_MB_FILTER]; const ALL_SHAPE_MB_FILTER = [ - ...TOO_MANY_FEATURES_FILTER, + ...EXCLUDE_KBN_FEATURES, [ 'any', ['==', ['geometry-type'], GEO_JSON_TYPE.POLYGON], @@ -40,7 +43,7 @@ const ALL_SHAPE_MB_FILTER = [ const VISIBLE_ALL_SHAPE_MB_FILTER = [...VISIBILITY_FILTER_CLAUSE, ALL_SHAPE_MB_FILTER]; const POINT_MB_FILTER = [ - ...TOO_MANY_FEATURES_FILTER, + ...EXCLUDE_KBN_FEATURES, [ 'any', ['==', ['geometry-type'], GEO_JSON_TYPE.POINT], @@ -50,6 +53,10 @@ const POINT_MB_FILTER = [ const VISIBLE_POINT_MB_FILTER = [...VISIBILITY_FILTER_CLAUSE, POINT_MB_FILTER]; +const CENTROID_MB_FILTER = ['all', ['==', ['get', KBN_IS_CENTROID_FEATURE], true]]; + +const VISIBLE_CENTROID_MB_FILTER = [...VISIBILITY_FILTER_CLAUSE, CENTROID_MB_FILTER]; + export function getFillFilterExpression(hasJoins: boolean): unknown[] { return hasJoins ? VISIBLE_CLOSED_SHAPE_MB_FILTER : CLOSED_SHAPE_MB_FILTER; } @@ -61,3 +68,7 @@ export function getLineFilterExpression(hasJoins: boolean): unknown[] { export function getPointFilterExpression(hasJoins: boolean): unknown[] { return hasJoins ? VISIBLE_POINT_MB_FILTER : POINT_MB_FILTER; } + +export function getCentroidFilterExpression(hasJoins: boolean): unknown[] { + return hasJoins ? VISIBLE_CENTROID_MB_FILTER : CENTROID_MB_FILTER; +} diff --git a/x-pack/plugins/maps/server/mvt/get_tile.test.ts b/x-pack/plugins/maps/server/mvt/get_tile.test.ts index 3660039f2513c..634b898fdc18c 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.test.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.test.ts @@ -7,7 +7,12 @@ import { getGridTile, getTile } from './get_tile'; import { TILE_GRIDAGGS, TILE_SEARCHES } from './__tests__/tile_es_responses'; import { Logger } from 'src/core/server'; -import { ES_GEO_FIELD_TYPE, MVT_SOURCE_LAYER_NAME, RENDER_AS } from '../../common/constants'; +import { + ES_GEO_FIELD_TYPE, + KBN_IS_CENTROID_FEATURE, + MVT_SOURCE_LAYER_NAME, + RENDER_AS, +} from '../../common/constants'; // @ts-expect-error import { VectorTile, VectorTileLayer } from '@mapbox/vector-tile'; @@ -18,7 +23,6 @@ interface ITileLayerJsonExpectation { version: number; name: string; extent: number; - length: number; features: Array<{ id: string | number | undefined; type: number; @@ -75,7 +79,6 @@ describe('getTile', () => { version: 2, name: 'source_layer', extent: 4096, - length: 1, features: [ { id: undefined, @@ -97,6 +100,18 @@ describe('getTile', () => { ], ], }, + { + id: undefined, + type: 1, + properties: { + __kbn__feature_id__: 'poly:G7PRMXQBgyyZ-h5iYibj:0', + _id: 'G7PRMXQBgyyZ-h5iYibj', + _index: 'poly', + [KBN_IS_CENTROID_FEATURE]: true, + }, + extent: 4096, + pointArrays: [[{ x: 1470, y: 1702 }]], + }, ], }); }); @@ -166,7 +181,6 @@ describe('getGridTile', () => { version: 2, name: 'source_layer', extent: 4096, - length: 1, features: [ { id: undefined, @@ -189,7 +203,6 @@ describe('getGridTile', () => { version: 2, name: 'source_layer', extent: 4096, - length: 1, features: [ { id: undefined, @@ -209,6 +222,17 @@ describe('getGridTile', () => { ], ], }, + { + id: undefined, + type: 1, + properties: { + ['avg_of_TOTAL_AV']: 5398920.390458991, + doc_count: 42637, + [KBN_IS_CENTROID_FEATURE]: true, + }, + extent: 4096, + pointArrays: [[{ x: 1200, y: 1552 }]], + }, ], }); }); diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index cc87f3b65522e..ee45849042715 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -24,6 +24,7 @@ import { import { convertRegularRespToGeoJson, hitsToGeoJson } from '../../common/elasticsearch_util'; import { flattenHit } from './util'; import { ESBounds, tile2lat, tile2long, tileToESBbox } from '../../common/geo_tile_utils'; +import { getCentroidFeatures } from '../../common/get_centroid_features'; export async function getGridTile({ logger, @@ -270,6 +271,7 @@ function createMvtTile( x: number, y: number ): Buffer | null { + featureCollection.features.push(...getCentroidFeatures(featureCollection)); const tileIndex = geojsonvt(featureCollection, { maxZoom: 24, // max zoom to preserve detail on; can't be higher than 24 tolerance: 3, // simplification tolerance (higher means simpler) diff --git a/x-pack/test/functional/apps/maps/es_geo_grid_source.js b/x-pack/test/functional/apps/maps/es_geo_grid_source.js index 19680ae851a34..12af15793ff9a 100644 --- a/x-pack/test/functional/apps/maps/es_geo_grid_source.js +++ b/x-pack/test/functional/apps/maps/es_geo_grid_source.js @@ -13,8 +13,6 @@ export default function ({ getPageObjects, getService }) { const security = getService('security'); describe('layer geo grid aggregation source', () => { - const EXPECTED_NUMBER_FEATURES_ZOOMED_OUT = 4; - const EXPECTED_NUMBER_FEATURES_ZOOMED_IN = 6; const DATA_CENTER_LON = -98; const DATA_CENTER_LAT = 38; @@ -41,7 +39,11 @@ export default function ({ getPageObjects, getService }) { return requestTimestamp; } - function makeRequestTestsForGeoPrecision(LAYER_ID) { + function makeRequestTestsForGeoPrecision( + LAYER_ID, + expectedNumFeaturesZoomedOut, + expectedNumPartialFeatures + ) { describe('geoprecision - requests', () => { let beforeTimestamp; beforeEach(async () => { @@ -84,7 +86,7 @@ export default function ({ getPageObjects, getService }) { it('should request the data when the map covers the databounds', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal( - EXPECTED_NUMBER_FEATURES_ZOOMED_OUT + expectedNumFeaturesZoomedOut ); }); @@ -92,7 +94,9 @@ export default function ({ getPageObjects, getService }) { //todo this verifies the extent-filtering behavior (not really the correct application of geotile_grid-precision), and should ideally be moved to its own section await PageObjects.maps.setView(DATA_CENTER_LAT, DATA_CENTER_LON, 6); const mapboxStyle = await PageObjects.maps.getMapboxStyle(); - expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal(2); + expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal( + expectedNumPartialFeatures + ); }); }); } @@ -115,9 +119,7 @@ export default function ({ getPageObjects, getService }) { it('should decorate feature properties with scaled doc_count property', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); - expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal( - EXPECTED_NUMBER_FEATURES_ZOOMED_IN - ); + expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal(6); mapboxStyle.sources[LAYER_ID].data.features.forEach(({ properties }) => { expect(properties.hasOwnProperty(HEATMAP_PROP_NAME)).to.be(true); @@ -125,7 +127,7 @@ export default function ({ getPageObjects, getService }) { }); }); - makeRequestTestsForGeoPrecision(LAYER_ID); + makeRequestTestsForGeoPrecision(LAYER_ID, 4, 2); describe('query bar', () => { before(async () => { @@ -194,9 +196,7 @@ export default function ({ getPageObjects, getService }) { it('should decorate feature properties with metrics properterties', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); - expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal( - EXPECTED_NUMBER_FEATURES_ZOOMED_IN - ); + expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal(12); mapboxStyle.sources[LAYER_ID].data.features.forEach(({ properties }) => { expect(properties.hasOwnProperty(MAX_OF_BYTES_PROP_NAME)).to.be(true); @@ -204,7 +204,7 @@ export default function ({ getPageObjects, getService }) { }); }); - makeRequestTestsForGeoPrecision(LAYER_ID); + makeRequestTestsForGeoPrecision(LAYER_ID, 8, 4); describe('query bar', () => { before(async () => { @@ -262,7 +262,7 @@ export default function ({ getPageObjects, getService }) { const LAYER_ID = 'g1xkv'; it('should get expected number of grid cells', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); - expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal(13); + expect(mapboxStyle.sources[LAYER_ID].data.features.length).to.equal(26); }); describe('inspector', () => { 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 b0f98f807fd44..7c6ca3f516062 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 @@ -38,7 +38,7 @@ export default function ({ getPageObjects, getService }) { it('should render lines', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); const features = mapboxStyle.sources[VECTOR_SOURCE_ID].data.features; - expect(features.length).to.equal(2); + expect(features.length).to.equal(4); expect(features[0].geometry.type).to.equal('LineString'); }); diff --git a/x-pack/test/functional/apps/maps/joins.js b/x-pack/test/functional/apps/maps/joins.js index 9c769b8d9f59d..ff6686eef53ab 100644 --- a/x-pack/test/functional/apps/maps/joins.js +++ b/x-pack/test/functional/apps/maps/joins.js @@ -81,7 +81,7 @@ export default function ({ getPageObjects, getService }) { it('should decorate feature properties with join property', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); - expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(4); + expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(8); mapboxStyle.sources.n1t6f.data.features.forEach(({ properties }) => { if (properties.name === 'tango') { @@ -130,7 +130,17 @@ export default function ({ getPageObjects, getService }) { return feature.properties.__kbn_isvisibleduetojoin__; }); - expect(visibilitiesOfFeatures).to.eql([false, true, true, true]); + expect(visibilitiesOfFeatures).to.eql([ + false, + true, + true, + true, + // geo centroids for above features + false, + true, + true, + true, + ]); }); describe('query bar', () => { @@ -196,7 +206,17 @@ export default function ({ getPageObjects, getService }) { return feature.properties.__kbn_isvisibleduetojoin__; }); - expect(visibilitiesOfFeatures).to.eql([false, true, false, false]); + expect(visibilitiesOfFeatures).to.eql([ + false, + true, + false, + false, + // geo centroids for above features + false, + true, + false, + false, + ]); }); }); diff --git a/x-pack/test/functional/apps/maps/mapbox_styles.js b/x-pack/test/functional/apps/maps/mapbox_styles.js index 78720fa1689ec..ed94b2290af63 100644 --- a/x-pack/test/functional/apps/maps/mapbox_styles.js +++ b/x-pack/test/functional/apps/maps/mapbox_styles.js @@ -17,6 +17,7 @@ export const MAPBOX_STYLES = { [ 'all', ['!=', ['get', '__kbn_too_many_features__'], true], + ['!=', ['get', '__kbn_is_centroid_feature__'], true], ['any', ['==', ['geometry-type'], 'Point'], ['==', ['geometry-type'], 'MultiPoint']], ], ], @@ -91,6 +92,7 @@ export const MAPBOX_STYLES = { [ 'all', ['!=', ['get', '__kbn_too_many_features__'], true], + ['!=', ['get', '__kbn_is_centroid_feature__'], true], ['any', ['==', ['geometry-type'], 'Polygon'], ['==', ['geometry-type'], 'MultiPolygon']], ], ], @@ -161,6 +163,7 @@ export const MAPBOX_STYLES = { [ 'all', ['!=', ['get', '__kbn_too_many_features__'], true], + ['!=', ['get', '__kbn_is_centroid_feature__'], true], [ 'any', ['==', ['geometry-type'], 'Polygon'], diff --git a/yarn.lock b/yarn.lock index d7292dd5d17e7..585d6a1c81ca9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4381,6 +4381,25 @@ dependencies: "@babel/runtime" "^7.10.2" +"@turf/along@6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@turf/along/-/along-6.0.1.tgz#595cecdc48fc7fcfa83c940a8e3eb24d4c2e04d4" + integrity sha512-6PptAcrsFR3o0Flpktk8Vo68W2txEVTh14zjoTVu+H5docd2+pv5/upA77bg3YFBoJgAxmUFt1leDdjReJ44BQ== + dependencies: + "@turf/bearing" "6.x" + "@turf/destination" "6.x" + "@turf/distance" "6.x" + "@turf/helpers" "6.x" + "@turf/invariant" "6.x" + +"@turf/area@6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@turf/area/-/area-6.0.1.tgz#50ed63c70ef2bdb72952384f1594319d94f3b051" + integrity sha512-Zv+3N1ep9P5JvR0YOYagLANyapGWQBh8atdeR3bKpWcigVXFsEKNUw03U/5xnh+cKzm7yozHD6MFJkqQv55y0g== + dependencies: + "@turf/helpers" "6.x" + "@turf/meta" "6.x" + "@turf/bbox-polygon@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@turf/bbox-polygon/-/bbox-polygon-6.0.1.tgz#ae0fbb14558831fb34538aae089a23d3336c6379" @@ -4396,6 +4415,14 @@ "@turf/helpers" "6.x" "@turf/meta" "6.x" +"@turf/bearing@6.x": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@turf/bearing/-/bearing-6.0.1.tgz#8da5d17092e571f170cde7bfb2e5b0d74923c92d" + integrity sha512-mXY1NozqV9EFfBTbUItujwfqfQF0G/Xe2fzvnZle90ekPEUfhi4Dgf5JswJTd96J9LiT8kcd6Jonp5khnx0wIg== + dependencies: + "@turf/helpers" "6.x" + "@turf/invariant" "6.x" + "@turf/boolean-contains@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@turf/boolean-contains/-/boolean-contains-6.0.1.tgz#c3c583215fc5bda47ede51cf52d735ffdc1006a5" @@ -4423,6 +4450,25 @@ "@turf/helpers" "6.x" "@turf/invariant" "6.x" +"@turf/center-of-mass@6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@turf/center-of-mass/-/center-of-mass-6.0.1.tgz#be8904edfd6523683706429ea2f4adf5badd5b26" + integrity sha512-cY+RndzVzDBMlEShRmvLko0CSG1+iC+WdeMAtauCGL61e23LTYHxFSjVOOo4gF+aKqKia1veZPol8ENJoOU4ow== + dependencies: + "@turf/centroid" "6.x" + "@turf/convex" "6.x" + "@turf/helpers" "6.x" + "@turf/invariant" "6.x" + "@turf/meta" "6.x" + +"@turf/centroid@6.x": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@turf/centroid/-/centroid-6.0.2.tgz#c4eb16b4bc60b692f74e1809cf9a7c4a4f5ba1cc" + integrity sha512-auyDauOtC4eddH7GC3CHFTDu2PKhpSeKCRhwhHhXtJqn2dWCJQNIoCeJRmfXRIbzCWhWvgvQafvvhq8HNvmvWw== + dependencies: + "@turf/helpers" "6.x" + "@turf/meta" "6.x" + "@turf/circle@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@turf/circle/-/circle-6.0.1.tgz#0ab72083373ae3c76b700c17a504ab1b5c0910b9" @@ -4431,6 +4477,15 @@ "@turf/destination" "6.x" "@turf/helpers" "6.x" +"@turf/convex@6.x": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@turf/convex/-/convex-6.0.3.tgz#d7e9912b96483f1504cdd2f60b4b1bbdbf77416c" + integrity sha512-S9zvcKiqkIiQ/fhnEP5ftDrsVY3Sh0XeLDVZY761nlvuvzLVzz26Gq7H3NMsCJlmIcQS9jPARFBVpRZi6eTV8Q== + dependencies: + "@turf/helpers" "6.x" + "@turf/meta" "6.x" + concaveman "*" + "@turf/destination@6.x": version "6.0.1" resolved "https://registry.yarnpkg.com/@turf/destination/-/destination-6.0.1.tgz#5275887fa96ec463f44864a2c17f0b712361794a" @@ -4439,7 +4494,7 @@ "@turf/helpers" "6.x" "@turf/invariant" "6.x" -"@turf/distance@6.0.1": +"@turf/distance@6.0.1", "@turf/distance@6.x": version "6.0.1" resolved "https://registry.yarnpkg.com/@turf/distance/-/distance-6.0.1.tgz#0761f28784286e7865a427c4e7e3593569c2dea8" integrity sha512-q7t7rWIWfkg7MP1Vt4uLjSEhe5rPfCO2JjpKmk7JC+QZKEQkuvHEqy3ejW1iC7Kw5ZcZNR3qdMGGz+6HnVwqvg== @@ -4459,6 +4514,15 @@ dependencies: "@turf/helpers" "6.x" +"@turf/length@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@turf/length/-/length-6.0.2.tgz#22d91a6d0174e862a3614865613f1aceb1162dac" + integrity sha512-nyfXMowVtX2dICEG7u7EGC2SMaauVUWIMc9eWQrEauNA/9aw+7wbiuip4GPBoyeXEUUekF0EOjJn5aB9Zc8CzA== + dependencies: + "@turf/distance" "6.x" + "@turf/helpers" "6.x" + "@turf/meta" "6.x" + "@turf/meta@6.x": version "6.0.2" resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.0.2.tgz#eb92951126d24a613ac1b7b99d733fcc20fd30cf" @@ -10056,6 +10120,17 @@ concat-stream@~2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" +concaveman@*: + version "1.1.1" + resolved "https://registry.yarnpkg.com/concaveman/-/concaveman-1.1.1.tgz#6c2482580b2523cef82fc2bec00a0415e6e68162" + integrity sha1-bCSCWAslI874L8K+wAoEFebmgWI= + dependencies: + monotone-convex-hull-2d "^1.0.1" + point-in-polygon "^1.0.1" + rbush "^2.0.1" + robust-orientation "^1.1.3" + tinyqueue "^1.1.0" + config-chain@^1.1.12, config-chain@~1.1.8: version "1.1.12" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" @@ -11680,10 +11755,10 @@ detective@^5.0.2, detective@^5.2.0: defined "^1.0.0" minimist "^1.1.1" -devtools-protocol@0.0.818844: - version "0.0.818844" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e" - integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg== +devtools-protocol@0.0.809251: + version "0.0.809251" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.809251.tgz#300b3366be107d5c46114ecb85274173e3999518" + integrity sha512-pf+2OY6ghMDPjKkzSWxHMq+McD+9Ojmq5XVRYpv/kPd9sTMQxzEt21592a31API8qRjro0iYYOc3ag46qF/1FA== dezalgo@^1.0.0: version "1.0.3" @@ -20245,6 +20320,13 @@ monocle-ts@^1.0.0: resolved "https://registry.yarnpkg.com/monocle-ts/-/monocle-ts-1.7.1.tgz#03a615938aa90983a4fa29749969d30f72d80ba1" integrity sha512-X9OzpOyd/R83sYex8NYpJjUzi/MLQMvGNVfxDYiIvs+QMXMEUDwR61MQoARFN10Cqz5h/mbFSPnIQNUIGhYd2Q== +monotone-convex-hull-2d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/monotone-convex-hull-2d/-/monotone-convex-hull-2d-1.0.1.tgz#47f5daeadf3c4afd37764baa1aa8787a40eee08c" + integrity sha1-R/Xa6t88Sv03dkuqGqh4ekDu4Iw= + dependencies: + robust-orientation "^1.1.3" + moo@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e" @@ -22215,6 +22297,11 @@ pnp-webpack-plugin@1.6.4: dependencies: ts-pnp "^1.1.6" +point-in-polygon@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/point-in-polygon/-/point-in-polygon-1.0.1.tgz#d59b64e8fee41c49458aac82b56718c5957b2af7" + integrity sha1-1Ztk6P7kHElFiqyCtWcYxZV7Kvc= + polished@^1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/polished/-/polished-1.9.2.tgz#d705cac66f3a3ed1bd38aad863e2c1e269baf6b6" @@ -22720,7 +22807,7 @@ puppeteer@^2.0.0: integrity sha512-I4JbNmQHZkE72TPNdipND8GnsEBnqzuksxPSAT25qvudShuuzdY9TwNBQ65IJwPD/pjlpx7fUIUmFyvTHwlxhQ== dependencies: debug "^4.1.0" - devtools-protocol "0.0.818844" + devtools-protocol "0.0.809251" extract-zip "^2.0.0" https-proxy-agent "^4.0.0" node-fetch "^2.6.1" @@ -22796,6 +22883,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +quickselect@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-1.1.1.tgz#852e412ce418f237ad5b660d70cffac647ae94c2" + integrity sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ== + quickselect@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" @@ -22906,6 +22998,13 @@ raw-loader@^4.0.1: loader-utils "^2.0.0" schema-utils "^2.6.5" +rbush@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/rbush/-/rbush-2.0.2.tgz#bb6005c2731b7ba1d5a9a035772927d16a614605" + integrity sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA== + dependencies: + quickselect "^1.0.1" + rbush@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf" @@ -24756,6 +24855,34 @@ rison-node@1.0.2: resolved "https://registry.yarnpkg.com/rison-node/-/rison-node-1.0.2.tgz#b7b5f37f39f5ae2a51a973a33c9aa17239a33e4b" integrity sha1-t7Xzfzn1ripRqXOjPJqhcjmjPks= +robust-orientation@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/robust-orientation/-/robust-orientation-1.1.3.tgz#daff5b00d3be4e60722f0e9c0156ef967f1c2049" + integrity sha1-2v9bANO+TmByLw6cAVbvln8cIEk= + dependencies: + robust-scale "^1.0.2" + robust-subtract "^1.0.0" + robust-sum "^1.0.0" + two-product "^1.0.2" + +robust-scale@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/robust-scale/-/robust-scale-1.0.2.tgz#775132ed09542d028e58b2cc79c06290bcf78c32" + integrity sha1-d1Ey7QlULQKOWLLMecBikLz3jDI= + dependencies: + two-product "^1.0.2" + two-sum "^1.0.0" + +robust-subtract@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/robust-subtract/-/robust-subtract-1.0.0.tgz#e0b164e1ed8ba4e3a5dda45a12038348dbed3e9a" + integrity sha1-4LFk4e2LpOOl3aRaEgODSNvtPpo= + +robust-sum@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/robust-sum/-/robust-sum-1.0.0.tgz#16646e525292b4d25d82757a286955e0bbfa53d9" + integrity sha1-FmRuUlKStNJdgnV6KGlV4Lv6U9k= + rollup@^0.25.8: version "0.25.8" resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.25.8.tgz#bf6ce83b87510d163446eeaa577ed6a6fc5835e0" @@ -27084,6 +27211,11 @@ tinymath@1.2.1: resolved "https://registry.yarnpkg.com/tinymath/-/tinymath-1.2.1.tgz#f97ed66c588cdbf3c19dfba2ae266ee323db7e47" integrity sha512-8CYutfuHR3ywAJus/3JUhaJogZap1mrUQGzNxdBiQDhP3H0uFdQenvaXvqI8lMehX4RsanRZzxVfjMBREFdQaA== +tinyqueue@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-1.2.3.tgz#b6a61de23060584da29f82362e45df1ec7353f3d" + integrity sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA== + tinyqueue@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08" @@ -27484,6 +27616,16 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +two-product@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/two-product/-/two-product-1.0.2.tgz#67d95d4b257a921e2cb4bd7af9511f9088522eaa" + integrity sha1-Z9ldSyV6kh4stL16+VEfkIhSLqo= + +two-sum@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/two-sum/-/two-sum-1.0.0.tgz#31d3f32239e4f731eca9df9155e2b297f008ab64" + integrity sha1-MdPzIjnk9zHsqd+RVeKyl/AIq2Q= + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"