forked from MapComplete/MapComplete
Further stabilization of UK-addresses: add minzoom requirement to import button, fix eternal loading message
This commit is contained in:
parent
561b21d2fe
commit
d8fa054a34
8 changed files with 71 additions and 40 deletions
|
@ -29,8 +29,12 @@ export default class SaveTileToLocalStorageActor {
|
||||||
|
|
||||||
public static MarkVisited(layerId: string, tileId: number, freshness: Date){
|
public static MarkVisited(layerId: string, tileId: number, freshness: Date){
|
||||||
const key = `${SaveTileToLocalStorageActor.storageKey}-${layerId}-${tileId}`
|
const key = `${SaveTileToLocalStorageActor.storageKey}-${layerId}-${tileId}`
|
||||||
localStorage.setItem(key + "-time", JSON.stringify(freshness.getTime()))
|
try{
|
||||||
localStorage.setItem(key + "-format", SaveTileToLocalStorageActor.formatVersion)
|
localStorage.setItem(key + "-time", JSON.stringify(freshness.getTime()))
|
||||||
|
localStorage.setItem(key + "-format", SaveTileToLocalStorageActor.formatVersion)
|
||||||
|
}catch(e){
|
||||||
|
console.error("Could not mark tile ", key, "as visited")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -206,7 +206,9 @@ export default class FeaturePipeline {
|
||||||
maxZoomLevel: state.layoutToUse.clustering.maxZoom,
|
maxZoomLevel: state.layoutToUse.clustering.maxZoom,
|
||||||
registerTile: (tile) => {
|
registerTile: (tile) => {
|
||||||
// We save the tile data for the given layer to local storage
|
// We save the tile data for the given layer to local storage
|
||||||
new SaveTileToLocalStorageActor(tile, tile.tileIndex)
|
if(source.layer.layerDef.source.geojsonSource === undefined || source.layer.layerDef.source.isOsmCacheLayer == true){
|
||||||
|
new SaveTileToLocalStorageActor(tile, tile.tileIndex)
|
||||||
|
}
|
||||||
perLayerHierarchy.get(source.layer.layerDef.id).registerTile(new RememberingSource(tile))
|
perLayerHierarchy.get(source.layer.layerDef.id).registerTile(new RememberingSource(tile))
|
||||||
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile))
|
||||||
|
|
||||||
|
@ -239,7 +241,11 @@ export default class FeaturePipeline {
|
||||||
|
|
||||||
|
|
||||||
this.runningQuery = updater.runningQuery.map(
|
this.runningQuery = updater.runningQuery.map(
|
||||||
overpass => overpass || osmFeatureSource.isRunning.data, [osmFeatureSource.isRunning]
|
overpass => {
|
||||||
|
console.log("FeaturePipeline: runningQuery state changed. Overpass", overpass ? "is querying," : "is idle,",
|
||||||
|
"osmFeatureSource is", osmFeatureSource.isRunning ? "is running ("+ +")" : "is idle")
|
||||||
|
return overpass || osmFeatureSource.isRunning.data;
|
||||||
|
}, [osmFeatureSource.isRunning]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,21 +58,25 @@ export default class OsmFeatureSource {
|
||||||
|
|
||||||
for (const neededTile of neededTiles) {
|
for (const neededTile of neededTiles) {
|
||||||
if (self.downloadedTiles.has(neededTile)) {
|
if (self.downloadedTiles.has(neededTile)) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
console.log("Tile download", Tiles.tile_from_index(neededTile).join("/"), "started")
|
||||||
self.downloadedTiles.add(neededTile)
|
self.downloadedTiles.add(neededTile)
|
||||||
Promise.resolve(self.LoadTile(...Tiles.tile_from_index(neededTile)).then(_ => {
|
self.LoadTile(...Tiles.tile_from_index(neededTile)).then(_ => {
|
||||||
}))
|
console.log("Tile ", Tiles.tile_from_index(neededTile).join("/"), "loaded")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
}finally {
|
||||||
|
console.log("Done")
|
||||||
|
self.isRunning.setData(false)
|
||||||
}
|
}
|
||||||
self.isRunning.setData(false)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const neededLayers = options.state.layoutToUse.layers
|
const neededLayers = options.state.layoutToUse.layers
|
||||||
.filter( layer => !layer.doNotDownload )
|
.filter(layer => !layer.doNotDownload)
|
||||||
.filter(layer => layer.source.geojsonSource === undefined || layer.source.isOsmCacheLayer)
|
.filter(layer => layer.source.geojsonSource === undefined || layer.source.isOsmCacheLayer)
|
||||||
this.allowedTags = new Or(neededLayers.map(l => l.source.osmTags))
|
this.allowedTags = new Or(neededLayers.map(l => l.source.osmTags))
|
||||||
}
|
}
|
||||||
|
@ -96,22 +100,22 @@ export default class OsmFeatureSource {
|
||||||
{
|
{
|
||||||
flatProperties: true
|
flatProperties: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// The geojson contains _all_ features at the given location
|
// The geojson contains _all_ features at the given location
|
||||||
// We only keep what is needed
|
// We only keep what is needed
|
||||||
|
|
||||||
geojson.features = geojson.features.filter(feature => this.allowedTags.matchesProperties(feature.properties))
|
geojson.features = geojson.features.filter(feature => this.allowedTags.matchesProperties(feature.properties))
|
||||||
|
|
||||||
console.log("Tile geojson:", z, x, y, "is", geojson)
|
console.log("Tile geojson:", z, x, y, "is", geojson)
|
||||||
const index = Tiles.tile_index(z, x, y);
|
const index = Tiles.tile_index(z, x, y);
|
||||||
new PerLayerFeatureSourceSplitter(this.filteredLayers,
|
new PerLayerFeatureSourceSplitter(this.filteredLayers,
|
||||||
this.handleTile,
|
this.handleTile,
|
||||||
new StaticFeatureSource(geojson.features, false),
|
new StaticFeatureSource(geojson.features, false),
|
||||||
{
|
{
|
||||||
tileIndex:index
|
tileIndex: index
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(this.options.markTileVisited){
|
if (this.options.markTileVisited) {
|
||||||
this.options.markTileVisited(index)
|
this.options.markTileVisited(index)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -9,11 +9,17 @@ import Constants from "../../Models/Constants";
|
||||||
import Toggle from "../Input/Toggle";
|
import Toggle from "../Input/Toggle";
|
||||||
import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction";
|
import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction";
|
||||||
import {Tag} from "../../Logic/Tags/Tag";
|
import {Tag} from "../../Logic/Tags/Tag";
|
||||||
|
import Loading from "../Base/Loading";
|
||||||
|
|
||||||
export default class ImportButton extends Toggle {
|
export default class ImportButton extends Toggle {
|
||||||
constructor(imageUrl: string | BaseUIElement, message: string | BaseUIElement,
|
constructor(imageUrl: string | BaseUIElement, message: string | BaseUIElement,
|
||||||
originalTags: UIEventSource<any>,
|
originalTags: UIEventSource<any>,
|
||||||
newTags: UIEventSource<Tag[]>, lat: number, lon: number) {
|
newTags: UIEventSource<Tag[]>,
|
||||||
|
lat: number, lon: number,
|
||||||
|
minZoom: number,
|
||||||
|
state: {
|
||||||
|
locationControl: UIEventSource<{ zoom: number }>
|
||||||
|
}) {
|
||||||
const t = Translations.t.general.add;
|
const t = Translations.t.general.add;
|
||||||
const isImported = originalTags.map(tags => tags._imported === "yes")
|
const isImported = originalTags.map(tags => tags._imported === "yes")
|
||||||
const appliedTags = new Toggle(
|
const appliedTags = new Toggle(
|
||||||
|
@ -30,6 +36,7 @@ export default class ImportButton extends Toggle {
|
||||||
)
|
)
|
||||||
const button = new SubtleButton(imageUrl, message)
|
const button = new SubtleButton(imageUrl, message)
|
||||||
|
|
||||||
|
minZoom = Math.max(16, minZoom ?? 19)
|
||||||
|
|
||||||
button.onClick(async () => {
|
button.onClick(async () => {
|
||||||
if (isImported.data) {
|
if (isImported.data) {
|
||||||
|
@ -49,11 +56,13 @@ export default class ImportButton extends Toggle {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const withLoadingCheck = new Toggle(
|
const withLoadingCheck = new Toggle(new Toggle(
|
||||||
t.stillLoading,
|
new Loading(t.stillLoading.Clone()),
|
||||||
new Combine([button, appliedTags]).SetClass("flex flex-col"),
|
new Combine([button, appliedTags]).SetClass("flex flex-col"),
|
||||||
State.state.featurePipeline.runningQuery
|
State.state.featurePipeline.runningQuery
|
||||||
)
|
),t.zoomInFurther.Clone(),
|
||||||
|
state.locationControl.map(l => l.zoom >= minZoom)
|
||||||
|
)
|
||||||
const importButton = new Toggle(t.hasBeenImported, withLoadingCheck, isImported)
|
const importButton = new Toggle(t.hasBeenImported, withLoadingCheck, isImported)
|
||||||
|
|
||||||
const pleaseLoginButton =
|
const pleaseLoginButton =
|
||||||
|
|
|
@ -396,7 +396,10 @@ export default class SpecialVisualizations {
|
||||||
name: "icon",
|
name: "icon",
|
||||||
doc: "A nice icon to show in the button",
|
doc: "A nice icon to show in the button",
|
||||||
defaultValue: "./assets/svg/addSmall.svg"
|
defaultValue: "./assets/svg/addSmall.svg"
|
||||||
}],
|
},
|
||||||
|
{name:"minzoom",
|
||||||
|
doc: "How far the contributor must zoom in before being able to import the point",
|
||||||
|
defaultValue: "18"}],
|
||||||
docs: `This button will copy the data from an external dataset into OpenStreetMap. It is only functional in official themes but can be tested in unofficial themes.
|
docs: `This button will copy the data from an external dataset into OpenStreetMap. It is only functional in official themes but can be tested in unofficial themes.
|
||||||
|
|
||||||
If you want to import a dataset, make sure that:
|
If you want to import a dataset, make sure that:
|
||||||
|
@ -439,13 +442,13 @@ There are also some technicalities in your theme to keep in mind:
|
||||||
return newTags
|
return newTags
|
||||||
})
|
})
|
||||||
const id = tagSource.data.id;
|
const id = tagSource.data.id;
|
||||||
const feature = State.state.allElements.ContainingFeatures.get(id)
|
const feature = state.allElements.ContainingFeatures.get(id)
|
||||||
if (feature.geometry.type !== "Point") {
|
if (feature.geometry.type !== "Point") {
|
||||||
return new FixedUiElement("Error: can only import point objects").SetClass("alert")
|
return new FixedUiElement("Error: can only import point objects").SetClass("alert")
|
||||||
}
|
}
|
||||||
const [lon, lat] = feature.geometry.coordinates;
|
const [lon, lat] = feature.geometry.coordinates;
|
||||||
return new ImportButton(
|
return new ImportButton(
|
||||||
args[2], args[1], tagSource, rewrittenTags, lat, lon
|
args[2], args[1], tagSource, rewrittenTags, lat, lon, Number(args[3]), state
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,24 +37,29 @@
|
||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1043"
|
inkscape:window-height="1003"
|
||||||
id="namedview14"
|
id="namedview14"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
inkscape:zoom="7.375"
|
inkscape:zoom="7.375"
|
||||||
inkscape:cx="-1.3561062"
|
inkscape:cx="-1.3561062"
|
||||||
inkscape:cy="19.621117"
|
inkscape:cy="41.316032"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="862"
|
||||||
inkscape:window-y="0"
|
inkscape:window-y="1080"
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="1"
|
||||||
inkscape:current-layer="svg12" />
|
inkscape:current-layer="svg12" />
|
||||||
<path
|
<path
|
||||||
d="m 42.372766,41.559418 h 3.247468 c 0.421762,0 0.76133,0.339541 0.76133,0.761329 v 3.241506 c 0,0.421761 -0.339541,0.761329 -0.76133,0.761329 h -3.247468 c -0.421762,0 -0.76133,-0.339541 -0.76133,-0.761329 v -3.241506 c 0,-0.421761 0.339541,-0.761329 0.76133,-0.761329 z"
|
d="m 27.122405,19.186537 h 33.74819 c 4.383014,0 7.911859,3.528561 7.911859,7.911848 v 33.68623 c 0,4.383006 -3.528563,7.911848 -7.911859,7.911848 h -33.74819 c -4.383014,0 -7.911859,-3.528561 -7.911859,-7.911848 v -33.68623 c 0,-4.383006 3.528563,-7.911848 7.911859,-7.911848 z"
|
||||||
style="fill:#495aad;stroke-width:0.0542103;paint-order:normal"
|
style="fill:#495aad;stroke-width:0.56336182;paint-order:normal"
|
||||||
id="path6"
|
id="path6"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
<path
|
<path
|
||||||
d="m 42.085614,42.793949 v 2.289464 c 0.381581,0 0.763173,0.381581 0.763173,0.763173 h 2.289463 c 0,-0.381581 0.381581,-0.763173 0.763173,-0.763173 v -2.289464 c -0.381581,0 -0.763173,-0.381581 -0.763173,-0.763172 h -2.289463 c 0,0.38158 -0.381581,0.763172 -0.763173,0.763172 z"
|
d="m 24.138277,32.015973 v 23.792462 c 3.965449,0 7.931011,3.965449 7.931011,7.931014 h 23.792453 c 0,-3.965449 3.965449,-7.931014 7.931014,-7.931014 V 32.015973 c -3.965449,0 -7.931014,-3.965449 -7.931014,-7.931002 H 32.069288 c 0,3.965439 -3.965449,7.931002 -7.931011,7.931002 z"
|
||||||
id="path8"
|
id="path8"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:none;stroke:#ffffff;stroke-width:0.27187553" />
|
style="fill:none;stroke:#ffffff;stroke-width:2.8253727" />
|
||||||
|
<path
|
||||||
|
id="path3711"
|
||||||
|
d="m 44.16217,30.966164 c -7.526249,0 -13.627102,6.101307 -13.627102,13.627103 0,7.525795 6.101307,13.627102 13.627102,13.627102 7.525796,0 13.627103,-6.101307 13.627103,-13.627102 0,-7.525796 -6.101307,-13.627103 -13.627103,-13.627103 z m -3.168302,21.803364 -0.0091,-0.0091 -0.0077,0.0091 -6.353865,-6.541009 3.192832,-3.254153 3.16921,3.263237 9.53897,-9.820144 3.176933,3.269596 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#fdd835;stroke-width:0.45423675" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.8 KiB |
|
@ -39,14 +39,14 @@
|
||||||
{
|
{
|
||||||
"id": "to_import",
|
"id": "to_import",
|
||||||
"source": {
|
"source": {
|
||||||
"#geoJson": "http://127.0.0.1:8080/islington_small_piece.geojson",
|
"#geoJson": "https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/assets/themes/uk_addresses/islington_small_piece.geojson",
|
||||||
"geoJson": "https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/assets/themes/uk_addresses/islington_small_piece.geojson",
|
"geoJson": "https://osm-uk-addresses.russss.dev/addresses/{z}/{x}/{y}.json",
|
||||||
"##geoJson": "https://raw.githubusercontent.com/russss/osm-uk-addresses/main/output/islington.geojson",
|
|
||||||
"osmTags": "inspireid~*",
|
"osmTags": "inspireid~*",
|
||||||
|
"geoJsonZoomLevel": 16,
|
||||||
"isOsmCache": false
|
"isOsmCache": false
|
||||||
},
|
},
|
||||||
"name": "Addresses to check",
|
"name": "Addresses to check",
|
||||||
"minzoom": 12,
|
"minzoom": 14,
|
||||||
"wayHandling": 1,
|
"wayHandling": 1,
|
||||||
"icon": {
|
"icon": {
|
||||||
"render": "./assets/themes/uk_addresses/housenumber_unknown.svg",
|
"render": "./assets/themes/uk_addresses/housenumber_unknown.svg",
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"calculatedTags": [
|
"calculatedTags": [
|
||||||
"_closest_3_street_names=feat.closestn('named_streets',3, 'name').map(f => ({name: f.feat.properties.name, distance: Math.round(1000*f.distance), id: f.id}))",
|
"_closest_3_street_names=feat.properties['addr:street'] === undefined ? feat.closestn('named_streets',3, 'name').map(f => ({name: f.feat.properties.name, distance: Math.round(1000*f.distance), id: f.id})) : []",
|
||||||
"_closest_street:0:name=JSON.parse(feat.properties._closest_3_street_names)[0]?.name",
|
"_closest_street:0:name=JSON.parse(feat.properties._closest_3_street_names)[0]?.name",
|
||||||
"_closest_street:1:name=JSON.parse(feat.properties._closest_3_street_names)[1]?.name",
|
"_closest_street:1:name=JSON.parse(feat.properties._closest_3_street_names)[1]?.name",
|
||||||
"_closest_street:2:name=JSON.parse(feat.properties._closest_3_street_names)[2]?.name",
|
"_closest_street:2:name=JSON.parse(feat.properties._closest_3_street_names)[2]?.name",
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
"uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>",
|
"uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>",
|
||||||
"dontDelete": "Cancel",
|
"dontDelete": "Cancel",
|
||||||
"doDelete": "Remove image",
|
"doDelete": "Remove image",
|
||||||
"isDeleted": "Deleted",
|
"isDeleted": "Deleted"
|
||||||
"hasBeenImported": "This feature has been imported"
|
|
||||||
},
|
},
|
||||||
"centerMessage": {
|
"centerMessage": {
|
||||||
"loadingData": "Loading data…",
|
"loadingData": "Loading data…",
|
||||||
|
@ -103,7 +102,8 @@
|
||||||
"confirmButton": "Add a {category} here.<br/><div class='alert'>Your addition is visible for everyone</div>",
|
"confirmButton": "Add a {category} here.<br/><div class='alert'>Your addition is visible for everyone</div>",
|
||||||
"openLayerControl": "Open the layer control box",
|
"openLayerControl": "Open the layer control box",
|
||||||
"layerNotEnabled": "The layer {layer} is not enabled. Enable this layer to add a point",
|
"layerNotEnabled": "The layer {layer} is not enabled. Enable this layer to add a point",
|
||||||
"hasBeenImported": "This point has already been imported"
|
"hasBeenImported": "This point has already been imported",
|
||||||
|
"zoomInMore": "Zoom in more to import this feature"
|
||||||
},
|
},
|
||||||
"pickLanguage": "Choose a language: ",
|
"pickLanguage": "Choose a language: ",
|
||||||
"about": "Easily edit and add OpenStreetMap for a certain theme",
|
"about": "Easily edit and add OpenStreetMap for a certain theme",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue