[Maps] add WKT and geohash string support (#34472)

This commit is contained in:
Thomas Neirynck 2019-05-15 14:31:53 -04:00 committed by GitHub
parent 2791becd27
commit 3a3bcfb498
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 35 deletions

View file

@ -334,6 +334,7 @@
"vscode-jsonrpc": "^3.6.2",
"vscode-languageserver": "^4.2.1",
"vscode-languageserver-types": "^3.10.0",
"wellknown": "^0.5.0",
"xml2js": "^0.4.19",
"xregexp": "3.2.0"
},

View file

@ -6,6 +6,8 @@
import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import { parse } from 'wellknown';
import { decodeGeoHash } from 'ui/utils/decode_geo_hash';
import { DECIMAL_DEGREES_PRECISION, ES_GEO_FIELD_TYPE } from '../common/constants';
/**
@ -69,23 +71,22 @@ export function geoPointToGeometry(value, accumulator) {
}
if (typeof value === 'string') {
const commaSplit = value.split(',');
if (commaSplit.length === 1) {
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.geohashIsUnsupportedErrorMessage', {
defaultMessage: `Unable to convert to geojson, geohash not supported`
});
throw new Error(errorMessage);
const commaSplit = value.split(',');
let point;
if (commaSplit.length === 1) {
const geohash = decodeGeoHash(value);
point = pointGeometryFactory(geohash.latitude[2], geohash.longitude[2]);
} else {
const lat = parseFloat(commaSplit[0]);
const lon = parseFloat(commaSplit[1]);
point = pointGeometryFactory(lat, lon);
}
// Geo-point expressed as a string with the format: "lat,lon".
const lat = parseFloat(commaSplit[0]);
const lon = parseFloat(commaSplit[1]);
accumulator.push(pointGeometryFactory(lat, lon));
accumulator.push(point);
return;
}
if (typeof value === 'object' && _.has(value, 'lat') && _.has(value, 'lon')) {
// Geo-point expressed as an object with the format: { lon, lat }
accumulator.push(pointGeometryFactory(value.lat, value.lon));
return;
}
@ -103,7 +104,6 @@ export function geoPointToGeometry(value, accumulator) {
if (value.length === 2
&& typeof value[0] === 'number'
&& typeof value[1] === 'number') {
// Geo-point expressed as an array with the format: [lon, lat]
const lat = value[1];
const lon = value[0];
accumulator.push(pointGeometryFactory(lat, lon));
@ -116,26 +116,7 @@ export function geoPointToGeometry(value, accumulator) {
}
}
export function geoShapeToGeometry(value, accumulator) {
if (!value) {
return;
}
if (Array.isArray(value)) {
// value expressed as an array of values
for (let i = 0; i < value.length; i++) {
geoShapeToGeometry(value[i], accumulator);
}
return;
}
// TODO handle case where value is WKT and convert to geojson
if (typeof value === 'string') {
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.wktIsUnsupportedErrorMessage', {
defaultMessage: `Unable to convert WKT to geojson, not supported`,
});
throw new Error(errorMessage);
}
export function convertESShapeToGeojsonGeometry(value) {
const geoJson = {
type: value.type,
@ -172,8 +153,51 @@ export function geoShapeToGeometry(value, accumulator) {
break;
case 'envelope':
case 'circle':
// TODO handle envelope and circle geometry types which exist in elasticsearch but not in geojson
throw new Error(`Unable to convert ${geoJson.type} geometry to geojson, not supported`);
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.convert.unsupportedGeometryTypeErrorMessage', {
defaultMessage: `Unable to convert {geometryType} geometry to geojson, not supported`,
values: {
geometryType: geoJson.type
}
});
throw new Error(errorMessage);
}
return geoJson;
}
function convertWKTStringToGeojson(value) {
try {
return parse(value);
} catch (e) {
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.wkt.invalidWKTErrorMessage', {
defaultMessage: `Unable to convert {wkt} to geojson. Valid WKT expected.`,
values: {
wkt: value
}
});
throw new Error(errorMessage);
}
}
export function geoShapeToGeometry(value, accumulator) {
if (!value) {
return;
}
if (Array.isArray(value)) {
// value expressed as an array of values
for (let i = 0; i < value.length; i++) {
geoShapeToGeometry(value[i], accumulator);
}
return;
}
let geoJson;
if (typeof value === 'string') {
geoJson = convertWKTStringToGeojson(value);
} else {
geoJson = convertESShapeToGeojsonGeometry(value);
}
accumulator.push(geoJson);

View file

@ -59,6 +59,7 @@ describe('hitsToGeoJson', () => {
});
});
it('Should handle documents where geoField is not populated', () => {
const hits = [
{
@ -244,6 +245,15 @@ describe('geoPointToGeometry', () => {
expect(points[0].coordinates).toEqual([lon, lat]);
expect(points[1].coordinates).toEqual([lon2, lat2]);
});
it('Should handle point as geohash string', () => {
const geohashValue = 'drm3btev3e86';
const points = [];
geoPointToGeometry(geohashValue, points);
expect(points.length).toBe(1);
expect(points[0].coordinates).toEqual([-71.34000012651086, 41.12000000663102]);
});
});
describe('geoShapeToGeometry', () => {
@ -281,6 +291,30 @@ describe('geoShapeToGeometry', () => {
expect(shapes[1].type).toBe('Point');
expect(shapes[1].coordinates).toEqual(pointCoordinates);
});
it('Should convert wkt shapes to geojson', () => {
const pointWkt = 'POINT (32 40)';
const linestringWkt = 'LINESTRING (50 60, 70 80)';
const shapes = [];
geoShapeToGeometry(pointWkt, shapes);
geoShapeToGeometry(linestringWkt, shapes);
expect(shapes.length).toBe(2);
expect(shapes[0]).toEqual({
coordinates: [32, 40],
type: 'Point',
});
expect(shapes[1]).toEqual({
coordinates: [[50, 60], [70, 80]],
type: 'LineString',
});
});
});
describe('createExtentFilter', () => {

View file

@ -8152,6 +8152,15 @@ concat-stream@^1.4.7, concat-stream@~1.6.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concat-stream@~1.5.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
integrity sha1-cIl4Yk2FavQaWnQd790mHadSwmY=
dependencies:
inherits "~2.0.1"
readable-stream "~2.0.0"
typedarray "~0.0.5"
conf@^1.1.2, conf@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/conf/-/conf-1.4.0.tgz#1ea66c9d7a9b601674a5bb9d2b8dc3c726625e67"
@ -18242,7 +18251,7 @@ minimist@1.1.x:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=
minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
@ -27867,6 +27876,14 @@ websocket-extensions@>=0.1.1:
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
wellknown@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/wellknown/-/wellknown-0.5.0.tgz#09ae9871fa826cf0a6ec1537ef00c379d78d7101"
integrity sha1-Ca6YcfqCbPCm7BU37wDDedeNcQE=
dependencies:
concat-stream "~1.5.0"
minimist "~1.2.0"
wgs84@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/wgs84/-/wgs84-0.0.0.tgz#34fdc555917b6e57cf2a282ed043710c049cdc76"