From b0fe95dbd9a72d22388e3863c6d6194e6d166035 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 16 Apr 2025 18:28:23 +0200 Subject: [PATCH] feat: naive support for GeometryCollection as Feature geometry Currently, we just skip those, but sometimes togeojson produces this output from a KML. This will create one feature per geometry, while in an ideal world this should be a multi, but we lack reliable geometry tools to merge the geometries without risking to create mistakes. So let's say it's a first improvement. --- umap/static/umap/js/modules/data/layer.js | 15 +++++- umap/tests/integration/test_import.py | 57 +++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/umap/static/umap/js/modules/data/layer.js b/umap/static/umap/js/modules/data/layer.js index 617fea1a..a0b5f5ff 100644 --- a/umap/static/umap/js/modules/data/layer.js +++ b/umap/static/umap/js/modules/data/layer.js @@ -492,8 +492,19 @@ export class DataLayer { const features = [] this.sortFeatures(collection) for (const featureJson of collection) { - const feature = this.makeFeature(featureJson, sync) - if (feature) features.push(feature) + if (featureJson.geometry?.type === 'GeometryCollection') { + for (const geometry of featureJson.geometry.geometries) { + const feature = this.makeFeature({ + type: 'Feature', + geometry, + properties: featureJson.properties, + }) + if (feature) features.push(feature) + } + } else { + const feature = this.makeFeature(featureJson, sync) + if (feature) features.push(feature) + } } return features } diff --git a/umap/tests/integration/test_import.py b/umap/tests/integration/test_import.py index 779aae75..424762ae 100644 --- a/umap/tests/integration/test_import.py +++ b/umap/tests/integration/test_import.py @@ -435,6 +435,63 @@ def test_import_geometry_collection(live_server, page, tilelayer): expect(paths).to_have_count(2) +def test_import_geometry_collection_in_feature(live_server, page, tilelayer): + data = { + "type": "Feature", + "properties": {"name": "foobar"}, + "geometry": { + "type": "GeometryCollection", + "geometries": [ + {"type": "Point", "coordinates": [-80.6608, 35.0493]}, + { + "type": "Polygon", + "coordinates": [ + [ + [-80.6645, 35.0449], + [-80.6634, 35.0460], + [-80.6625, 35.0455], + [-80.6638, 35.0442], + [-80.6645, 35.0449], + ] + ], + }, + { + "type": "LineString", + "coordinates": [ + [-80.66237, 35.05950], + [-80.66269, 35.05926], + [-80.66284, 35.05893], + [-80.66308, 35.05833], + [-80.66385, 35.04387], + [-80.66303, 35.04371], + ], + }, + ], + }, + } + page.goto(f"{live_server.url}/map/new/") + page.get_by_title("Open browser").click() + layers = page.locator(".umap-browser .datalayer") + markers = page.locator(".leaflet-marker-icon") + paths = page.locator("path") + expect(markers).to_have_count(0) + expect(paths).to_have_count(0) + expect(layers).to_have_count(0) + button = page.get_by_title("Import data") + expect(button).to_be_visible() + button.click() + textarea = page.locator(".umap-import textarea") + textarea.fill(json.dumps(data)) + page.locator('select[name="format"]').select_option("geojson") + page.get_by_role("button", name="Import data", exact=True).click() + # A layer has been created + expect(layers).to_have_count(1) + expect(markers).to_have_count(1) + expect(paths).to_have_count(2) + # Geometries are treated as separate features. + expect(page.get_by_text("foobar")).to_have_count(3) + + def test_import_multipolygon(live_server, page, tilelayer): data = { "type": "Feature",