| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  | import * as L from "leaflet" | 
					
						
							| 
									
										
										
										
											2020-09-27 23:37:47 +02:00
										 |  |  | import * as X from "leaflet-providers" | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  | import {TileLayer} from "leaflet" | 
					
						
							| 
									
										
										
										
											2020-08-17 17:23:15 +02:00
										 |  |  | import {UIEventSource} from "../UIEventSource"; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | import {UIElement} from "../../UI/UIElement"; | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  | import {BaseLayer} from "../BaseLayer"; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-22 14:46:43 +02:00
										 |  |  | // Contains all setup and baselayers for Leaflet stuff
 | 
					
						
							|  |  |  | export class Basemap { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |     public static osmCarto: BaseLayer = | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             id: "osm", | 
					
						
							|  |  |  |             //max_zoom: 19, 
 | 
					
						
							|  |  |  |             name: "OpenStreetMap", | 
					
						
							|  |  |  |             layer: Basemap.CreateBackgroundLayer("osm", "OpenStreetMap", | 
					
						
							|  |  |  |                 "https://tile.openstreetmap.org/{z}/{x}/{y}.png", "OpenStreetMap", "https://openStreetMap.org/copyright", | 
					
						
							|  |  |  |                 19, | 
					
						
							|  |  |  |                 false, false), | 
					
						
							|  |  |  |             feature: null, | 
					
						
							|  |  |  |             max_zoom: 19, | 
					
						
							|  |  |  |             min_zoom: 0 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-22 14:46:43 +02:00
										 |  |  |     // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     public readonly map: Map; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     public readonly Location: UIEventSource<{ zoom: number, lat: number, lon: number }>; | 
					
						
							|  |  |  |     public readonly LastClickLocation: UIEventSource<{ lat: number, lon: number }> = new UIEventSource<{ lat: number, lon: number }>(undefined) | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |     private _previousLayer: TileLayer = undefined; | 
					
						
							|  |  |  |     public readonly CurrentLayer: UIEventSource<BaseLayer> = new UIEventSource(Basemap.osmCarto); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 03:12:44 +02:00
										 |  |  |     constructor(leafletElementId: string, | 
					
						
							|  |  |  |                 location: UIEventSource<{ zoom: number, lat: number, lon: number }>, | 
					
						
							|  |  |  |                 extraAttribution: UIElement) { | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |         this._previousLayer = Basemap.osmCarto.layer; | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  |         this.map = L.map(leafletElementId, { | 
					
						
							| 
									
										
										
										
											2020-08-26 20:11:43 +02:00
										 |  |  |             center: [location.data.lat ?? 0, location.data.lon ?? 0], | 
					
						
							|  |  |  |             zoom: location.data.zoom ?? 2, | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |             layers: [this._previousLayer], | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-07-22 15:17:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |         // Users are not allowed to zoom to the 'copies' on the left and the right, stuff goes wrong then
 | 
					
						
							|  |  |  |         // We give a bit of leeway for people on the edges
 | 
					
						
							|  |  |  |         // Also see: https://www.reddit.com/r/openstreetmap/comments/ih4zzc/mapcomplete_a_new_easytouse_editor/g31ubyv/
 | 
					
						
							|  |  |  |         this.map.setMaxBounds( | 
					
						
							|  |  |  |             [[-100,-200],[100,200]] | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-06-29 03:40:19 +02:00
										 |  |  |         this.map.attributionControl.setPrefix( | 
					
						
							|  |  |  |             extraAttribution.Render() + " | <a href='https://osm.org'>OpenStreetMap</a>"); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         this.Location = location; | 
					
						
							| 
									
										
										
										
											2020-06-29 03:12:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-28 00:06:23 +02:00
										 |  |  |         this.map.zoomControl.setPosition("bottomright"); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         this.map.on("moveend", function () { | 
					
						
							|  |  |  |             location.data.zoom = self.map.getZoom(); | 
					
						
							|  |  |  |             location.data.lat = self.map.getCenter().lat; | 
					
						
							| 
									
										
										
										
											2020-06-29 03:12:44 +02:00
										 |  |  |             location.data.lon = self.map.getCenter().lng; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             location.ping(); | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.CurrentLayer.addCallback((layer: BaseLayer) => { | 
					
						
							|  |  |  |             if (self._previousLayer !== undefined) { | 
					
						
							| 
									
										
										
										
											2020-07-22 15:17:29 +02:00
										 |  |  |                 self.map.removeLayer(self._previousLayer); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             self._previousLayer = layer.layer; | 
					
						
							|  |  |  |             self.map.addLayer(layer.layer); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 03:12:44 +02:00
										 |  |  |         this.map.on("click", function (e) { | 
					
						
							|  |  |  |             self.LastClickLocation.setData({lat: e.latlng.lat, lon: e.latlng.lng}) | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-09-05 18:40:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.map.on("contextmenu", function (e) { | 
					
						
							|  |  |  |             self.LastClickLocation.setData({lat: e.latlng.lat, lon: e.latlng.lng}); | 
					
						
							|  |  |  |             e.preventDefault(); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |     public static CreateBackgroundLayer(id: string, name: string, url: string, attribution: string, attributionUrl: string, | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |                                         maxZoom: number, isWms: boolean, isWMTS?: boolean): TileLayer { | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         url = url.replace("{zoom}", "{z}") | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |             .replace("&BBOX={bbox}", "") | 
					
						
							|  |  |  |             .replace("&bbox={bbox}", ""); | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 01:38:51 +02:00
										 |  |  |         const subdomainsMatch = url.match(/{switch:[^}]*}/) | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |         let domains: string[] = []; | 
					
						
							| 
									
										
										
										
											2020-09-27 01:38:51 +02:00
										 |  |  |         if (subdomainsMatch !== null) { | 
					
						
							|  |  |  |             let domainsStr = subdomainsMatch[0].substr("{switch:".length); | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |             domainsStr = domainsStr.substr(0, domainsStr.length - 1); | 
					
						
							| 
									
										
										
										
											2020-09-27 01:38:51 +02:00
										 |  |  |             domains = domainsStr.split(","); | 
					
						
							|  |  |  |             url = url.replace(/{switch:[^}]*}/, "{s}") | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |         if (isWms) { | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |             url = url.replace("&SRS={proj}",""); | 
					
						
							|  |  |  |             url = url.replace("&srs={proj}",""); | 
					
						
							|  |  |  |             const paramaters = ["format", "layers", "version", "service", "request", "styles", "transparent", "version"]; | 
					
						
							|  |  |  |             const urlObj = new URL(url); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const isUpper = urlObj.searchParams["LAYERS"] !== null; | 
					
						
							|  |  |  |             const options = { | 
					
						
							|  |  |  |                 maxZoom: maxZoom ?? 19, | 
					
						
							|  |  |  |                 attribution: attribution + " | ", | 
					
						
							|  |  |  |                 subdomains: domains, | 
					
						
							|  |  |  |                 uppercase: isUpper, | 
					
						
							|  |  |  |                 transparent: false | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const paramater of paramaters) { | 
					
						
							|  |  |  |                 let p = paramater; | 
					
						
							|  |  |  |                 if (isUpper) { | 
					
						
							|  |  |  |                     p = paramater.toUpperCase(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 options[paramater] = urlObj.searchParams.get(p); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if(options.transparent === null){ | 
					
						
							|  |  |  |                 options.transparent = false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |             return L.tileLayer.wms(urlObj.protocol + "//" + urlObj.host + urlObj.pathname, options); | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |         if (attributionUrl) { | 
					
						
							|  |  |  |             attribution = `<a href='${attributionUrl}' target='_blank'>${attribution}</a>`; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |         return L.tileLayer(url, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 attribution: attribution, | 
					
						
							|  |  |  |                 maxZoom: maxZoom, | 
					
						
							|  |  |  |                 minZoom: 1, | 
					
						
							|  |  |  |                 // @ts-ignore
 | 
					
						
							|  |  |  |                 wmts: isWMTS ?? false, | 
					
						
							|  |  |  |                 subdomains: domains | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |     public static ProvidedLayer(name: string, options?: any): any { | 
					
						
							| 
									
										
										
										
											2020-09-27 23:37:47 +02:00
										 |  |  |         X // We simply 'call' the namespace X here to force the import to run and not to be optimized away
 | 
					
						
							|  |  |  |         // @ts-ignore
 | 
					
						
							|  |  |  |         return L.tileLayer.provider(name, options); | 
					
						
							| 
									
										
										
										
											2020-09-27 22:48:43 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | } |