Hi Anthony and Dave,
Thank you for your suggestions and I have implemented this visualiser:). I
add button in the cell and when it's clicked the geometry is shown in a
map. Here is the screenshots of it:
https://photos.app.goo.gl/fQVBRcmZJ3YcPLcL8
Attached is the patch for this geometry viewer. Please review it. Thank you.
Anthony DeBarros <[email protected]> 于2018年5月26日周六 上午12:47写道:
> I agree the map is the ultimate tool. However, I do think that being able
>> to quickly view a single geometry from within the grid makes a lot of sense
>> - and for users who want to easily visualise a single geometry, will be a
>> great deal more convenient than the map.
>>
>> Note that I'm not talking about anything complex here - just a
>> convenience panel that renders the geometry, and maybe has zoom and
>> scrolling. The viewing tab would be where the real magic happens - handling
>> the map overlay and the ability to display many geometries at once.
>>
>>
>> As a user, I would agree with Dave here. A good example is a table that
> holds the polygons of each county in the U.S. or each country in Europe. It
> would be very helpful to view each individually as well as collectively if
> I were to select all in a query.
>
>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EnterpriseDB UK: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>
diff --git a/web/package.json b/web/package.json
index a551af1..102aad2 100644
--- a/web/package.json
+++ b/web/package.json
@@ -63,6 +63,7 @@
"css-loader": "0.14.0",
"cssnano": "^3.10.0",
"dropzone": "^5.1.1",
+ "element-resize-detector": "^1.1.14",
"eonasdan-bootstrap-datetimepicker": "^4.17.47",
"exports-loader": "~0.6.4",
"flotr2": "^0.1.0",
@@ -74,6 +75,7 @@
"jquery": "3.3.1",
"jquery-contextmenu": "^2.6.4",
"jquery-ui": "^1.12.1",
+ "leaflet": "^1.3.3",
"moment": "^2.20.1",
"mousetrap": "^1.6.1",
"prop-types": "^15.5.10",
@@ -91,7 +93,8 @@
"underscore": "^1.8.3",
"underscore.string": "^3.3.4",
"watchify": "~3.9.0",
- "webcabin-docker": "git+https://github.com/EnterpriseDB/wcDocker"
+ "webcabin-docker": "git+https://github.com/EnterpriseDB/wcDocker",
+ "wkx": "^0.4.5"
},
"scripts": {
"linter": "yarn eslint --no-eslintrc -c .eslintrc.js --ext .js --ext .jsx .",
diff --git a/web/pgadmin/static/css/style.css b/web/pgadmin/static/css/style.css
index ed88eab..d9d39bf 100644
--- a/web/pgadmin/static/css/style.css
+++ b/web/pgadmin/static/css/style.css
@@ -14,6 +14,7 @@
@import '~webcabin-docker/Build/wcDocker.css';
@import '~acitree/css/aciTree.css';
@import '~spectrum-colorpicker/spectrum.css';
+@import '~leaflet/dist/leaflet.css';
@import '~codemirror/lib/codemirror.css';
@import '~codemirror/addon/dialog/dialog.css';
diff --git a/web/pgadmin/static/js/slickgrid/formatters.js b/web/pgadmin/static/js/slickgrid/formatters.js
index adfcf79..ea003d4 100644
--- a/web/pgadmin/static/js/slickgrid/formatters.js
+++ b/web/pgadmin/static/js/slickgrid/formatters.js
@@ -4,6 +4,8 @@
* @module Formatters
* @namespace Slick
*/
+import {Geometry} from 'wkx';
+import {Buffer} from 'buffer';
(function($) {
// register namespace
@@ -15,6 +17,7 @@
'Checkmark': CheckmarkFormatter,
'Text': TextFormatter,
'Binary': BinaryFormatter,
+ 'EWKB': EWKBFormatter,
},
},
});
@@ -111,4 +114,39 @@
return '<span class=\'pull-left disabled_cell\'>[' + _.escape(value) + ']</span>';
}
}
+
+ function EWKBFormatter(row, cell, value, columnDef, dataContext) {
+ // If column has default value, set placeholder
+ var data = NullAndDefaultFormatter(row, cell, value, columnDef, dataContext);
+ if (data) {
+ return data;
+ } else {
+ let geometry;
+ try {
+ let buffer = new Buffer(value, 'hex');
+ geometry = Geometry.parse(buffer);
+ } catch (e) {
+ //unsupported geometry type
+ return '<button title="Can not render geometry of this type" class="btn-xs btn-default btn-ewkb-viewer disabled">' +
+ '<i class="fa fa-eye-slash" aria-hidden="true"></i>' +
+ '</button>' +
+ _.escape(value);
+ }
+
+ if (geometry.hasZ) {
+ //the viewer can not render 3d geometry
+ return '<button title="Can not render 3d geometry" class="btn-xs btn-default btn-ewkb-viewer disabled">' +
+ '<i class="fa fa-eye-slash" aria-hidden="true"></i>' +
+ '</button>' +
+ _.escape(value);
+ }
+ else {
+ return '<button title="View Geometry" class="btn-xs btn-default btn-ewkb-viewer btn-view-ewkb-enabled">' +
+ '<i class="fa fa-eye" aria-hidden="true"></i>' +
+ '</button>' +
+ _.escape(value);
+ }
+
+ }
+ }
})(window.jQuery);
diff --git a/web/pgadmin/static/js/sqleditor/geometry_viewer.js b/web/pgadmin/static/js/sqleditor/geometry_viewer.js
new file mode 100644
index 0000000..4254547
--- /dev/null
+++ b/web/pgadmin/static/js/sqleditor/geometry_viewer.js
@@ -0,0 +1,140 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import gettext from 'sources/gettext';
+import Alertify from 'pgadmin.alertifyjs';
+import {Geometry} from 'wkx';
+import {Buffer} from 'buffer';
+import $ from 'jquery';
+import elementResizeDetectorMaker from 'element-resize-detector';
+import L from 'leaflet';
+
+// fix the icon url issue according to https://github.com/Leaflet/Leaflet/issues/4849
+import 'leaflet/dist/images/marker-icon.png';
+import 'leaflet/dist/images/marker-icon-2x.png';
+import 'leaflet/dist/images/marker-shadow.png';
+import 'leaflet/dist/images/layers.png';
+import 'leaflet/dist/images/layers-2x.png';
+
+
+let GeometryViewerDialog = {
+
+ 'dialog': function (value) {
+
+ Alertify.mapDialog || Alertify.dialog('mapDialog', function () {
+ let $container = $('<div class="ewkb-viewer-container"></div>');
+ let geomLayer = L.geoJSON();
+ let osmLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ attribution: '<a target="_blank" href="https://www.openstreetmap.org/copyright">© OpenStreetMap</a>',
+ });
+ let lmap;
+
+ return {
+ main: function (geometry) {
+ //reset map
+ geomLayer.clearLayers();
+ lmap.eachLayer(function (layer) {
+ lmap.removeLayer(layer);
+ });
+
+ try {
+ geomLayer.addData(geometry.toGeoJSON());
+ } catch (e) {
+ // Invalid LatLng object: (NaN, NaN)
+ lmap.setView([0, 0], 0);
+ return;
+ }
+
+ if (geometry.toWkt().endsWith('EMPTY')) {
+ // empty geometry
+ lmap.setView([0, 0], 0);
+ } else {
+ let bounds = geomLayer.getBounds();
+ bounds = bounds.pad(0.1);
+ let maxLength = Math.max(bounds.getNorth() - bounds.getSouth(),
+ bounds.getEast() - bounds.getWest());
+ if (geometry.srid === 4326) {
+ lmap.options.crs = L.CRS.EPSG3857;
+ lmap.setMinZoom(0);
+ osmLayer.addTo(lmap);
+ } else {
+ lmap.options.crs = L.CRS.Simple;
+ if (maxLength >= 180) {
+ // calculate the min zoom level to enable the map to fit the whole geometry.
+ let minZoom = Math.floor(Math.log2(360 / maxLength)) - 2;
+ lmap.setMinZoom(minZoom);
+ } else {
+ lmap.setMinZoom(0);
+ }
+ }
+ geomLayer.addTo(lmap);
+
+ if (maxLength > 0) {
+ lmap.fitBounds(bounds);
+ } else {
+ lmap.setView(bounds.getCenter(), 5);
+ }
+ }
+ },
+
+ setup: function () {
+ return {
+ options: {
+ closable: true,
+ frameless: true,
+ padding: false,
+ overflow: false,
+ title: gettext('Geometry Viewer'),
+ },
+ };
+ },
+
+ build: function () {
+ let div = $container.get(0);
+ this.elements.content.appendChild(div);
+ lmap = L.map(div);
+ geomLayer.addTo(lmap);
+ // add resize event listener to resize map
+ let erd = elementResizeDetectorMaker();
+ erd.listenTo(div, function () {
+ setTimeout(function () {
+ lmap.invalidateSize();
+ }, 200);
+ });
+ Alertify.pgDialogBuild.apply(this);
+ this.elements.dialog.style.width = '80%';
+ this.elements.dialog.style.height = '60%';
+ },
+
+ prepare: function () {
+ this.elements.dialog.style.width = '80%';
+ this.elements.dialog.style.height = '60%';
+ },
+ };
+ });
+
+ let geometry;
+ try {
+ let buffer = new Buffer(value, 'hex');
+ geometry = Geometry.parse(buffer);
+ } catch (e) {
+ Alertify.alert(gettext('Geometry Viewer Error'), gettext('Can not render geometry of this type'));
+ }
+
+ if (geometry.hasZ) {
+ Alertify.alert(gettext('Geometry Viewer Error'), gettext('Can not render 3d geometry'));
+ } else {
+ Alertify.mapDialog(geometry);
+ }
+ },
+
+};
+
+
+module.exports = GeometryViewerDialog;
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 75ead26..d48f5ad 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -641,3 +641,20 @@ input.editor-checkbox:focus {
.connection-status-hide {
display: none;
}
+
+/* For slickgrid EWKB data viewer button */
+.btn-ewkb-viewer{
+ float: right;
+ position: relative;
+}
+
+/* For EWKB data viewer dialog */
+.ewkb-viewer-container{
+ width: 100%;
+ height: 100%;
+}
+
+/* For leaflet map background */
+.leaflet-container {
+ background: #fff;
+}
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index 1316c7b..87c6c8d 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -15,6 +15,7 @@ define('tools.querytool', [
'sources/sqleditor/execute_query',
'sources/sqleditor/query_tool_http_error_handler',
'sources/sqleditor/filter_dialog',
+ 'sources/sqleditor/geometry_viewer',
'sources/history/index.js',
'sourcesjsx/history/query_history',
'react', 'react-dom',
@@ -36,7 +37,7 @@ define('tools.querytool', [
], function(
babelPollyfill, gettext, url_for, $, _, S, alertify, pgAdmin, Backbone, codemirror,
pgExplain, GridSelector, ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent,
- XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler,
+ XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler, GeometryViewerDialog,
HistoryBundle, queryHistory, React, ReactDOM,
keyboardShortcuts, queryToolActions, queryToolNotifications, Datagrid,
modifyAnimation, calculateQueryRunTime, callRenderAfterPoll, queryToolPref) {
@@ -727,7 +728,13 @@ define('tools.querytool', [
} else if (c.cell == 'binary') {
// We do not support editing binary data in SQL editor and data grid.
options['formatter'] = Slick.Formatters.Binary;
- } else {
+ } else if (c.cell == 'geometry' || c.cell == 'geography' ){
+ options['editor'] = is_editable ? Slick.Editors.pgText :
+ Slick.Editors.ReadOnlypgText;
+ // EWKB formatter for viewing geometry data.
+ options['formatter'] = Slick.Formatters.EWKB;
+ }
+ else {
options['editor'] = is_editable ? Slick.Editors.pgText :
Slick.Editors.ReadOnlypgText;
options['formatter'] = Slick.Formatters.Text;
@@ -826,6 +833,15 @@ define('tools.querytool', [
setStagedRows.bind(editor_data));
}
+ // listen for 'view geometry' button click event in datagrid
+ grid.onClick.subscribe(function (e, args) {
+ if ($(e.target).hasClass('btn-view-ewkb-enabled') || $(e.target).parent().hasClass('btn-view-ewkb-enabled')) {
+ var value = dataView.getItem(args.row)[grid.getColumns()[args.cell].field];
+ //show geometry viewer dialog
+ GeometryViewerDialog.dialog(value);
+ }
+ });
+
grid.onColumnsResized.subscribe(function() {
var columns = this.getColumns();
_.each(columns, function(col) {
@@ -2382,6 +2398,12 @@ define('tools.querytool', [
case 'bytea[]':
col_cell = 'binary';
break;
+ case 'geometry':
+ col_cell = 'geometry';
+ break;
+ case 'geography':
+ col_cell = 'geography';
+ break;
default:
col_cell = 'string';
}
diff --git a/web/regression/javascript/geometry_viewer/slickgrid_ewkb_formatter_spec.js b/web/regression/javascript/geometry_viewer/slickgrid_ewkb_formatter_spec.js
new file mode 100644
index 0000000..1f3b8e3
--- /dev/null
+++ b/web/regression/javascript/geometry_viewer/slickgrid_ewkb_formatter_spec.js
@@ -0,0 +1,172 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import 'sources/slickgrid/formatters';
+
+describe('EWKB formatter test', function () {
+ let EWKBFromatter = window.Slick.Formatters.EWKB;
+ const row = undefined;
+ const cell = undefined;
+
+ describe('format supported geometry', function () {
+ it('should return the view button for geometry', function () {
+ // POINT(0 0)
+ let ewkb = '010100000000000000000000000000000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // LINESTRING(0 0,1 1,1 2)
+ let ewkb = '01020000000300000000000000000000000000000000000000000000000000' +
+ 'F03F000000000000F03F000000000000F03F0000000000000040';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))
+ let ewkb = '01070000000200000001010000000000000000000040000000000000084001' +
+ '02000000020000000000000000000040000000000000084000000000000008400000000' +
+ '000001040';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // SRID=32632;POINT(0 0)
+ let ewkb = '0101000020787F000000000000000000000000000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // SRID=4326;MULTIPOINTM(0 0 0,1 2 1)
+ let ewkb = '0104000060E610000002000000010100004000000000000000000000000000' +
+ '00000000000000000000000101000040000000000000F03F00000000000000400000000' +
+ '00000F03F';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))
+ let ewkb = '01070000000200000001010000000000000000000040000000000000084001' +
+ '02000000020000000000000000000040000000000000084000000000000008400000000' +
+ '000001040';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // POINT EMPTY
+ let ewkb = '0101000000000000000000F87F000000000000F87F';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // LINESTRING EMPTY
+ let ewkb = '010200000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // POLYGON EMPTY
+ let ewkb = '010300000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // MULTIPOINT EMPTY
+ let ewkb = '010400000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ it('should return the view button for geometry', function () {
+ // GEOMETRYCOLLECTION EMPTY
+ let ewkb = '010700000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('View Geometry');
+ });
+ });
+
+ describe('format 3d geometry', function () {
+ it('should return the disabled button for 3d geometry', function () {
+ // POINT(0 0 0)
+ let ewkb = '0101000080000000000000F03F000000000000F03F000000000000F03F';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render 3d geometry');
+ });
+
+ it('should return the disabled button for 3d geometry', function () {
+ // POINT(0 0 0 0)
+ let ewkb = '01010000C00000000000000000000000000000000000000000000000000000' +
+ '000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render 3d geometry');
+ });
+
+ it('should return the disabled button for 3d geometry', function () {
+ let ewkb = '01060000800200000001030000800200000005000000000000000000000000' +
+ '00000000000000000000000000000000000000000010400000000000000000000000000' +
+ '00000000000000000001040000000000000104000000000000000000000000000000000' +
+ '00000000000010400000000000000000000000000000000000000000000000000000000' +
+ '00000000005000000000000000000F03F000000000000F03F0000000000000000000000' +
+ '0000000040000000000000F03F000000000000000000000000000000400000000000000' +
+ '0400000000000000000000000000000F03F000000000000004000000000000000000000' +
+ '00000000F03F000000000000F03F0000000000000000010300008001000000050000000' +
+ '00000000000F0BF000000000000F0BF0000000000000000000000000000F0BF00000000' +
+ '000000C0000000000000000000000000000000C000000000000000C0000000000000000' +
+ '000000000000000C0000000000000F0BF0000000000000000000000000000F0BF000000' +
+ '000000F0BF0000000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render 3d geometry');
+ });
+ });
+
+ describe('format unsupported geometry type', function () {
+ it('should return the disabled button for unsupported geometry', function () {
+ let ewkb = '';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render geometry of this type');
+ });
+ it('should return the disabled button for unsupported geometry', function () {
+ // MULTICURVE( (0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4) )
+ let ewkb = '010B0000000200000001020000000200000000000000000000000000000000' +
+ '00000000000000000014400000000000001440010800000003000000000000000000104' +
+ '00000000000000000000000000000104000000000000010400000000000002040000000' +
+ '0000001040';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render geometry of this type');
+ });
+ it('should return the disabled button for unsupported geometry', function () {
+ // POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )
+ let ewkb = '010F0000800600000001030000800100000005000000000000000000000000' +
+ '00000000000000000000000000000000000000000000000000000000000000000000000' +
+ '000F03F0000000000000000000000000000F03F000000000000F03F0000000000000000' +
+ '000000000000F03F0000000000000000000000000000000000000000000000000000000' +
+ '00000000001030000800100000005000000000000000000000000000000000000000000' +
+ '0000000000000000000000000000000000000000F03F000000000000000000000000000' +
+ '0F03F000000000000F03F0000000000000000000000000000F03F000000000000000000' +
+ '00000000000000000000000000000000000000000000000000000000000000010300008' +
+ '00100000005000000000000000000000000000000000000000000000000000000000000' +
+ '000000F03F00000000000000000000000000000000000000000000F03F0000000000000' +
+ '000000000000000F03F00000000000000000000000000000000000000000000F03F0000' +
+ '00000000000000000000000000000000000000000000010300008001000000050000000' +
+ '00000000000F03F000000000000F03F0000000000000000000000000000F03F00000000' +
+ '0000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03' +
+ 'F000000000000F03F00000000000000000000000000000000000000000000F03F000000' +
+ '000000F03F0000000000000000010300008001000000050000000000000000000000000' +
+ '000000000F03F00000000000000000000000000000000000000000000F03F0000000000' +
+ '00F03F000000000000F03F000000000000F03F000000000000F03F000000000000F03F0' +
+ '00000000000F03F00000000000000000000000000000000000000000000F03F00000000' +
+ '00000000010300008001000000050000000000000000000000000000000000000000000' +
+ '0000000F03F000000000000F03F0000000000000000000000000000F03F000000000000' +
+ 'F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000' +
+ '000000000F03F00000000000000000000000000000000000000000000F03F';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render geometry of this type');
+ });
+ it('should return the disabled button for unsupported geometry', function () {
+ // TRIANGLE ((0 0, 0 9, 9 0, 0 0))
+ let ewkb = '01110000000100000004000000000000000000000000000000000000000000' +
+ '00000000000000000000000022400000000000002240000000000000000000000000000' +
+ '000000000000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render geometry of this type');
+ });
+ it('should return the disabled button for unsupported geometry', function () {
+ // TIN( ((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0)) )
+ let ewkb = '01100000800200000001110000800100000004000000000000000000000000' +
+ '00000000000000000000000000000000000000000000000000000000000000000000000' +
+ '000F03F0000000000000000000000000000F03F00000000000000000000000000000000' +
+ '00000000000000000000000000000000011100008001000000040000000000000000000' +
+ '000000000000000000000000000000000000000000000000000000000000000F03F0000' +
+ '000000000000000000000000F03F000000000000F03F000000000000000000000000000' +
+ '0000000000000000000000000000000000000';
+ expect(EWKBFromatter(row, cell, ewkb)).toContain('Can not render geometry of this type');
+ });
+ });
+});
diff --git a/web/yarn.lock b/web/yarn.lock
index f0ff60b..9506f1e 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -1234,6 +1234,10 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
+batch-processor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8"
+
bcrypt-pbkdf@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
@@ -3002,6 +3006,12 @@ electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30:
version "1.3.45"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.45.tgz#458ac1b1c5c760ce8811a16d2bfbd97ec30bafb8"
+element-resize-detector@^1.1.14:
+ version "1.1.14"
+ resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.1.14.tgz#af064a0a618a820ad570a95c5eec5b77be0128c1"
+ dependencies:
+ batch-processor "^1.0.0"
+
elliptic@^6.0.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
@@ -5604,6 +5614,10 @@ lead@^1.0.0:
dependencies:
flush-write-stream "^1.0.2"
+leaflet@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.3.3.tgz#5c8f2fd50e4a41ead93ab850dcd9e058811da9b9"
+
level-codec@~7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7"
@@ -9611,6 +9625,12 @@ [email protected]:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+wkx@^0.4.5:
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.4.5.tgz#a85e15a6e69d1bfaec2f3c523be3dfa40ab861d0"
+ dependencies:
+ "@types/node" "*"
+
[email protected]:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"