From f0765df5ed69344f2ce6364449de53542a662384 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 21 Mar 2021 01:32:21 +0100 Subject: [PATCH] Add possibility to add external geojson --- Customizations/JSON/LayerConfig.ts | 10 ++-- InitUiElements.ts | 2 +- Logic/Actors/UpdateFromOverpass.ts | 4 ++ Logic/FeatureSource/FeaturePipeline.ts | 15 +++++- Logic/FeatureSource/FeatureSourceMerger.ts | 1 - Logic/FeatureSource/GeoJsonSource.ts | 52 ++++++++++++++++++++ Logic/Osm/Overpass.ts | 1 + UI/ShowDataLayer.ts | 2 +- assets/tagRenderings/icons.json | 3 +- assets/themes/speelplekken/speelplekken.json | 19 ++++++- 10 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 Logic/FeatureSource/GeoJsonSource.ts diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index 2cc3b54..af0b7d3 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -127,7 +127,7 @@ export default class LayerConfig { * A string is interpreted as a name to call * @param tagRenderings */ - function trs(tagRenderings?: (string | TagRenderingConfigJson)[]) { + function trs(tagRenderings?: (string | TagRenderingConfigJson)[], readOnly = false) { if (tagRenderings === undefined) { return []; } @@ -137,6 +137,10 @@ export default class LayerConfig { if (typeof renderingJson === "string") { if (renderingJson === "questions") { + if(readOnly){ + throw `A tagrendering has a question, but asking a question does not make sense here: is it a title icon or a geojson-layer? ${context}` + } + return new TagRenderingConfig("questions", undefined) } @@ -151,7 +155,7 @@ export default class LayerConfig { }); } - this.tagRenderings = trs(json.tagRenderings); + this.tagRenderings = trs(json.tagRenderings, this.source.geojsonSource !== undefined); const titleIcons = []; @@ -164,7 +168,7 @@ export default class LayerConfig { } } - this.titleIcons = trs(titleIcons); + this.titleIcons = trs(titleIcons, true); this.title = tr("title", undefined); diff --git a/InitUiElements.ts b/InitUiElements.ts index 97ef886..2b0da01 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -394,7 +394,7 @@ export class InitUiElements { features.forEach(feature => { State.state.allElements.addOrGetElement(feature); - if (Hash.hash.data === feature.properties.id.replace("/", "_")) { + if (Hash.hash.data === feature.properties.id) { State.state.selectedElement.setData(feature); } diff --git a/Logic/Actors/UpdateFromOverpass.ts b/Logic/Actors/UpdateFromOverpass.ts index 5785156..8f2809b 100644 --- a/Logic/Actors/UpdateFromOverpass.ts +++ b/Logic/Actors/UpdateFromOverpass.ts @@ -85,6 +85,10 @@ export default class UpdateFromOverpass implements FeatureSource { if (layer.doNotDownload) { continue; } + if(layer.source.geojsonSource !== undefined){ + // Not our responsibility to download this layer! + continue; + } // Check if data for this layer has already been loaded diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index cfe8989..688f4fc 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -11,6 +11,7 @@ import LayerConfig from "../../Customizations/JSON/LayerConfig"; import LocalStorageSource from "./LocalStorageSource"; import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; import Loc from "../../Models/Loc"; +import GeoJsonSource from "./GeoJsonSource"; export default class FeaturePipeline implements FeatureSource { @@ -30,6 +31,15 @@ export default class FeaturePipeline implements FeatureSource { ) ); + const geojsonSources: GeoJsonSource [] = [] + for (const flayer of flayers.data) { + const sourceUrl = flayer.layerDef.source.geojsonSource + if (sourceUrl !== undefined) { + geojsonSources.push(new WayHandlingApplyingFeatureSource(flayers, + new GeoJsonSource(flayer.layerDef.id, sourceUrl))) + } + } + const amendedLocalStorageSource = new RememberingSource( new WayHandlingApplyingFeatureSource(flayers, @@ -37,11 +47,12 @@ export default class FeaturePipeline implements FeatureSource { )); newPoints = new FeatureDuplicatorPerLayer(flayers, newPoints); - + const merged = new FeatureSourceMerger([ amendedOverpassSource, amendedLocalStorageSource, - newPoints + newPoints, + ...geojsonSources ]); const source = diff --git a/Logic/FeatureSource/FeatureSourceMerger.ts b/Logic/FeatureSource/FeatureSourceMerger.ts index fc85daf..717c18b 100644 --- a/Logic/FeatureSource/FeatureSourceMerger.ts +++ b/Logic/FeatureSource/FeatureSourceMerger.ts @@ -22,7 +22,6 @@ export default class FeatureSourceMerger implements FeatureSource { let all = {}; // Mapping 'id' -> {feature, freshness} for (const source of this._sources) { if(source?.features?.data === undefined){ - console.log("Not defined"); continue; } for (const f of source.features.data) { diff --git a/Logic/FeatureSource/GeoJsonSource.ts b/Logic/FeatureSource/GeoJsonSource.ts new file mode 100644 index 0000000..a8d3c79 --- /dev/null +++ b/Logic/FeatureSource/GeoJsonSource.ts @@ -0,0 +1,52 @@ +import FeatureSource from "./FeatureSource"; +import {UIEventSource} from "../UIEventSource"; +import * as $ from "jquery"; +import {Layer} from "leaflet"; + +/** + * Fetches a geojson file somewhere and passes it along + */ +export default class GeoJsonSource implements FeatureSource { + features: UIEventSource<{ feature: any; freshness: Date }[]>; + + constructor(layerId: string, url: string, onFail: ((errorMsg: any) => void) = undefined) { + if (onFail === undefined) { + onFail = errorMsg => { + console.warn(`Could not load geojson layer from`, url, "due to", errorMsg) + } + } + this.features = new UIEventSource<{ feature: any; freshness: Date }[]>(undefined) + const eventSource = this.features; + $.getJSON(url, function (json, status) { + if (status !== "success") { + console.log("Fetching geojson failed failed") + onFail(status); + return; + } + + if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) { + console.log("Timeout or other runtime error"); + onFail("Runtime error (timeout)") + return; + } + const time = new Date(); + const features: { feature: any, freshness: Date } [] = [] + let i = 0; + for (const feature of json.features) { + if (feature.properties.id === undefined) { + feature.properties.id = url + "/" + i; + feature.id = url + "/" + i; + i++; + } + feature._matching_layer_id = layerId; + features.push({feature: feature, freshness: time}) + } + console.log("Loaded features are", features) + eventSource.setData(features) + + }).fail(onFail) + + } + + +} \ No newline at end of file diff --git a/Logic/Osm/Overpass.ts b/Logic/Osm/Overpass.ts index 66df736..7035329 100644 --- a/Logic/Osm/Overpass.ts +++ b/Logic/Osm/Overpass.ts @@ -44,6 +44,7 @@ export class Overpass { if (status !== "success") { console.log("Query failed") onFail(status); + return; } if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) { diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index f10bc41..9991b08 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -110,7 +110,7 @@ export default class ShowDataLayer { private postProcessFeature(feature, leafletLayer: L.Layer) { const layer: LayerConfig = this._layerDict[feature._matching_layer_id]; if(layer === undefined){ - console.warn("No layer found for object (probably a now disabled layer)", feature) + console.warn("No layer found for object (probably a now disabled layer)", feature, this._layerDict) return; } if (layer.title === undefined && (layer.tagRenderings ?? []).length === 0) { diff --git a/assets/tagRenderings/icons.json b/assets/tagRenderings/icons.json index 6261d99..e0bde24 100644 --- a/assets/tagRenderings/icons.json +++ b/assets/tagRenderings/icons.json @@ -62,7 +62,8 @@ "if": "id~=-", "then": "Uploading..." } - ] + ], + "condition": "id~(node|way|relation)/[0-9]*" }, "sharelink": { "render": "{share_link()}" diff --git a/assets/themes/speelplekken/speelplekken.json b/assets/themes/speelplekken/speelplekken.json index 0ab7bb8..7f43645 100644 --- a/assets/themes/speelplekken/speelplekken.json +++ b/assets/themes/speelplekken/speelplekken.json @@ -15,7 +15,7 @@ "maintainer": "MapComplete", "icon": "./assets/layers/play_forest/icon.svg", "hideFromOverview": true, - "lockLocation": true, + "lockLocation": false, "version": "0", "startLat": 51.17174, "startLon": 4.449462, @@ -23,13 +23,28 @@ "widenFactor": 0.05, "socialImage": "", "defaultBackgroundId": "CartoDB.Positron", - "layers": [ + "layersX": [ "play_forest", "playground", "sport_pitch", "slow_roads", "grass_in_parks", "village_green" + ], + "layers": [ + { + "id": "test", + "source": { + "osmTags": "country~*", + "geoJsonSource": "https://pietervdvn.github.io/latlon2country/15.10774.14922.json" + }, + "maxOverlapPercentage": 0, + "name": "test", + "title": "Test", + "minzoom": 0 + } + + ], "roamingRenderings": [] } \ No newline at end of file