forked from MapComplete/MapComplete
		
	Add smoothness, add highlighting of a way
This commit is contained in:
		
							parent
							
								
									8af25a9cdf
								
							
						
					
					
						commit
						afaaaaadb1
					
				
					 12 changed files with 146 additions and 12 deletions
				
			
		|  | @ -10,6 +10,7 @@ import {MetaMap} from "./Layouts/MetaMap"; | ||||||
| import {StreetWidth} from "./Layouts/StreetWidth"; | import {StreetWidth} from "./Layouts/StreetWidth"; | ||||||
| import {Natuurpunt} from "./Layouts/Natuurpunt"; | import {Natuurpunt} from "./Layouts/Natuurpunt"; | ||||||
| import {ClimbingTrees} from "./Layouts/ClimbingTrees"; | import {ClimbingTrees} from "./Layouts/ClimbingTrees"; | ||||||
|  | import {Smoothness} from "./Layouts/Smoothness"; | ||||||
| 
 | 
 | ||||||
| export class AllKnownLayouts { | export class AllKnownLayouts { | ||||||
|     public static allSets = AllKnownLayouts.AllLayouts(); |     public static allSets = AllKnownLayouts.AllLayouts(); | ||||||
|  | @ -25,9 +26,9 @@ export class AllKnownLayouts { | ||||||
|             new StreetWidth(), |             new StreetWidth(), | ||||||
|             new Natuurpunt(), |             new Natuurpunt(), | ||||||
|             new ClimbingTrees(), |             new ClimbingTrees(), | ||||||
|             new Artworks() |             new Artworks(), | ||||||
|  |             new Smoothness() | ||||||
|             /*new Toilets(), |             /*new Toilets(), | ||||||
|             new Statues(), |  | ||||||
|             */ |             */ | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -69,6 +69,7 @@ export class LayerDefinition { | ||||||
|      */ |      */ | ||||||
|     style: (tags: any) => { |     style: (tags: any) => { | ||||||
|         color: string, |         color: string, | ||||||
|  |         weight?: number, | ||||||
|         icon: {  |         icon: {  | ||||||
|             iconUrl: string, |             iconUrl: string, | ||||||
|             iconSize: number[], |             iconSize: number[], | ||||||
|  |  | ||||||
|  | @ -171,7 +171,7 @@ export class Widths extends LayerDefinition { | ||||||
|             return { |             return { | ||||||
|                 icon: null, |                 icon: null, | ||||||
|                 color: c, |                 color: c, | ||||||
|                 weight: 7, |                 weight: 10, | ||||||
|                 dashArray: dashArray |                 dashArray: dashArray | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -39,6 +39,12 @@ export class Layout { | ||||||
|      |      | ||||||
|     public hideFromOverview : boolean = false; |     public hideFromOverview : boolean = false; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * The BBOX of the currently visible map are widened by this factor, in order to make some panning possible. | ||||||
|  |      * This number influences this | ||||||
|  |      */ | ||||||
|  |     public widenFactor : number = 0.07; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      *  |      *  | ||||||
|      * @param name: The name used in the query string. If in the query "quests=<name>" is defined, it will select this layout |      * @param name: The name used in the query string. If in the query "quests=<name>" is defined, it will select this layout | ||||||
|  | @ -128,7 +134,7 @@ export class WelcomeMessage extends UIElement { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected InnerUpdate(htmlElement: HTMLElement) { |     protected InnerUpdate(htmlElement: HTMLElement) { | ||||||
|         this.osmConnection.registerActivateOsmAUthenticationClass() |         this.osmConnection?.registerActivateOsmAUthenticationClass() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										81
									
								
								Customizations/Layouts/Smoothness.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Customizations/Layouts/Smoothness.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | ||||||
|  | import {Layout} from "../Layout"; | ||||||
|  | import {LayerDefinition} from "../LayerDefinition"; | ||||||
|  | import {Or, Tag} from "../../Logic/TagsFilter"; | ||||||
|  | import {TagRenderingOptions} from "../TagRendering"; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export class SmoothnessLayer extends LayerDefinition { | ||||||
|  | 
 | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         this.name = "smoothness"; | ||||||
|  |         this.minzoom = 17; | ||||||
|  |         this.overpassFilter = new Or([ | ||||||
|  |             new Tag("highway", "residential"), | ||||||
|  |             new Tag("highway", "cycleway"), | ||||||
|  |             new Tag("highway", "footway"), | ||||||
|  |             new Tag("highway", "path"), | ||||||
|  |             new Tag("highway", "tertiary") | ||||||
|  |         ]); | ||||||
|  |          | ||||||
|  |         this.elementsToShow = [ | ||||||
|  |             new TagRenderingOptions({ | ||||||
|  |                 question: "How smooth is this road to rollerskate on", | ||||||
|  |                 mappings: [ | ||||||
|  |                     {k: new Tag("smoothness","bad"), txt: "It's horrible"}, | ||||||
|  |                     {k: new Tag("smoothness","intermediate"), txt: "It is passable by rollerscate, but only if you have to"}, | ||||||
|  |                     {k: new Tag("smoothness","good"), txt: "Good, but it has some friction or holes"}, | ||||||
|  |                     {k: new Tag("smoothness","very_good"), txt: "Quite good and enjoyable"}, | ||||||
|  |                     {k: new Tag("smoothness","excellent"), txt: "Excellent - this is where you'd want to drive 24/7"}, | ||||||
|  |                 ] | ||||||
|  |             }) | ||||||
|  |         ] | ||||||
|  |          | ||||||
|  |         this.style = (properties) => { | ||||||
|  |             let color = "#000000"; | ||||||
|  |             if(new Tag("smoothness","bad").matchesProperties(properties)){ | ||||||
|  |                 color = "#ff0000"; | ||||||
|  |             } | ||||||
|  |             if(new Tag("smoothness","intermediate").matchesProperties(properties)){ | ||||||
|  |                 color = "#ffaa00"; | ||||||
|  |             } | ||||||
|  |             if(new Tag("smoothness","good").matchesProperties(properties)){ | ||||||
|  |                 color = "#ccff00"; | ||||||
|  |             } | ||||||
|  |             if(new Tag("smoothness","very_good").matchesProperties(properties)){ | ||||||
|  |                 color = "#00aa00"; | ||||||
|  |             } | ||||||
|  |             if(new Tag("smoothness","excellent").matchesProperties(properties)){ | ||||||
|  |                 color = "#00ff00"; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             return { | ||||||
|  |                 color: color, | ||||||
|  |                 icon: undefined, | ||||||
|  |                 weight: 8 | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class Smoothness extends Layout { | ||||||
|  |     constructor() { | ||||||
|  |         super( | ||||||
|  |             "smoothness", | ||||||
|  |             ["en"   ], | ||||||
|  |             "Smoothness while rollerskating", | ||||||
|  |             [new SmoothnessLayer()], | ||||||
|  |             17, | ||||||
|  |             51.2, | ||||||
|  |             3.2, | ||||||
|  |             "Give smoothness feedback for rollerskating" | ||||||
|  |         ); | ||||||
|  |         this.widenFactor = 0.005 | ||||||
|  |         this.hideFromOverview = true; | ||||||
|  |         this.enableAdd = false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -28,7 +28,7 @@ export class FilteredLayer { | ||||||
|     private readonly _map: Basemap; |     private readonly _map: Basemap; | ||||||
|     private readonly _maxAllowedOverlap: number; |     private readonly _maxAllowedOverlap: number; | ||||||
| 
 | 
 | ||||||
|     private readonly _style: (properties) => { color: string, icon: { iconUrl: string, iconSize? : number[], popupAnchor?: number[], iconAnchor?:number[] } }; |     private readonly _style: (properties) => { color: string, weight?: number, icon: { iconUrl: string, iconSize? : number[], popupAnchor?: number[], iconAnchor?:number[] } }; | ||||||
| 
 | 
 | ||||||
|     private readonly _storage: ElementStorage; |     private readonly _storage: ElementStorage; | ||||||
| 
 | 
 | ||||||
|  | @ -239,19 +239,37 @@ export class FilteredLayer { | ||||||
|             }, |             }, | ||||||
| 
 | 
 | ||||||
|             onEachFeature: function (feature, layer) { |             onEachFeature: function (feature, layer) { | ||||||
|                 let eventSource = self._storage.addOrGetElement(feature); | 
 | ||||||
|                 eventSource.addCallback(function () { |                 feature.updateStyle = () => { | ||||||
|                     if (layer.setIcon) { |                     if (layer.setIcon) { | ||||||
|                         layer.setIcon(L.icon(self._style(feature.properties).icon)) |                         layer.setIcon(L.icon(self._style(feature.properties).icon)) | ||||||
|                     } else { |                     } else { | ||||||
|                         self._geolayer.setStyle(function (feature) { |                         self._geolayer.setStyle(function (feature) { | ||||||
|                             return self._style(feature.properties); |                             const style = self._style(feature.properties); | ||||||
|  |                             if (self._selectedElement.data?.feature === feature) { | ||||||
|  |                                 if (style.weight !== undefined) { | ||||||
|  |                                     style.weight = style.weight * 2; | ||||||
|  |                                 }else{ | ||||||
|  |                                     style.weight = 20; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                             return style; | ||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
|                 }); |                 } | ||||||
|  | 
 | ||||||
|  |                 let eventSource = self._storage.addOrGetElement(feature); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |                 eventSource.addCallback(feature.updateStyle); | ||||||
| 
 | 
 | ||||||
|                 layer.on("click", function (e) { |                 layer.on("click", function (e) { | ||||||
|  |                     const previousFeature = self._selectedElement.data?.feature; | ||||||
|                     self._selectedElement.setData({feature: feature}); |                     self._selectedElement.setData({feature: feature}); | ||||||
|  |                     feature.updateStyle(); | ||||||
|  |                     previousFeature?.updateStyle(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|                     if (feature.geometry.type === "Point") { |                     if (feature.geometry.type === "Point") { | ||||||
|                         return; // Points bind there own popups
 |                         return; // Points bind there own popups
 | ||||||
|                     } |                     } | ||||||
|  | @ -267,7 +285,6 @@ export class FilteredLayer { | ||||||
|                     uiElement.Update(); |                     uiElement.Update(); | ||||||
|                     uiElement.Activate(); |                     uiElement.Activate(); | ||||||
|                     L.DomEvent.stop(e); // Marks the event as consumed
 |                     L.DomEvent.stop(e); // Marks the event as consumed
 | ||||||
| 
 |  | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ import {Basemap} from "./Leaflet/Basemap"; | ||||||
| export class LayerUpdater { | export class LayerUpdater { | ||||||
|     private _map: Basemap; |     private _map: Basemap; | ||||||
|     private _layers: FilteredLayer[]; |     private _layers: FilteredLayer[]; | ||||||
|  |     private widenFactor: number; | ||||||
| 
 | 
 | ||||||
|     public readonly runningQuery: UIEventSource<boolean> = new UIEventSource<boolean>(false); |     public readonly runningQuery: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
|     public readonly retries: UIEventSource<number> = new UIEventSource<number>(0); |     public readonly retries: UIEventSource<number> = new UIEventSource<number>(0); | ||||||
|  | @ -27,7 +28,9 @@ export class LayerUpdater { | ||||||
|      */ |      */ | ||||||
|     constructor(map: Basemap, |     constructor(map: Basemap, | ||||||
|                 minzoom: number, |                 minzoom: number, | ||||||
|  |                 widenFactor: number, | ||||||
|                 layers: FilteredLayer[]) { |                 layers: FilteredLayer[]) { | ||||||
|  |         this.widenFactor = widenFactor; | ||||||
|         this._map = map; |         this._map = map; | ||||||
|         this._layers = layers; |         this._layers = layers; | ||||||
|         this._minzoom = minzoom; |         this._minzoom = minzoom; | ||||||
|  | @ -97,7 +100,7 @@ export class LayerUpdater { | ||||||
|          |          | ||||||
|         const bounds = this._map.map.getBounds(); |         const bounds = this._map.map.getBounds(); | ||||||
| 
 | 
 | ||||||
|         const diff =0.07; |         const diff = this.widenFactor; | ||||||
| 
 | 
 | ||||||
|         const n = bounds.getNorth() + diff; |         const n = bounds.getNorth() + diff; | ||||||
|         const e = bounds.getEast() +  diff; |         const e = bounds.getEast() +  diff; | ||||||
|  |  | ||||||
|  | @ -91,6 +91,8 @@ export class OsmConnection { | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             self.UpdatePreferences(); |             self.UpdatePreferences(); | ||||||
|  |             self.CheckForMessagesContinuously(); | ||||||
|  |              | ||||||
|             // details is an XML DOM of user details
 |             // details is an XML DOM of user details
 | ||||||
|             let userInfo = details.getElementsByTagName("user")[0]; |             let userInfo = details.getElementsByTagName("user")[0]; | ||||||
| 
 | 
 | ||||||
|  | @ -120,9 +122,21 @@ export class OsmConnection { | ||||||
|             data.unreadMessages = parseInt(messages.getAttribute("unread")); |             data.unreadMessages = parseInt(messages.getAttribute("unread")); | ||||||
|             data.totalMessages = parseInt(messages.getAttribute("count")); |             data.totalMessages = parseInt(messages.getAttribute("count")); | ||||||
|             self.userDetails.ping(); |             self.userDetails.ping(); | ||||||
|  |            | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     private CheckForMessagesContinuously() { | ||||||
|  |         const self = this; | ||||||
|  |         window.setTimeout(() => { | ||||||
|  |             if (self.userDetails.data.loggedIn) { | ||||||
|  |                 console.log("Checking for messages") | ||||||
|  |                 this.AttemptLogin(); | ||||||
|  |             } | ||||||
|  |         },  5 * 60 * 1000); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * All elements with class 'activate-osm-authentication' are loaded and get an 'onclick' to authenticate |      * All elements with class 'activate-osm-authentication' are loaded and get an 'onclick' to authenticate | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|  | @ -52,6 +52,7 @@ export class MoreScreen extends UIElement { | ||||||
| 
 | 
 | ||||||
|         return new VerticalCombine([ |         return new VerticalCombine([ | ||||||
|             tr.intro, |             tr.intro, | ||||||
|  |             tr.requestATheme, | ||||||
|             new VerticalCombine(els), |             new VerticalCombine(els), | ||||||
|             tr.streetcomplete |             tr.streetcomplete | ||||||
|         ]).Render(); |         ]).Render(); | ||||||
|  |  | ||||||
|  | @ -924,6 +924,12 @@ export default class Translations { | ||||||
|                     fr: "<h3>Plus de thème </h3>Vous aimez collecter des données? <br/>Il y a plus de thèmes disponible.", |                     fr: "<h3>Plus de thème </h3>Vous aimez collecter des données? <br/>Il y a plus de thèmes disponible.", | ||||||
|                     nl: "<h3>Meer thema's</h3>Vind je het leuk om geodata te verzamelen? <br/> Hier vind je meer opties." |                     nl: "<h3>Meer thema's</h3>Vind je het leuk om geodata te verzamelen? <br/> Hier vind je meer opties." | ||||||
|                 }), |                 }), | ||||||
|  |                  | ||||||
|  |                 requestATheme: new T({ | ||||||
|  |                     en: "If you want a custom-built quest, request it <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>here</a>", | ||||||
|  |                     nl: "Wil je een eigen kaartthema, vraag dit <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>hier aan</a>" | ||||||
|  |                 }), | ||||||
|  | 
 | ||||||
|                 streetcomplete: new T({ |                 streetcomplete: new T({ | ||||||
|                     en: "Another, similar application is <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>", |                     en: "Another, similar application is <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>", | ||||||
|                     fr: "Une autre application similaire est <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>", |                     fr: "Une autre application similaire est <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>", | ||||||
|  |  | ||||||
|  | @ -54,6 +54,10 @@ form { | ||||||
|     display: block; |     display: block; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .selected-element { | ||||||
|  |     fill: black | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**************** GENERIC ****************/ | /**************** GENERIC ****************/ | ||||||
| 
 | 
 | ||||||
| .uielement { | .uielement { | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								index.ts
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								index.ts
									
										
									
									
									
								
							|  | @ -186,7 +186,7 @@ const bm = new Basemap("leafletDiv", locationControl, new VariableUiElement( | ||||||
| 
 | 
 | ||||||
| const layerSetup = InitUiElements.InitLayers(layoutToUse, osmConnection, changes, allElements, bm, fullScreenMessage, selectedElement); | const layerSetup = InitUiElements.InitLayers(layoutToUse, osmConnection, changes, allElements, bm, fullScreenMessage, selectedElement); | ||||||
| 
 | 
 | ||||||
| const layerUpdater = new LayerUpdater(bm, layerSetup.minZoom, layerSetup.flayers); | const layerUpdater = new LayerUpdater(bm, layerSetup.minZoom, layoutToUse.widenFactor, layerSetup.flayers); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // --------------- Setting up layer selection ui --------
 | // --------------- Setting up layer selection ui --------
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue