Skip to content

Commit

Permalink
import
Browse files Browse the repository at this point in the history
reuse utility

re-enable dynamic styling

update tile

ts fixes
  • Loading branch information
thomasneirynck committed Aug 20, 2020
1 parent 6e2455f commit 38e3a54
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 65 deletions.
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: any[],
flattenHit: (geojsonProperties: GeoJsonProperties) => GeoJsonProperties,
geoFieldName: string,
geoFieldType: ES_GEO_FIELD_TYPE,
epochMillisFields: string[]
): FeatureCollection;
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/elasticsearch_geo_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export function hitsToGeoJson(hits, flattenHit, geoFieldName, geoFieldType, epoc
delete properties[geoFieldName];

//create new geojson Feature for every individual geojson geometry.
//todo: Consider using GeometryCollection instead.
for (let j = 0; j < tmpGeometriesAccumulator.length; j++) {
features.push({
type: 'Feature',
Expand Down
Binary file modified x-pack/plugins/maps/server/mvt/__tests__/pbf/0_0_0.pbf
Binary file not shown.
3 changes: 1 addition & 2 deletions x-pack/plugins/maps/server/mvt/__tests__/tile_searches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

// @ts-expect-error
const search000json = await import('./json/0_0_0_search.json'); // Prefer require() over setting the compiler options, which affect production modules as well
const search000json = require('./json/0_0_0_search.json'); // Prefer require() over setting the compiler options, which affect production modules as well

export const TILE_SEARCHES = {
'0.0.0': {
Expand Down
88 changes: 25 additions & 63 deletions x-pack/plugins/maps/server/mvt/get_tile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import geojsonvt from 'geojson-vt';
// @ts-expect-error
import vtpbf from 'vt-pbf';
import { Logger } from 'src/core/server';
import { Feature, FeatureCollection, GeoJsonProperties, Geometry, Polygon } from 'geojson';
import { Feature, FeatureCollection, GeoJsonProperties, Polygon } from 'geojson';
import {
ES_GEO_FIELD_TYPE,
FEATURE_ID_PROPERTY_NAME,
MVT_SOURCE_LAYER_NAME,
KBN_TOO_MANY_FEATURES_PROPERTY,
MVT_SOURCE_LAYER_NAME,
} from '../../common/constants';

import { hitsToGeoJson } from '../../common/elasticsearch_geo_utils';
import { flattenHit } from './util';

interface ESBounds {
top_left: {
lon: number;
Expand Down Expand Up @@ -116,70 +120,28 @@ export async function getTile({
// Perform actual search
result = await callElasticsearch('search', esSearchQuery);

// @ts-expect-error
const hitsFeatures: Array<Feature | null> = result.hits.hits.map(
(hit: any): Feature | null => {
let geomType:
| 'Point'
| 'MultiPoint'
| 'LineString'
| 'MultiLineString'
| 'Polygon'
| 'MultiPolygon';
const geometry = hit._source[geometryFieldName];
if (geometry.type === 'polygon' || geometry.type === 'Polygon') {
geomType = 'Polygon';
} else if (geometry.type === 'multipolygon' || geometry.type === 'MultiPolygon') {
geomType = 'MultiPolygon';
} else if (geometry.type === 'linestring' || geometry.type === 'LineString') {
geomType = 'LineString';
} else if (geometry.type === 'multilinestring' || geometry.type === 'MultiLineString') {
geomType = 'MultiLineString';
} else if (geometry.type === 'point' || geometry.type === 'Point') {
geomType = 'Point';
} else if (geometry.type === 'MultiPoint' || geometry.type === 'multipoint') {
geomType = 'MultiPoint';
} else {
return null;
}
const geometryGeoJson: Geometry = {
type: geomType,
coordinates: geometry.coordinates,
};

const firstFields: GeoJsonProperties = {};
if (hit.fields) {
const fields = hit.fields;
Object.keys(fields).forEach((key) => {
const value = fields[key];
if (Array.isArray(value)) {
firstFields[key] = value[0];
} else {
firstFields[key] = value;
}
});
}
// Todo: pass in epochMillies-fields
const featureCollection = hitsToGeoJson(
// @ts-expect-error
result.hits.hits,
(hit: GeoJsonProperties) => {
return flattenHit(geometryFieldName, hit);
},
geometryFieldName,
ES_GEO_FIELD_TYPE.GEO_SHAPE,
[]
);

const properties = {
...hit._source,
...firstFields,
_id: hit._id,
_index: hit._index,
[FEATURE_ID_PROPERTY_NAME]: hit._id,
[KBN_TOO_MANY_FEATURES_PROPERTY]: false,
};
delete properties[geometryFieldName];
resultFeatures = featureCollection.features;

return {
type: 'Feature',
id: hit._id,
geometry: geometryGeoJson,
properties,
};
// Correct system-fields.
for (let i = 0; i < resultFeatures.length; i++) {
const props = resultFeatures[i].properties;
if (props !== null) {
props[FEATURE_ID_PROPERTY_NAME] = resultFeatures[i].id;
props[KBN_TOO_MANY_FEATURES_PROPERTY] = false;
}
);

resultFeatures = hitsFeatures.filter((f) => !!f) as Feature[];
}
}
} catch (e) {
logger.warn(e.message);
Expand Down
67 changes: 67 additions & 0 deletions x-pack/plugins/maps/server/mvt/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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.
*/

// This implementation:
// - does not include meta-fields
// - does not validate the schema against the index-pattern (e.g. nested fields)
// In the context of .mvt this is sufficient:
// - only fields from the response are packed in the tile (more efficient)
// - query-dsl submitted from the client, which was generated by the IndexPattern
// todo: Ideally, this should adapt/reuse from https://github.com/elastic/kibana/blob/52b42a81faa9dd5c102b9fbb9a645748c3623121/src/plugins/data/common/index_patterns/index_patterns/flatten_hit.ts#L26
import { GeoJsonProperties } from 'geojson';

export function flattenHit(geometryField: string, hit: GeoJsonProperties): GeoJsonProperties {
const flat: GeoJsonProperties = {};
if (hit) {
flattenSource(flat, '', hit._source, geometryField);
if (hit.fields) {
flattenFields(flat, hit.fields);
}

// Attach meta fields
flat._index = hit._index;
flat._id = hit._id;
}
return flat;
}

function flattenSource(
accum: GeoJsonProperties,
path: string,
properties: GeoJsonProperties = {},
geometryField: string
): GeoJsonProperties {
accum = accum || {};
for (const key in properties) {
if (properties.hasOwnProperty(key)) {
const newKey = path ? path + '.' + key : key;
let value;
if (geometryField === newKey) {
value = properties[key]; // do not deep-copy the geometry
} else if (properties[key] !== null && typeof value === 'object' && !Array.isArray(value)) {
value = flattenSource(accum, newKey, properties[key], geometryField);
} else {
value = properties[key];
}
accum[newKey] = value;
}
}
return accum;
}

function flattenFields(accum: GeoJsonProperties = {}, fields: GeoJsonProperties[]) {
accum = accum || {};
for (const key in fields) {
if (fields.hasOwnProperty(key)) {
const value = fields[key];
if (Array.isArray(value)) {
accum[key] = value[0];
} else {
accum[key] = value;
}
}
}
}

0 comments on commit 38e3a54

Please sign in to comment.