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] Add mvt support for ES doc sources #75698

Merged
merged 57 commits into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
bd4f39b
mvt init
thomasneirynck Aug 14, 2020
4da768c
cleanup
thomasneirynck Aug 14, 2020
aae411f
typing
thomasneirynck Aug 14, 2020
a3fbf97
update snapshot
thomasneirynck Aug 14, 2020
828ce8a
Enable mvt only for geo_shape
thomasneirynck Aug 14, 2020
02e7688
fix ts
thomasneirynck Aug 17, 2020
058c116
Fix snapshot
thomasneirynck Aug 17, 2020
43efc7c
update functional tests
thomasneirynck Aug 17, 2020
4c238c7
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt
thomasneirynck Aug 17, 2020
76bdfcc
feedback
thomasneirynck Aug 17, 2020
2371e7b
fix snapshot
thomasneirynck Aug 18, 2020
9769159
disable client-side metadata retrieval
thomasneirynck Aug 18, 2020
3a5a642
fix typos
thomasneirynck Aug 18, 2020
aa3e6e1
take into account url-state
thomasneirynck Aug 18, 2020
318e2e8
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt
thomasneirynck Aug 18, 2020
d011799
add unit test
thomasneirynck Aug 18, 2020
4839327
add test stub
thomasneirynck Aug 18, 2020
d1cb30d
add functional test
thomasneirynck Aug 18, 2020
f611360
add getTile unit test boilerplate
thomasneirynck Aug 18, 2020
abe3188
fix import
thomasneirynck Aug 19, 2020
c73faef
exclude bbox-features from tooltips
thomasneirynck Aug 19, 2020
919024a
only include required fields
thomasneirynck Aug 19, 2020
0010eae
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt
thomasneirynck Aug 20, 2020
6e2455f
simplify test
thomasneirynck Aug 20, 2020
38e3a54
import
thomasneirynck Aug 20, 2020
4df20b4
wording feedback
thomasneirynck Aug 20, 2020
b140223
update snap
thomasneirynck Aug 21, 2020
f516140
add unit tests
thomasneirynck Aug 21, 2020
6520132
snapshot
thomasneirynck Aug 21, 2020
0255c8b
unit tests
thomasneirynck Aug 21, 2020
106dc57
unit test
thomasneirynck Aug 21, 2020
5e28973
ts fixes
thomasneirynck Aug 21, 2020
f6b61bb
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt_fix
thomasneirynck Aug 25, 2020
84dcb37
feedback
thomasneirynck Aug 25, 2020
dee9fc4
flip test-case default
thomasneirynck Aug 25, 2020
0d571f4
fix typing
thomasneirynck Aug 25, 2020
188a0d2
test feedback
thomasneirynck Aug 26, 2020
131701f
reuse
thomasneirynck Aug 26, 2020
dfa0fa5
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt_fix
thomasneirynck Aug 26, 2020
7eee020
make too many features optional
thomasneirynck Aug 26, 2020
410420f
rename for clarity
thomasneirynck Aug 26, 2020
4d4f22e
remove cruft
thomasneirynck Aug 26, 2020
93d0e93
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt_fix
thomasneirynck Aug 27, 2020
b5d6121
feedback
thomasneirynck Aug 27, 2020
3086da2
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt_fix
thomasneirynck Aug 27, 2020
7afd405
fix unit test
thomasneirynck Aug 27, 2020
5ad7b15
fix ts
thomasneirynck Aug 27, 2020
8d57d58
fix test
thomasneirynck Aug 27, 2020
03ee20c
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt_fix
thomasneirynck Aug 31, 2020
6430aaf
fix unit test
thomasneirynck Aug 31, 2020
11d8da4
fix functional
thomasneirynck Aug 31, 2020
3b6e6f0
eslint
thomasneirynck Aug 31, 2020
31c4963
Merge branch 'master' of github.com:elastic/kibana into maps/es_mvt_fix
thomasneirynck Sep 1, 2020
63671b2
type check
thomasneirynck Sep 1, 2020
b32edc5
add api test
thomasneirynck Sep 1, 2020
33f1626
eslint
thomasneirynck Sep 1, 2020
7742735
fix merge error
thomasneirynck Sep 1, 2020
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
2 changes: 2 additions & 0 deletions x-pack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@
"file-type": "^10.9.0",
"font-awesome": "4.7.0",
"fp-ts": "^2.3.1",
"geojson-vt": "^3.2.1",
"get-port": "^5.0.0",
"getos": "^3.1.0",
"git-url-parse": "11.1.2",
Expand Down Expand Up @@ -384,6 +385,7 @@
"ui-select": "0.19.8",
"uuid": "3.3.2",
"vscode-languageserver": "^5.2.1",
"vt-pbf": "^3.1.1",
"webpack": "^4.41.5",
"wellknown": "^0.5.0",
"xml2js": "^0.4.22",
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/maps/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ export const MAP_PATH = 'map';
export const GIS_API_PATH = `api/${APP_ID}`;
export const INDEX_SETTINGS_API_PATH = `${GIS_API_PATH}/indexSettings`;
export const FONTS_API_PATH = `${GIS_API_PATH}/fonts`;
export const API_ROOT_PATH = `/${GIS_API_PATH}`;

export const MVT_GETTILE_API_PATH = 'mvt/getTile';
export const MVT_SOURCE_LAYER_NAME = 'source_layer';
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__';

const MAP_BASE_URL = `/${MAPS_APP_PATH}/${MAP_PATH}`;
export function getNewMapPath() {
Expand Down Expand Up @@ -220,6 +226,7 @@ export enum SCALING_TYPES {
LIMIT = 'LIMIT',
CLUSTERS = 'CLUSTERS',
TOP_HITS = 'TOP_HITS',
MVT = 'MVT',
}

export const RGBA_0000 = 'rgba(0,0,0,0)';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export type MapFilters = {
refreshTimerLastTriggeredAt?: string;
timeFilters: TimeRange;
zoom: number;
geogridPrecision?: number;
};

type ESSearchSourceSyncMeta = {
Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/maps/common/elasticsearch_geo_utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { FeatureCollection, GeoJsonProperties } from 'geojson';
import { MapExtent } from './descriptor_types';
import { ES_GEO_FIELD_TYPE } from './constants';

export function scaleBounds(bounds: MapExtent, scaleFactor: number): MapExtent;

Expand All @@ -13,3 +15,11 @@ export function turfBboxToBounds(turfBbox: unknown): MapExtent;
export function clampToLatBounds(lat: number): number;

export function clampToLonBounds(lon: number): number;

export function hitsToGeoJson(
hits: Array<Record<string, unknown>>,
flattenHit: (elasticSearchHit: Record<string, unknown>) => GeoJsonProperties,
geoFieldName: string,
geoFieldType: ES_GEO_FIELD_TYPE,
epochMillisFields: string[]
): FeatureCollection;
8 changes: 8 additions & 0 deletions x-pack/plugins/maps/public/classes/fields/es_doc_field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@ import { IVectorSource } from '../sources/vector_source';

export class ESDocField extends AbstractField implements IField {
private readonly _source: IESSource;
private readonly _canReadFromGeoJson: boolean;

constructor({
fieldName,
source,
origin,
canReadFromGeoJson = true,
}: {
fieldName: string;
source: IESSource;
origin: FIELD_ORIGIN;
canReadFromGeoJson?: boolean;
}) {
super({ fieldName, origin });
this._source = source;
this._canReadFromGeoJson = canReadFromGeoJson;
}

canValueBeFormatted(): boolean {
Expand Down Expand Up @@ -60,6 +64,10 @@ export class ESDocField extends AbstractField implements IField {
return true;
}

canReadFromGeoJson(): boolean {
return this._canReadFromGeoJson;
}

async getOrdinalFieldMetaRequest(): Promise<unknown> {
const indexPatternField = await this._getIndexPatternField();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,41 @@ describe('syncData', () => {
sinon.assert.notCalled(syncContext2.stopLoading);
});

it('Should resync when changes to source params', async () => {
const layer1: TiledVectorLayer = createLayer({}, {});
const syncContext1 = new MockSyncContext({ dataFilters: {} });

await layer1.syncData(syncContext1);

const dataRequestDescriptor: DataRequestDescriptor = {
data: defaultConfig,
dataId: 'source',
};
const layer2: TiledVectorLayer = createLayer(
{
__dataRequests: [dataRequestDescriptor],
},
{ layerName: 'barfoo' }
);
const syncContext2 = new MockSyncContext({ dataFilters: {} });
await layer2.syncData(syncContext2);

// @ts-expect-error
sinon.assert.calledOnce(syncContext2.startLoading);
// @ts-expect-error
sinon.assert.calledOnce(syncContext2.stopLoading);

// @ts-expect-error
const call = syncContext2.stopLoading.getCall(0);
expect(call.args[2]).toEqual({ ...defaultConfig, layerName: 'barfoo' });
describe('Should resync when changes to source params: ', () => {
[
{ layerName: 'barfoo' },
{ urlTemplate: 'https://sub.example.com/{z}/{x}/{y}.pbf' },
{ minSourceZoom: 1 },
{ maxSourceZoom: 12 },
].forEach((changes) => {
it(`change in ${Object.keys(changes).join(',')}`, async () => {
const layer1: TiledVectorLayer = createLayer({}, {});
const syncContext1 = new MockSyncContext({ dataFilters: {} });

await layer1.syncData(syncContext1);

const dataRequestDescriptor: DataRequestDescriptor = {
data: defaultConfig,
dataId: 'source',
};
const layer2: TiledVectorLayer = createLayer(
{
__dataRequests: [dataRequestDescriptor],
},
changes
);
const syncContext2 = new MockSyncContext({ dataFilters: {} });
await layer2.syncData(syncContext2);

// @ts-expect-error
sinon.assert.calledOnce(syncContext2.startLoading);
// @ts-expect-error
sinon.assert.calledOnce(syncContext2.stopLoading);

// @ts-expect-error
const call = syncContext2.stopLoading.getCall(0);
expect(call.args[2]).toEqual({ ...defaultConfig, ...changes });
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,24 @@ export class TiledVectorLayer extends VectorLayer {
);
const prevDataRequest = this.getSourceDataRequest();

const templateWithMeta = await this._source.getUrlTemplateWithMeta(searchFilters);
if (prevDataRequest) {
const data: MVTSingleLayerVectorSourceConfig = prevDataRequest.getData() as MVTSingleLayerVectorSourceConfig;
const canSkipBecauseNoChanges =
data.layerName === this._source.getLayerName() &&
data.minSourceZoom === this._source.getMinZoom() &&
data.maxSourceZoom === this._source.getMaxZoom();

if (canSkipBecauseNoChanges) {
return null;
if (data) {
const canSkipBecauseNoChanges =
data.layerName === this._source.getLayerName() &&
data.minSourceZoom === this._source.getMinZoom() &&
data.maxSourceZoom === this._source.getMaxZoom() &&
data.urlTemplate === templateWithMeta.urlTemplate;

if (canSkipBecauseNoChanges) {
return null;
}
}
}

startLoading(SOURCE_DATA_REQUEST_ID, requestToken, searchFilters);
try {
const templateWithMeta = await this._source.getUrlTemplateWithMeta();
stopLoading(SOURCE_DATA_REQUEST_ID, requestToken, templateWithMeta, {});
} catch (error) {
onLoadError(SOURCE_DATA_REQUEST_ID, requestToken, error.message);
Expand Down Expand Up @@ -160,6 +163,11 @@ export class TiledVectorLayer extends VectorLayer {
return false;
}

if (!mbTileSource.tiles) {
// Expected source is not compatible, so remove.
return true;
}

const isSourceDifferent =
mbTileSource.tiles[0] !== tiledSourceMeta.urlTemplate ||
mbTileSource.minzoom !== tiledSourceMeta.minSourceZoom ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import {
SOURCE_BOUNDS_DATA_REQUEST_ID,
FEATURE_VISIBLE_PROPERTY_NAME,
EMPTY_FEATURE_COLLECTION,
KBN_TOO_MANY_FEATURES_PROPERTY,
LAYER_TYPE,
FIELD_ORIGIN,
LAYER_STYLE_TYPE,
KBN_TOO_MANY_FEATURES_IMAGE_ID,
} from '../../../../common/constants';
import _ from 'lodash';
import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property';
Expand Down Expand Up @@ -777,6 +779,8 @@ export class VectorLayer extends AbstractLayer {
const sourceId = this.getId();
const fillLayerId = this._getMbPolygonLayerId();
const lineLayerId = this._getMbLineLayerId();
const tooManyFeaturesLayerId = this._getMbTooManyFeaturesLayerId();

const hasJoins = this.hasJoins();
if (!mbMap.getLayer(fillLayerId)) {
const mbLayer = {
Expand All @@ -802,6 +806,30 @@ export class VectorLayer extends AbstractLayer {
}
mbMap.addLayer(mbLayer);
}
if (!mbMap.getLayer(tooManyFeaturesLayerId)) {
const mbLayer = {
id: tooManyFeaturesLayerId,
type: 'fill',
source: sourceId,
paint: {},
};
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());
}

this.getCurrentStyle().setMBPaintProperties({
alpha: this.getAlpha(),
mbMap,
Expand All @@ -822,6 +850,9 @@ export class VectorLayer extends AbstractLayer {
if (lineFilterExpr !== mbMap.getFilter(lineLayerId)) {
mbMap.setFilter(lineLayerId, lineFilterExpr);
}

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

_syncStylePropertiesWithMb(mbMap) {
Expand All @@ -836,6 +867,19 @@ export class VectorLayer extends AbstractLayer {
type: 'geojson',
data: EMPTY_FEATURE_COLLECTION,
});
} else if (mbSource.type !== 'geojson') {
thomasneirynck marked this conversation as resolved.
Show resolved Hide resolved
// Recreate source when existing source is not geojson. This can occur when layer changes from tile layer to vector layer.
this.getMbLayerIds().forEach((mbLayerId) => {
if (mbMap.getLayer(mbLayerId)) {
mbMap.removeLayer(mbLayerId);
}
});

mbMap.removeSource(this._getMbSourceId());
mbMap.addSource(this._getMbSourceId(), {
type: 'geojson',
data: EMPTY_FEATURE_COLLECTION,
});
}
}

Expand Down Expand Up @@ -865,13 +909,18 @@ export class VectorLayer extends AbstractLayer {
return this.makeMbLayerId('fill');
}

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

getMbLayerIds() {
return [
this._getMbPointLayerId(),
this._getMbTextLayerId(),
this._getMbSymbolLayerId(),
this._getMbLineLayerId(),
this._getMbPolygonLayerId(),
this._getMbTooManyFeaturesLayerId(),
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { MapExtent, MapFilters } from '../../../../common/descriptor_types';
import { MapExtent, VectorSourceRequestMeta } from '../../../../common/descriptor_types';

jest.mock('../../../kibana_services');

Expand All @@ -19,6 +19,7 @@ import { SearchSource } from '../../../../../../../src/plugins/data/public/searc

export class MockSearchSource {
setField = jest.fn();
setParent() {}
}

describe('ESGeoGridSource', () => {
Expand Down Expand Up @@ -104,6 +105,9 @@ describe('ESGeoGridSource', () => {
async create() {
return mockSearchSource as SearchSource;
},
createEmpty() {
return mockSearchSource as SearchSource;
},
},
};

Expand All @@ -120,16 +124,24 @@ describe('ESGeoGridSource', () => {
maxLat: 80,
};

const mapFilters: MapFilters = {
const mapFilters: VectorSourceRequestMeta = {
geogridPrecision: 4,
filters: [],
timeFilters: {
from: 'now',
to: '15m',
mode: 'relative',
},
// extent,
extent,
applyGlobalQuery: true,
fieldNames: [],
buffer: extent,
sourceQuery: {
query: '',
language: 'KQL',
queryLastTriggeredAt: '2019-04-25T20:53:22.331Z',
},
sourceMeta: null,
zoom: 0,
};

Expand Down
Loading