Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] show incomplete data boundary when MVT tile does not contain all features #90194

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions x-pack/plugins/maps/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ 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 "incomplete data" feature.
// "incomplete data" feature is a box showing an area where incomplete data is displayed
export const KBN_IS_INCOMPLETE_DATA_FEATURE = '__kbn_is_incomplete_data_feature__';
// 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__';
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/common/get_centroid_features.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ test('should not create centroid for too many features polygon', () => {
],
},
properties: {
__kbn_too_many_features__: true,
__kbn_is_incomplete_data_feature__: true,
prop0: 'value0',
prop1: 0.0,
},
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/maps/common/get_centroid_features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { lineString, polygon } from '@turf/helpers';
import {
GEO_JSON_TYPE,
KBN_IS_CENTROID_FEATURE,
KBN_TOO_MANY_FEATURES_PROPERTY,
KBN_IS_INCOMPLETE_DATA_FEATURE,
} from './constants';

export function getCentroidFeatures(featureCollection: FeatureCollection): Feature[] {
Expand All @@ -31,7 +31,7 @@ export function getCentroidFeatures(featureCollection: FeatureCollection): Featu
const feature = featureCollection.features[i];

// do not add centroid for kibana added features
if (feature.properties?.[KBN_TOO_MANY_FEATURES_PROPERTY]) {
if (feature.properties?.[KBN_IS_INCOMPLETE_DATA_FEATURE]) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ import {
SOURCE_BOUNDS_DATA_REQUEST_ID,
FEATURE_VISIBLE_PROPERTY_NAME,
EMPTY_FEATURE_COLLECTION,
KBN_TOO_MANY_FEATURES_PROPERTY,
KBN_IS_INCOMPLETE_DATA_FEATURE,
LAYER_TYPE,
FIELD_ORIGIN,
LAYER_STYLE_TYPE,
KBN_TOO_MANY_FEATURES_IMAGE_ID,
FieldFormatter,
VECTOR_SHAPE_TYPE,
} from '../../../../common/constants';
Expand Down Expand Up @@ -937,7 +936,7 @@ export class VectorLayer extends AbstractLayer {
const sourceId = this.getId();
const fillLayerId = this._getMbPolygonLayerId();
const lineLayerId = this._getMbLineLayerId();
const tooManyFeaturesLayerId = this._getMbTooManyFeaturesLayerId();
const incompleteDataLayerId = this._getMbIncompleteDataLayerId();

const hasJoins = this.hasJoins();
if (!mbMap.getLayer(fillLayerId)) {
Expand All @@ -964,29 +963,25 @@ export class VectorLayer extends AbstractLayer {
}
mbMap.addLayer(mbLayer);
}
if (!mbMap.getLayer(tooManyFeaturesLayerId)) {
if (!mbMap.getLayer(incompleteDataLayerId)) {
const mbLayer: MbLayer = {
id: tooManyFeaturesLayerId,
type: 'fill',
id: incompleteDataLayerId,
type: 'line',
source: sourceId,
paint: {},
paint: {
'line-color': 'red',
'line-width': 4,
'line-dasharray': [2, 1],
},
};
if (mvtSourceLayer) {
mbLayer['source-layer'] = mvtSourceLayer;
}
mbMap.addLayer(mbLayer);
mbMap.setFilter(tooManyFeaturesLayerId, [
'==',
['get', KBN_TOO_MANY_FEATURES_PROPERTY],
true,
]);
mbMap.setPaintProperty(
tooManyFeaturesLayerId,
'fill-pattern',
KBN_TOO_MANY_FEATURES_IMAGE_ID
);
mbMap.setPaintProperty(tooManyFeaturesLayerId, 'fill-opacity', this.getAlpha());
mbMap.setFilter(incompleteDataLayerId, ['==', ['get', KBN_IS_INCOMPLETE_DATA_FEATURE], true]);
mbMap.setLayoutProperty(incompleteDataLayerId, 'line-join', 'bevel');
}
mbMap.setPaintProperty(incompleteDataLayerId, 'line-opacity', this.getAlpha() * 0.6);

this.getCurrentStyle().setMBPaintProperties({
alpha: this.getAlpha(),
Expand All @@ -1009,8 +1004,8 @@ export class VectorLayer extends AbstractLayer {
mbMap.setFilter(lineLayerId, lineFilterExpr);
}

this.syncVisibilityWithMb(mbMap, tooManyFeaturesLayerId);
mbMap.setLayerZoomRange(tooManyFeaturesLayerId, this.getMinZoom(), this.getMaxZoom());
this.syncVisibilityWithMb(mbMap, incompleteDataLayerId);
mbMap.setLayerZoomRange(incompleteDataLayerId, this.getMinZoom(), this.getMaxZoom());
}

_setMbCentroidProperties(mbMap: MbMap, mvtSourceLayer?: string) {
Expand Down Expand Up @@ -1103,8 +1098,8 @@ export class VectorLayer extends AbstractLayer {
return this.makeMbLayerId('fill');
}

_getMbTooManyFeaturesLayerId() {
return this.makeMbLayerId('toomanyfeatures');
_getMbIncompleteDataLayerId() {
return this.makeMbLayerId('kbn_incomplete_data_features');
}

getMbLayerIds() {
Expand All @@ -1115,7 +1110,7 @@ export class VectorLayer extends AbstractLayer {
this._getMbSymbolLayerId(),
this._getMbLineLayerId(),
this._getMbPolygonLayerId(),
this._getMbTooManyFeaturesLayerId(),
this._getMbIncompleteDataLayerId(),
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('ESGeoGridSource', () => {
expect(urlTemplateWithMeta.minSourceZoom).toBe(0);
expect(urlTemplateWithMeta.maxSourceZoom).toBe(24);
expect(urlTemplateWithMeta.urlTemplate).toBe(
"rootdir/api/maps/mvt/getGridTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!((geo_bounding_box:(bar:(bottom_right:!(180,-82.67628),top_left:!(-180,82.67628)))))),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point"
"rootdir/api/maps/mvt/getGridTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!((geo_bounding_box:(bar:(bottom_right:!(180,-82.67628),top_left:!(-180,82.67628)))))),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap"
);
});

Expand All @@ -288,7 +288,7 @@ describe('ESGeoGridSource', () => {
});

expect(urlTemplateWithMeta.urlTemplate).toBe(
"rootdir/api/maps/mvt/getGridTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!((geo_bounding_box:(bar:(bottom_right:!(180,-82.67628),top_left:!(-180,82.67628)))))),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point&searchSessionId=1"
"rootdir/api/maps/mvt/getGridTile;?x={x}&y={y}&z={z}&geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!((geo_bounding_box:(bar:(bottom_right:!(180,-82.67628),top_left:!(-180,82.67628)))))),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&searchSessionId=1"
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,16 +443,14 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle
`/${GIS_API_PATH}/${MVT_GETGRIDTILE_API_PATH}`
);

const geoField = await this._getGeoField();
const urlTemplate = `${mvtUrlServicePath}\
?x={x}\
&y={y}\
&z={z}\
&geometryFieldName=${this._descriptor.geoField}\
&index=${indexPattern.title}\
&requestBody=${risonDsl}\
&requestType=${this._descriptor.requestType}\
&geoFieldType=${geoField.type}`;
&requestType=${this._descriptor.requestType}`;
return {
layerName: this.getLayerName(),
minSourceZoom: this.getMinZoom(),
Expand Down
10 changes: 7 additions & 3 deletions x-pack/plugins/maps/public/classes/util/mb_filter_expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import {
GEO_JSON_TYPE,
FEATURE_VISIBLE_PROPERTY_NAME,
KBN_IS_CENTROID_FEATURE,
KBN_TOO_MANY_FEATURES_PROPERTY,
KBN_IS_INCOMPLETE_DATA_FEATURE,
} from '../../../common/constants';

export const EXCLUDE_TOO_MANY_FEATURES_BOX = ['!=', ['get', KBN_TOO_MANY_FEATURES_PROPERTY], true];
export const EXCLUDE_INCOMPLETE_DATA_FEATURES = [
'!=',
['get', KBN_IS_INCOMPLETE_DATA_FEATURE],
true,
];
const EXCLUDE_CENTROID_FEATURES = ['!=', ['get', KBN_IS_CENTROID_FEATURE], true];

const VISIBILITY_FILTER_CLAUSE = ['all', ['==', ['get', FEATURE_VISIBLE_PROPERTY_NAME], true]];
// 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 EXCLUDE_KBN_FEATURES = ['all', EXCLUDE_INCOMPLETE_DATA_FEATURES, EXCLUDE_CENTROID_FEATURES];

const CLOSED_SHAPE_MB_FILTER = [
...EXCLUDE_KBN_FEATURES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,7 @@ import { getPreserveDrawingBuffer } from '../../kibana_services';
import { ILayer } from '../../classes/layers/layer';
import { MapSettings } from '../../reducers/map';
import { Goto } from '../../../common/descriptor_types';
import {
DECIMAL_DEGREES_PRECISION,
KBN_TOO_MANY_FEATURES_IMAGE_ID,
RawValue,
ZOOM_PRECISION,
} from '../../../common/constants';
import { DECIMAL_DEGREES_PRECISION, RawValue, ZOOM_PRECISION } from '../../../common/constants';
import { getGlyphUrl, isRetina } from '../../meta';
import { syncLayerOrder } from './sort_layers';
// @ts-expect-error
Expand Down Expand Up @@ -201,14 +196,6 @@ export class MBMap extends Component<Props, State> {
mbMap.addControl(new mapboxgl.NavigationControl({ showCompass: false }), 'top-left');
}

const tooManyFeaturesImageSrc =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAA7DgAAOw4BzLahgwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAARLSURBVHic7ZnPbxRVAMe/7735sWO3293ZlUItJsivCxEE0oTYRgu1FqTQoFSwKTYx8SAH/wHjj4vRozGGi56sMcW2UfqTEuOhppE0KJc2GIuKQFDY7qzdtrudX88D3YTUdFuQN8+k87ltZt7uZz958/bNLAGwBWsYKltANmEA2QKyCQPIFpBNGEC2gGzCALIFZBMGkC0gmzCAbAHZhAFkC8gmDCBbQDZhANkCslnzARQZH6oDpNs0D5UDSUIInePcOpPLfdfnODNBuwQWIAWwNOABwHZN0x8npE6hNLJ4DPWRyFSf40wE5VOEQPBjcR0g3YlE4ybGmtK+/1NzJtOZA/xSYwZMs3nG962T2ez3It2AANaA/kSidYuivOQBs5WM1fUnk6f0u+GXJUqIuUtVXx00zRbRfkIDfBqL7a1WlIYbjvNtTTr99jXXHVpH6dMjK0R4cXq6c9rzxjcx9sKX8XitSEdhAToMI7VP10/97fsTh7PZrgWAN1lW72KE2vOm2b5chDTgtWQyn93x/bEEIetEOQIC14CxVOr1CkKefH929t0v8vn0vcdGEoljGxXl4C3PGz2YyXy+AHARDqtByAxoUdWKBKV70r4/vvTLA0CjZfX+5nkDGxirKzUTgkBIgNaysh3gnF627R+XO+dQJvP1ddcdrmSsbtA020pF+CAW21qrqmUiXIUEqGRsIwD0FQq/lzqv0bJ6rrvucBVjzwyb5ivLRTiiaW+8VV7eIEBVTAANiIIQd9RxZlc6t9Gyem647vn1jD07ZJonl4sQASoevqmgABzwwHnJzc69PGdZ3X+47sgGxuqHTPPE0ggeVtg5/QeEBMhxPg1Aa1DV2GrHPG9ZXy1G2D+wNALn9jyQEeHKAJgP+033Kgrdqij7AFwZtu3bqx3XWShMHtV1o1pRGo4YxiNd+fyEB2DKdX/4aG5u0hbwcylkBryTy/3scT6zW9Nq7ndso2Wdvea6Q1WUHuiPx1/WAXLBcWZXun94UMRcAoD/p+ddTFK6u8MwUvc7vsmyem+67oVqVT0wkEgcF+FYRNhW+L25uX6f84XThtHxIBudE5bVY/t++jFVrU/dvVSFICzAqG3PX/S8rihj2/61qK1AOUB7ksl2jdLUL7Z9rvgcQQRCFsEi5wqFmw26XnhCUQ63GcZmCly95Lrzpca0G0byk3j8tEnpU1c975tmyxoU5QcE8EAEAM5WVOzfoarHAeC2749dcpzxMwsLv07Ztg0AOzVNf03Ttu/S9T2PMlbjc25fdpyutmx2TLRbIAEA4M1otKo1EjmaoHQn4ZwBgA/kAVAK6MXXdzxv/ONcrq/HcbJBeAUWoEizqsaORaPbKglZrxMSZZyrM76f/ovzWx/m85PFWREUgQf4v7Hm/xcIA8gWkE0YQLaAbMIAsgVkEwaQLSCbMIBsAdmEAWQLyCYMIFtANmEA2QKyCQPIFpDNmg/wD3OFdEybUvJjAAAAAElFTkSuQmCC';
const tooManyFeaturesImage = new Image();
tooManyFeaturesImage.onload = () => {
mbMap.addImage(KBN_TOO_MANY_FEATURES_IMAGE_ID, tooManyFeaturesImage);
};
tooManyFeaturesImage.src = tooManyFeaturesImageSrc;

let emptyImage: HTMLImageElement;
mbMap.on('styleimagemissing', (e: unknown) => {
if (emptyImage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import _ from 'lodash';
import React from 'react';
import { FEATURE_ID_PROPERTY_NAME, LON_INDEX } from '../../../../common/constants';
import { TooltipPopover } from './tooltip_popover';
import { EXCLUDE_TOO_MANY_FEATURES_BOX } from '../../../classes/util/mb_filter_expressions';
import { EXCLUDE_INCOMPLETE_DATA_FEATURES } from '../../../classes/util/mb_filter_expressions';

function justifyAnchorLocation(mbLngLat, targetFeature) {
let popupAnchorLocation = [mbLngLat.lng, mbLngLat.lat]; // default popup location to mouse location
Expand Down Expand Up @@ -179,7 +179,7 @@ export class TooltipControl extends React.Component {
];
return this.props.mbMap.queryRenderedFeatures(mbBbox, {
layers: mbLayerIds,
filter: EXCLUDE_TOO_MANY_FEATURES_BOX,
filter: EXCLUDE_INCOMPLETE_DATA_FEATURES,
});
}

Expand Down
Loading