| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | import L 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-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-25 21:58:29 +02:00
										 |  |  |     public static readonly defaultLayer: { name: string, layer: any, id: string } = | 
					
						
							|  |  |  |         Basemap.CreateBackgroundLayer("osm", "OpenStreetMap", "https://tile.openstreetmap.org/{z}/{x}/{y}.png", | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |             "OpenStreetMap (ODBL)", 'https://openstreetmap.org/copyright', | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |             22, false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-25 21:58:29 +02:00
										 |  |  |     private _previousLayer: L.tileLayer = undefined; | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     public readonly CurrentLayer: UIEventSource<{ | 
					
						
							| 
									
										
										
										
											2020-08-07 20:50:46 +02:00
										 |  |  |         id: string, | 
					
						
							| 
									
										
										
										
											2020-07-22 14:46:43 +02:00
										 |  |  |         name: string, | 
					
						
							|  |  |  |         layer: L.tileLayer | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |     }> = new UIEventSource<L.tileLayer>(Basemap.defaultLayer); | 
					
						
							| 
									
										
										
										
											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-25 21:58:29 +02:00
										 |  |  |         this._previousLayer = Basemap.defaultLayer.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-07-22 15:17:29 +02:00
										 |  |  |          | 
					
						
							|  |  |  |         this.CurrentLayer.addCallback((layer:{layer: L.tileLayer}) => { | 
					
						
							|  |  |  |             if(self._previousLayer !== undefined){ | 
					
						
							|  |  |  |                 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-25 21:58:29 +02:00
										 |  |  |                                         maxZoom: number, isWms: boolean, isWMTS?: boolean) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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-25 21:58:29 +02:00
										 |  |  |             return { | 
					
						
							|  |  |  |                 id: id, | 
					
						
							|  |  |  |                 name: name, | 
					
						
							| 
									
										
										
										
											2020-09-27 18:45:37 +02:00
										 |  |  |                 layer: 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-25 21:58:29 +02:00
										 |  |  |         return { | 
					
						
							|  |  |  |             id: id, | 
					
						
							|  |  |  |             name: name, | 
					
						
							|  |  |  |             layer: L.tileLayer(url, | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     attribution: attribution, | 
					
						
							|  |  |  |                     maxZoom: maxZoom, | 
					
						
							|  |  |  |                     minZoom: 1, | 
					
						
							| 
									
										
										
										
											2020-09-27 01:38:51 +02:00
										 |  |  |                     wmts: isWMTS ?? false, | 
					
						
							|  |  |  |                     subdomains: domains | 
					
						
							| 
									
										
										
										
											2020-09-25 21:58:29 +02:00
										 |  |  |                 }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | } |