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){ | ||||
|         const key = `${SaveTileToLocalStorageActor.storageKey}-${layerId}-${tileId}` | ||||
|         localStorage.setItem(key + "-time", JSON.stringify(freshness.getTime())) | ||||
|         localStorage.setItem(key + "-format", SaveTileToLocalStorageActor.formatVersion) | ||||
|         try{ | ||||
|             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, | ||||
|                 registerTile: (tile) => { | ||||
|                     // 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)) | ||||
|                     tile.features.addCallbackAndRunD(_ => self.newDataLoadedSignal.setData(tile)) | ||||
| 
 | ||||
|  | @ -239,7 +241,11 @@ export default class FeaturePipeline { | |||
| 
 | ||||
| 
 | ||||
|         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) { | ||||
|                     if (self.downloadedTiles.has(neededTile)) { | ||||
|                         return; | ||||
|                         continue; | ||||
|                     } | ||||
|                     console.log("Tile download", Tiles.tile_from_index(neededTile).join("/"), "started") | ||||
|                     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) { | ||||
|                 console.error(e) | ||||
|             }finally { | ||||
|                 console.log("Done") | ||||
|                 self.isRunning.setData(false) | ||||
|             } | ||||
|             self.isRunning.setData(false) | ||||
|         }) | ||||
| 
 | ||||
| 
 | ||||
|         const neededLayers = options.state.layoutToUse.layers | ||||
|             .filter(            layer => !layer.doNotDownload        ) | ||||
|             .filter(layer => !layer.doNotDownload) | ||||
|             .filter(layer => layer.source.geojsonSource === undefined || layer.source.isOsmCacheLayer) | ||||
|         this.allowedTags = new Or(neededLayers.map(l => l.source.osmTags)) | ||||
|     } | ||||
|  | @ -103,15 +107,15 @@ export default class OsmFeatureSource { | |||
|                 geojson.features = geojson.features.filter(feature => this.allowedTags.matchesProperties(feature.properties)) | ||||
| 
 | ||||
|                 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, | ||||
|                     this.handleTile, | ||||
|                     new StaticFeatureSource(geojson.features, false), | ||||
|                     { | ||||
|                         tileIndex:index | ||||
|                         tileIndex: index | ||||
|                     } | ||||
|                 ); | ||||
|                 if(this.options.markTileVisited){ | ||||
|                 if (this.options.markTileVisited) { | ||||
|                     this.options.markTileVisited(index) | ||||
|                 } | ||||
|             } catch (e) { | ||||
|  |  | |||
|  | @ -9,11 +9,17 @@ import Constants from "../../Models/Constants"; | |||
| import Toggle from "../Input/Toggle"; | ||||
| import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction"; | ||||
| import {Tag} from "../../Logic/Tags/Tag"; | ||||
| import Loading from "../Base/Loading"; | ||||
| 
 | ||||
| export default class ImportButton extends Toggle { | ||||
|     constructor(imageUrl: string | BaseUIElement, message: string | BaseUIElement, | ||||
|                 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 isImported = originalTags.map(tags => tags._imported === "yes") | ||||
|         const appliedTags = new Toggle( | ||||
|  | @ -30,6 +36,7 @@ export default class ImportButton extends Toggle { | |||
|         ) | ||||
|         const button = new SubtleButton(imageUrl, message) | ||||
| 
 | ||||
|         minZoom = Math.max(16, minZoom ?? 19) | ||||
| 
 | ||||
|         button.onClick(async () => { | ||||
|             if (isImported.data) { | ||||
|  | @ -49,11 +56,13 @@ export default class ImportButton extends Toggle { | |||
| 
 | ||||
|         }) | ||||
| 
 | ||||
|         const withLoadingCheck = new Toggle( | ||||
|             t.stillLoading, | ||||
|         const withLoadingCheck = new Toggle(new Toggle( | ||||
|             new Loading(t.stillLoading.Clone()), | ||||
|             new Combine([button, appliedTags]).SetClass("flex flex-col"), | ||||
|             State.state.featurePipeline.runningQuery | ||||
|         ) | ||||
|         ),t.zoomInFurther.Clone(), | ||||
|                 state.locationControl.map(l => l.zoom >= minZoom)     | ||||
|             ) | ||||
|         const importButton = new Toggle(t.hasBeenImported, withLoadingCheck, isImported) | ||||
| 
 | ||||
|         const pleaseLoginButton = | ||||
|  |  | |||
|  | @ -396,7 +396,10 @@ export default class SpecialVisualizations { | |||
|                         name: "icon", | ||||
|                         doc: "A nice icon to show in the button", | ||||
|                         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.
 | ||||
| 
 | ||||
| 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 | ||||
|                     }) | ||||
|                     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") { | ||||
|                         return new FixedUiElement("Error: can only import point objects").SetClass("alert") | ||||
|                     } | ||||
|                     const [lon, lat] = feature.geometry.coordinates; | ||||
|                     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:pageshadow="2" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="1043" | ||||
|      inkscape:window-height="1003" | ||||
|      id="namedview14" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="7.375" | ||||
|      inkscape:cx="-1.3561062" | ||||
|      inkscape:cy="19.621117" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="0" | ||||
|      inkscape:cy="41.316032" | ||||
|      inkscape:window-x="862" | ||||
|      inkscape:window-y="1080" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="svg12" /> | ||||
|   <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" | ||||
|      style="fill:#495aad;stroke-width:0.0542103;paint-order:normal" | ||||
|      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.56336182;paint-order:normal" | ||||
|      id="path6" | ||||
|      inkscape:connector-curvature="0" /> | ||||
|   <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" | ||||
|      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> | ||||
|  |  | |||
| Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.8 KiB | 
|  | @ -39,14 +39,14 @@ | |||
|     { | ||||
|       "id": "to_import", | ||||
|       "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/russss/osm-uk-addresses/main/output/islington.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", | ||||
|         "osmTags": "inspireid~*", | ||||
|         "geoJsonZoomLevel": 16, | ||||
|         "isOsmCache": false | ||||
|       }, | ||||
|       "name": "Addresses to check", | ||||
|       "minzoom": 12, | ||||
|       "minzoom": 14, | ||||
|       "wayHandling": 1, | ||||
|       "icon": { | ||||
|         "render": "./assets/themes/uk_addresses/housenumber_unknown.svg", | ||||
|  | @ -122,7 +122,7 @@ | |||
|         } | ||||
|       }, | ||||
|       "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: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", | ||||
|  |  | |||
|  | @ -13,8 +13,7 @@ | |||
|         "uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>", | ||||
|         "dontDelete": "Cancel", | ||||
|         "doDelete": "Remove image", | ||||
|         "isDeleted": "Deleted", | ||||
|         "hasBeenImported": "This feature has been imported" | ||||
|         "isDeleted": "Deleted" | ||||
|     }, | ||||
|     "centerMessage": { | ||||
|         "loadingData": "Loading data…", | ||||
|  | @ -103,7 +102,8 @@ | |||
|             "confirmButton": "Add a {category} here.<br/><div class='alert'>Your addition is visible for everyone</div>", | ||||
|             "openLayerControl": "Open the layer control box", | ||||
|             "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: ", | ||||
|         "about": "Easily edit and add OpenStreetMap for a certain theme", | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue