diff --git a/assets/leaflet-providers.json b/assets/leaflet-providers.json
new file mode 100644
index 0000000..3cfca29
--- /dev/null
+++ b/assets/leaflet-providers.json
@@ -0,0 +1,859 @@
+{
+ "OpenStreetMap": {
+ "url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 19,
+ "attribution": "© OpenStreetMap contributors"
+ },
+ "variants": {
+ "Mapnik": {},
+ "DE": {
+ "url": "https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 18
+ }
+ },
+ "CH": {
+ "url": "https://tile.osm.ch/switzerland/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 18,
+ "bounds": [
+ [
+ 45,
+ 5
+ ],
+ [
+ 48,
+ 11
+ ]
+ ]
+ }
+ },
+ "France": {
+ "url": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 20,
+ "attribution": "© Openstreetmap France | {attribution.OpenStreetMap}"
+ }
+ },
+ "HOT": {
+ "url": "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
+ "options": {
+ "attribution": "{attribution.OpenStreetMap}, Tiles style by Humanitarian OpenStreetMap Team hosted by OpenStreetMap France"
+ }
+ },
+ "BZH": {
+ "url": "https://tile.openstreetmap.bzh/br/{z}/{x}/{y}.png",
+ "options": {
+ "attribution": "{attribution.OpenStreetMap}, Tiles courtesy of Breton OpenStreetMap Team",
+ "bounds": [
+ [
+ 46.2,
+ -5.5
+ ],
+ [
+ 50,
+ 0.7
+ ]
+ ]
+ }
+ }
+ }
+ },
+ "OpenSeaMap": {
+ "url": "https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png",
+ "options": {
+ "attribution": "Map data: © OpenSeaMap contributors"
+ }
+ },
+ "OpenPtMap": {
+ "url": "http://openptmap.org/tiles/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 17,
+ "attribution": "Map data: © OpenPtMap contributors"
+ }
+ },
+ "OpenTopoMap": {
+ "url": "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 17,
+ "attribution": "Map data: {attribution.OpenStreetMap}, SRTM | Map style: © OpenTopoMap (CC-BY-SA)"
+ }
+ },
+ "OpenRailwayMap": {
+ "url": "https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 19,
+ "attribution": "Map data: {attribution.OpenStreetMap} | Map style: © OpenRailwayMap (CC-BY-SA)"
+ }
+ },
+ "OpenFireMap": {
+ "url": "http://openfiremap.org/hytiles/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 19,
+ "attribution": "Map data: {attribution.OpenStreetMap} | Map style: © OpenFireMap (CC-BY-SA)"
+ }
+ },
+ "SafeCast": {
+ "url": "https://s3.amazonaws.com/te512.safecast.org/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 16,
+ "attribution": "Map data: {attribution.OpenStreetMap} | Map style: © SafeCast (CC-BY-SA)"
+ }
+ },
+ "Thunderforest": {
+ "url": "https://{s}.tile.thunderforest.com/{variant}/{z}/{x}/{y}.png?apikey={apikey}",
+ "options": {
+ "attribution": "© Thunderforest, {attribution.OpenStreetMap}",
+ "variant": "cycle",
+ "apikey": "",
+ "maxZoom": 22
+ },
+ "variants": {
+ "OpenCycleMap": "cycle",
+ "Transport": {
+ "options": {
+ "variant": "transport"
+ }
+ },
+ "TransportDark": {
+ "options": {
+ "variant": "transport-dark"
+ }
+ },
+ "SpinalMap": {
+ "options": {
+ "variant": "spinal-map"
+ }
+ },
+ "Landscape": "landscape",
+ "Outdoors": "outdoors",
+ "Pioneer": "pioneer",
+ "MobileAtlas": "mobile-atlas",
+ "Neighbourhood": "neighbourhood"
+ }
+ },
+ "CyclOSM": {
+ "url": "https://dev.{s}.tile.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 20,
+ "attribution": "CyclOSM | Map data: {attribution.OpenStreetMap}"
+ }
+ },
+ "OpenMapSurfer": {
+ "url": "https://maps.heigit.org/openmapsurfer/tiles/{variant}/webmercator/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 19,
+ "variant": "roads",
+ "attribution": "Imagery from GIScience Research Group @ University of Heidelberg | Map data "
+ },
+ "variants": {
+ "Roads": {
+ "options": {
+ "variant": "roads",
+ "attribution": "{attribution.OpenMapSurfer}{attribution.OpenStreetMap}"
+ }
+ },
+ "Hybrid": {
+ "options": {
+ "variant": "hybrid",
+ "attribution": "{attribution.OpenMapSurfer}{attribution.OpenStreetMap}"
+ }
+ },
+ "AdminBounds": {
+ "options": {
+ "variant": "adminb",
+ "maxZoom": 18,
+ "attribution": "{attribution.OpenMapSurfer}{attribution.OpenStreetMap}"
+ }
+ },
+ "ContourLines": {
+ "options": {
+ "variant": "asterc",
+ "maxZoom": 18,
+ "minZoom": 13,
+ "attribution": "{attribution.OpenMapSurfer} ASTER GDEM"
+ }
+ },
+ "Hillshade": {
+ "options": {
+ "variant": "asterh",
+ "maxZoom": 18,
+ "attribution": "{attribution.OpenMapSurfer} ASTER GDEM, SRTM"
+ }
+ },
+ "ElementsAtRisk": {
+ "options": {
+ "variant": "elements_at_risk",
+ "attribution": "{attribution.OpenMapSurfer}{attribution.OpenStreetMap}"
+ }
+ }
+ }
+ },
+ "Hydda": {
+ "url": "https://{s}.tile.openstreetmap.se/hydda/{variant}/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 18,
+ "variant": "full",
+ "attribution": "Tiles courtesy of OpenStreetMap Sweden — Map data {attribution.OpenStreetMap}"
+ },
+ "variants": {
+ "Full": "full",
+ "Base": "base",
+ "RoadsAndLabels": "roads_and_labels"
+ }
+ },
+ "MapBox": {
+ "url": "https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}{r}.png?access_token={accessToken}",
+ "options": {
+ "attribution": "© Mapbox {attribution.OpenStreetMap} Improve this map",
+ "subdomains": "abcd",
+ "id": "mapbox.streets",
+ "accessToken": ""
+ }
+ },
+ "Stamen": {
+ "url": "https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}{r}.{ext}",
+ "options": {
+ "attribution": "Map tiles by Stamen Design, CC BY 3.0 — Map data {attribution.OpenStreetMap}",
+ "subdomains": "abcd",
+ "minZoom": 0,
+ "maxZoom": 20,
+ "variant": "toner",
+ "ext": "png"
+ },
+ "variants": {
+ "Toner": "toner",
+ "TonerBackground": "toner-background",
+ "TonerHybrid": "toner-hybrid",
+ "TonerLines": "toner-lines",
+ "TonerLabels": "toner-labels",
+ "TonerLite": "toner-lite",
+ "Watercolor": {
+ "url": "https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}",
+ "options": {
+ "variant": "watercolor",
+ "ext": "jpg",
+ "minZoom": 1,
+ "maxZoom": 16
+ }
+ },
+ "Terrain": {
+ "options": {
+ "variant": "terrain",
+ "minZoom": 0,
+ "maxZoom": 18
+ }
+ },
+ "TerrainBackground": {
+ "options": {
+ "variant": "terrain-background",
+ "minZoom": 0,
+ "maxZoom": 18
+ }
+ },
+ "TerrainLabels": {
+ "options": {
+ "variant": "terrain-labels",
+ "minZoom": 0,
+ "maxZoom": 18
+ }
+ },
+ "TopOSMRelief": {
+ "url": "https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}",
+ "options": {
+ "variant": "toposm-color-relief",
+ "ext": "jpg",
+ "bounds": [
+ [
+ 22,
+ -132
+ ],
+ [
+ 51,
+ -56
+ ]
+ ]
+ }
+ },
+ "TopOSMFeatures": {
+ "options": {
+ "variant": "toposm-features",
+ "bounds": [
+ [
+ 22,
+ -132
+ ],
+ [
+ 51,
+ -56
+ ]
+ ],
+ "opacity": 0.9
+ }
+ }
+ }
+ },
+ "TomTom": {
+ "url": "https://{s}.api.tomtom.com/map/1/tile/{variant}/{style}/{z}/{x}/{y}.{ext}?key={apikey}",
+ "options": {
+ "variant": "basic",
+ "maxZoom": 22,
+ "attribution": "© 1992 - 2020 TomTom. ",
+ "subdomains": "abcd",
+ "style": "main",
+ "ext": "png",
+ "apikey": ""
+ },
+ "variants": {
+ "Basic": "basic",
+ "Hybrid": "hybrid",
+ "Labels": "labels"
+ }
+ },
+ "Esri": {
+ "url": "https://server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{z}/{y}/{x}",
+ "options": {
+ "variant": "World_Street_Map",
+ "attribution": "Tiles © Esri"
+ },
+ "variants": {
+ "WorldStreetMap": {
+ "options": {
+ "attribution": "{attribution.Esri} — Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012"
+ }
+ },
+ "DeLorme": {
+ "options": {
+ "variant": "Specialty/DeLorme_World_Base_Map",
+ "minZoom": 1,
+ "maxZoom": 11,
+ "attribution": "{attribution.Esri} — Copyright: ©2012 DeLorme"
+ }
+ },
+ "WorldTopoMap": {
+ "options": {
+ "variant": "World_Topo_Map",
+ "attribution": "{attribution.Esri} — Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community"
+ }
+ },
+ "WorldImagery": {
+ "options": {
+ "variant": "World_Imagery",
+ "attribution": "{attribution.Esri} — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community"
+ }
+ },
+ "WorldTerrain": {
+ "options": {
+ "variant": "World_Terrain_Base",
+ "maxZoom": 13,
+ "attribution": "{attribution.Esri} — Source: USGS, Esri, TANA, DeLorme, and NPS"
+ }
+ },
+ "WorldShadedRelief": {
+ "options": {
+ "variant": "World_Shaded_Relief",
+ "maxZoom": 13,
+ "attribution": "{attribution.Esri} — Source: Esri"
+ }
+ },
+ "WorldPhysical": {
+ "options": {
+ "variant": "World_Physical_Map",
+ "maxZoom": 8,
+ "attribution": "{attribution.Esri} — Source: US National Park Service"
+ }
+ },
+ "OceanBasemap": {
+ "options": {
+ "variant": "Ocean_Basemap",
+ "maxZoom": 13,
+ "attribution": "{attribution.Esri} — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri"
+ }
+ },
+ "NatGeoWorldMap": {
+ "options": {
+ "variant": "NatGeo_World_Map",
+ "maxZoom": 16,
+ "attribution": "{attribution.Esri} — National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC"
+ }
+ },
+ "WorldGrayCanvas": {
+ "options": {
+ "variant": "Canvas/World_Light_Gray_Base",
+ "maxZoom": 16,
+ "attribution": "{attribution.Esri} — Esri, DeLorme, NAVTEQ"
+ }
+ }
+ }
+ },
+ "OpenWeatherMap": {
+ "url": "http://{s}.tile.openweathermap.org/map/{variant}/{z}/{x}/{y}.png?appid={apiKey}",
+ "options": {
+ "maxZoom": 19,
+ "attribution": "Map data © OpenWeatherMap",
+ "apiKey": "",
+ "opacity": 0.5
+ },
+ "variants": {
+ "Clouds": "clouds",
+ "CloudsClassic": "clouds_cls",
+ "Precipitation": "precipitation",
+ "PrecipitationClassic": "precipitation_cls",
+ "Rain": "rain",
+ "RainClassic": "rain_cls",
+ "Pressure": "pressure",
+ "PressureContour": "pressure_cntr",
+ "Wind": "wind",
+ "Temperature": "temp",
+ "Snow": "snow"
+ }
+ },
+ "HERE": {
+ "url": "https://{s}.{base}.maps.api.here.com/maptile/2.1/{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?app_id={app_id}&app_code={app_code}&lg={language}",
+ "options": {
+ "attribution": "Map © 1987-2020 HERE",
+ "subdomains": "1234",
+ "mapID": "newest",
+ "app_id": "",
+ "app_code": "",
+ "base": "base",
+ "variant": "normal.day",
+ "maxZoom": 20,
+ "type": "maptile",
+ "language": "eng",
+ "format": "png8",
+ "size": "256"
+ },
+ "variants": {
+ "normalDay": "normal.day",
+ "normalDayCustom": "normal.day.custom",
+ "normalDayGrey": "normal.day.grey",
+ "normalDayMobile": "normal.day.mobile",
+ "normalDayGreyMobile": "normal.day.grey.mobile",
+ "normalDayTransit": "normal.day.transit",
+ "normalDayTransitMobile": "normal.day.transit.mobile",
+ "normalDayTraffic": {
+ "options": {
+ "variant": "normal.traffic.day",
+ "base": "traffic",
+ "type": "traffictile"
+ }
+ },
+ "normalNight": "normal.night",
+ "normalNightMobile": "normal.night.mobile",
+ "normalNightGrey": "normal.night.grey",
+ "normalNightGreyMobile": "normal.night.grey.mobile",
+ "normalNightTransit": "normal.night.transit",
+ "normalNightTransitMobile": "normal.night.transit.mobile",
+ "reducedDay": "reduced.day",
+ "reducedNight": "reduced.night",
+ "basicMap": {
+ "options": {
+ "type": "basetile"
+ }
+ },
+ "mapLabels": {
+ "options": {
+ "type": "labeltile",
+ "format": "png"
+ }
+ },
+ "trafficFlow": {
+ "options": {
+ "base": "traffic",
+ "type": "flowtile"
+ }
+ },
+ "carnavDayGrey": "carnav.day.grey",
+ "hybridDay": {
+ "options": {
+ "base": "aerial",
+ "variant": "hybrid.day"
+ }
+ },
+ "hybridDayMobile": {
+ "options": {
+ "base": "aerial",
+ "variant": "hybrid.day.mobile"
+ }
+ },
+ "hybridDayTransit": {
+ "options": {
+ "base": "aerial",
+ "variant": "hybrid.day.transit"
+ }
+ },
+ "hybridDayGrey": {
+ "options": {
+ "base": "aerial",
+ "variant": "hybrid.grey.day"
+ }
+ },
+ "hybridDayTraffic": {
+ "options": {
+ "variant": "hybrid.traffic.day",
+ "base": "traffic",
+ "type": "traffictile"
+ }
+ },
+ "pedestrianDay": "pedestrian.day",
+ "pedestrianNight": "pedestrian.night",
+ "satelliteDay": {
+ "options": {
+ "base": "aerial",
+ "variant": "satellite.day"
+ }
+ },
+ "terrainDay": {
+ "options": {
+ "base": "aerial",
+ "variant": "terrain.day"
+ }
+ },
+ "terrainDayMobile": {
+ "options": {
+ "base": "aerial",
+ "variant": "terrain.day.mobile"
+ }
+ }
+ }
+ },
+ "FreeMapSK": {
+ "url": "http://t{s}.freemap.sk/T/{z}/{x}/{y}.jpeg",
+ "options": {
+ "minZoom": 8,
+ "maxZoom": 16,
+ "subdomains": "1234",
+ "bounds": [
+ [
+ 47.204642,
+ 15.996093
+ ],
+ [
+ 49.830896,
+ 22.576904
+ ]
+ ],
+ "attribution": "{attribution.OpenStreetMap}, vizualization CC-By-SA 2.0 Freemap.sk"
+ }
+ },
+ "MtbMap": {
+ "url": "http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png",
+ "options": {
+ "attribution": "{attribution.OpenStreetMap} & USGS"
+ }
+ },
+ "CartoDB": {
+ "url": "https://{s}.basemaps.cartocdn.com/{variant}/{z}/{x}/{y}{r}.png",
+ "options": {
+ "attribution": "{attribution.OpenStreetMap} © CARTO",
+ "subdomains": "abcd",
+ "maxZoom": 19,
+ "variant": "light_all"
+ },
+ "variants": {
+ "Positron": "light_all",
+ "PositronNoLabels": "light_nolabels",
+ "PositronOnlyLabels": "light_only_labels",
+ "DarkMatter": "dark_all",
+ "DarkMatterNoLabels": "dark_nolabels",
+ "DarkMatterOnlyLabels": "dark_only_labels",
+ "Voyager": "rastertiles/voyager",
+ "VoyagerNoLabels": "rastertiles/voyager_nolabels",
+ "VoyagerOnlyLabels": "rastertiles/voyager_only_labels",
+ "VoyagerLabelsUnder": "rastertiles/voyager_labels_under"
+ }
+ },
+ "HikeBike": {
+ "url": "https://tiles.wmflabs.org/{variant}/{z}/{x}/{y}.png",
+ "options": {
+ "maxZoom": 19,
+ "attribution": "{attribution.OpenStreetMap}",
+ "variant": "hikebike"
+ },
+ "variants": {
+ "HikeBike": {},
+ "HillShading": {
+ "options": {
+ "maxZoom": 15,
+ "variant": "hillshading"
+ }
+ }
+ }
+ },
+ "BasemapAT": {
+ "url": "https://maps{s}.wien.gv.at/basemap/{variant}/{type}/google3857/{z}/{y}/{x}.{format}",
+ "options": {
+ "maxZoom": 19,
+ "attribution": "Datenquelle: basemap.at",
+ "subdomains": [
+ "",
+ "1",
+ "2",
+ "3",
+ "4"
+ ],
+ "type": "normal",
+ "format": "png",
+ "bounds": [
+ [
+ 46.35877,
+ 8.782379
+ ],
+ [
+ 49.037872,
+ 17.189532
+ ]
+ ],
+ "variant": "geolandbasemap"
+ },
+ "variants": {
+ "basemap": {
+ "options": {
+ "maxZoom": 20,
+ "variant": "geolandbasemap"
+ }
+ },
+ "grau": "bmapgrau",
+ "overlay": "bmapoverlay",
+ "terrain": {
+ "options": {
+ "variant": "bmapgelaende",
+ "type": "grau",
+ "format": "jpeg"
+ }
+ },
+ "surface": {
+ "options": {
+ "variant": "bmapoberflaeche",
+ "type": "grau",
+ "format": "jpeg"
+ }
+ },
+ "highdpi": {
+ "options": {
+ "variant": "bmaphidpi",
+ "format": "jpeg"
+ }
+ },
+ "orthofoto": {
+ "options": {
+ "maxZoom": 20,
+ "variant": "bmaporthofoto30cm",
+ "format": "jpeg"
+ }
+ }
+ }
+ },
+ "nlmaps": {
+ "url": "https://geodata.nationaalgeoregister.nl/tiles/service/wmts/{variant}/EPSG:3857/{z}/{x}/{y}.png",
+ "options": {
+ "minZoom": 6,
+ "maxZoom": 19,
+ "bounds": [
+ [
+ 50.5,
+ 3.25
+ ],
+ [
+ 54,
+ 7.6
+ ]
+ ],
+ "attribution": "Kaartgegevens © Kadaster"
+ },
+ "variants": {
+ "standaard": "brtachtergrondkaart",
+ "pastel": "brtachtergrondkaartpastel",
+ "grijs": "brtachtergrondkaartgrijs",
+ "luchtfoto": {
+ "url": "https://geodata.nationaalgeoregister.nl/luchtfoto/rgb/wmts/2018_ortho25/EPSG:3857/{z}/{x}/{y}.png"
+ }
+ }
+ },
+ "NASAGIBS": {
+ "url": "https://map1.vis.earthdata.nasa.gov/wmts-webmerc/{variant}/default/{time}/{tilematrixset}{maxZoom}/{z}/{y}/{x}.{format}",
+ "options": {
+ "attribution": "Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System (ESDIS) with funding provided by NASA/HQ.",
+ "bounds": [
+ [
+ -85.0511287776,
+ -179.999999975
+ ],
+ [
+ 85.0511287776,
+ 179.999999975
+ ]
+ ],
+ "minZoom": 1,
+ "maxZoom": 9,
+ "format": "jpg",
+ "time": "",
+ "tilematrixset": "GoogleMapsCompatible_Level"
+ },
+ "variants": {
+ "ModisTerraTrueColorCR": "MODIS_Terra_CorrectedReflectance_TrueColor",
+ "ModisTerraBands367CR": "MODIS_Terra_CorrectedReflectance_Bands367",
+ "ViirsEarthAtNight2012": {
+ "options": {
+ "variant": "VIIRS_CityLights_2012",
+ "maxZoom": 8
+ }
+ },
+ "ModisTerraLSTDay": {
+ "options": {
+ "variant": "MODIS_Terra_Land_Surface_Temp_Day",
+ "format": "png",
+ "maxZoom": 7,
+ "opacity": 0.75
+ }
+ },
+ "ModisTerraSnowCover": {
+ "options": {
+ "variant": "MODIS_Terra_Snow_Cover",
+ "format": "png",
+ "maxZoom": 8,
+ "opacity": 0.75
+ }
+ },
+ "ModisTerraAOD": {
+ "options": {
+ "variant": "MODIS_Terra_Aerosol",
+ "format": "png",
+ "maxZoom": 6,
+ "opacity": 0.75
+ }
+ },
+ "ModisTerraChlorophyll": {
+ "options": {
+ "variant": "MODIS_Terra_Chlorophyll_A",
+ "format": "png",
+ "maxZoom": 7,
+ "opacity": 0.75
+ }
+ }
+ }
+ },
+ "NLS": {
+ "url": "https://nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg",
+ "options": {
+ "attribution": "National Library of Scotland Historic Maps",
+ "bounds": [
+ [
+ 49.6,
+ -12
+ ],
+ [
+ 61.7,
+ 3
+ ]
+ ],
+ "minZoom": 1,
+ "maxZoom": 18,
+ "subdomains": "0123"
+ }
+ },
+ "JusticeMap": {
+ "url": "http://www.justicemap.org/tile/{size}/{variant}/{z}/{x}/{y}.png",
+ "options": {
+ "attribution": "Justice Map",
+ "size": "county",
+ "bounds": [
+ [
+ 14,
+ -180
+ ],
+ [
+ 72,
+ -56
+ ]
+ ]
+ },
+ "variants": {
+ "income": "income",
+ "americanIndian": "indian",
+ "asian": "asian",
+ "black": "black",
+ "hispanic": "hispanic",
+ "multi": "multi",
+ "nonWhite": "nonwhite",
+ "white": "white",
+ "plurality": "plural"
+ }
+ },
+ "Wikimedia": {
+ "url": "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}{r}.png",
+ "options": {
+ "attribution": "Wikimedia",
+ "minZoom": 1,
+ "maxZoom": 19
+ }
+ },
+ "GeoportailFrance": {
+ "url": "https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER={variant}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}",
+ "options": {
+ "attribution": "Geoportail France",
+ "bounds": [
+ [
+ -75,
+ -180
+ ],
+ [
+ 81,
+ 180
+ ]
+ ],
+ "minZoom": 2,
+ "maxZoom": 18,
+ "apikey": "choisirgeoportail",
+ "format": "image/jpeg",
+ "style": "normal",
+ "variant": "GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD"
+ },
+ "variants": {
+ "parcels": {
+ "options": {
+ "variant": "CADASTRALPARCELS.PARCELS",
+ "maxZoom": 20,
+ "style": "bdparcellaire",
+ "format": "image/png"
+ }
+ },
+ "ignMaps": "GEOGRAPHICALGRIDSYSTEMS.MAPS",
+ "maps": "GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD",
+ "orthos": {
+ "options": {
+ "maxZoom": 19,
+ "variant": "ORTHOIMAGERY.ORTHOPHOTOS"
+ }
+ }
+ }
+ },
+ "OneMapSG": {
+ "url": "https://maps-{s}.onemap.sg/v3/{variant}/{z}/{x}/{y}.png",
+ "options": {
+ "variant": "Default",
+ "minZoom": 11,
+ "maxZoom": 18,
+ "bounds": [
+ [
+ 1.56073,
+ 104.11475
+ ],
+ [
+ 1.16,
+ 103.502
+ ]
+ ],
+ "attribution": " New OneMap | Map data © contributors, Singapore Land Authority"
+ },
+ "variants": {
+ "Default": "Default",
+ "Night": "Night",
+ "Original": "Original",
+ "Grey": "Grey",
+ "LandLot": "LandLot"
+ }
+ }
+}
\ No newline at end of file
diff --git a/assets/plugin.js b/assets/plugin.js
index 0876a6d..8a395a3 100644
--- a/assets/plugin.js
+++ b/assets/plugin.js
@@ -1,8 +1,10 @@
/**
* Leaflet handler (theoretically requires no jQuery, but we use it anyway, just because ;) :P )
*
- * @version 0.6.1
+ * @version 0.6.2
* Changelog:
+ * v0.6.2:
+ * - set zoom control position
* v0.6.1:
* - bugfix for search control position
*
@@ -55,8 +57,18 @@ jQuery( function() {
var map_layer = ( typeof( config.layer ) != 'undefined' ? config.layer : 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' );
+ // configure zoom Control
+ var _use_zoom_control = true;
+ if( typeof( config.zoom_position ) != 'undefined' ) {
+ var _use_zoom_control = false;
+ }
+
// init map
- _ui_leaflet_maps[ strMapID ] = L.map( strMapID );
+ _ui_leaflet_maps[ strMapID ] = L.map( strMapID, {
+ zoomControl: _use_zoom_control,
+ } );
+
+
// add tile layer (server)
@@ -65,10 +77,18 @@ jQuery( function() {
minZoom: 0,
zoom: 16,
subdomains: 'abc',
- attribution: 'Map data © OpenStreetMap contributors, ' +
- 'CC-BY-SA, ',
+ attribution: 'Map data © OpenStreetMap contributors, ' +
+ 'CC-BY-SA, ',
}).addTo( _ui_leaflet_maps[strMapID] );
+ if( _use_zoom_control == false ) {
+ //console.log( 'zoom_position:', config.zoom_position );
+
+ L.control.zoom({
+ position: config.zoom_position,
+ }).addTo( _ui_leaflet_maps[ strMapID ] );
+ }
+
// focus
//var mymap = L.map('mapid').setView([51.505, -0.09], 13);
//_ui_leaflet_maps[ strMapID ].setView( [51.505, -0.09], 14 );
@@ -92,10 +112,75 @@ jQuery( function() {
}).addTo( _ui_leaflet_maps[ strMapID ] );
}
+
+
+ _ui_leaflet_maps[ strMapID ].on( 'locationfound', function( e ) {
+ //console.info( 'location found:', e );
+ });
+
_ui_leaflet_maps[ strMapID ].setView( {lng: config.longitude, lat: config.latitude}, map_zoomlevel );
+ /**
+ * Based upon @link https://developer.mapquest.com/documentation/samples/leaflet/v2.2/maps/geolocation/
+ */
+
+ if( typeof( config.use_locate ) != 'undefined' && config.use_locate != false ) {
+ console.info( 'using locate' );
+
+ //if( typeof( config.locate_popup ) != 'undefined' ) {
+ var popup = L.popup();
+
+
+
+ function geolocationErrorOccurred(geolocationSupported, popup, latLng) {
+ popup.setLatLng(latLng);
+ popup.setContent(geolocationSupported ?
+ 'Error: The Geolocation service failed.' :
+ 'Error: This browser doesn\'t support geolocation.');
+ //popup.openOn(geolocationMap);
+
+ popup.openOn( _ui_leaflet_maps[ strMapID ] );
+ }
+
+ if (navigator.geolocation) {
+
+ navigator.geolocation.getCurrentPosition(function(position) {
+ var latLng = {
+ lat: position.coords.latitude,
+ lng: position.coords.longitude
+ };
+
+ var strPopupContent = 'This is your current position.';
+
+ if( typeof( config.locate_popup ) != 'undefined' ) {
+ strPopupContent = config.locate_popup;
+ }
+
+ popup.setLatLng(latLng);
+ //popup.setContent( 'This is your current location' );
+ popup.setContent( strPopupContent );
+ //popup.openOn(geolocationMap);
+
+ popup.openOn( _ui_leaflet_maps[ strMapID ] );
+
+ _ui_leaflet_maps[ strMapID ].setView(latLng);
+ }, function() {
+ //geolocationErrorOccurred(true, popup, geolocationMap.getCenter() );
+ geolocationErrorOccurred(true, popup, _ui_leaflet_maps[ strMapID ].getCenter() );
+ //geolocationErrorOccurred
+
+ });
+ } else {
+ //No browser support geolocation service
+ //geolocationErrorOccurred(false, popup, geolocationMap.getCenter());
+ geolocationErrorOccurred(false, popup, _ui_leaflet_maps[ strMapID ].getCenter() );
+ }
- //_ui_leaflet_maps[ strMapID ].setView( {lng: config.longitude, lat: config.latitude}, 14 );
+
+ //_ui_leaflet_maps[ strMapID ].locate({ setView: true, timeout: 5000 });
+
+
+ }
// init marker
@@ -122,10 +207,47 @@ jQuery( function() {
posMarker.lat = config.marker_position.latitude;
}
- var strMarkerIcon = '';
- if( typeof( config.marker_fa_icon ) != 'undefined' ) {
+
+
+ //var strMarkerIcon = '';
+ /**
+ * Change to a more fitting marker icon
+ * @since 0.9.4
+ */
+
+ var strMarkerIcon = '';
+
+ if( typeof( config.marker_fa_icon ) != 'undefined' && config.marker_fa_icon != '' ) {
var strMarkerIcon = '';
}
+
+ /**
+ * Optionally use a FortAwesome 5 icon
+ * @since v0.9.4
+ */
+
+ if( typeof( config.marker_far_icon ) != 'undefined' && config.marker_far_icon != '' ) {
+ var strMarkerIcon = '';
+ }
+
+ /**
+ * Use a COMPLETE DIFFERENT icon class (eg. because you generated your own, or want to use glyphicons instead)
+ * @since v0.9.4
+ */
+ if( typeof( config.marker_icon_class ) != 'undefined' && config.marker_icon_class != '' ) {
+ var strMarkerIcon = '';
+ }
+
+
+ /**
+ * Use custom HTML for the marker icon instead of the default Font / Fork / Fort Awesome-based icon HTML code
+ * @since v0.9.4
+ */
+
+ if( typeof( config.marker_icon_html ) != 'undefined' && config.marker_icon_html != '' ) {
+ strMarkerIcon = config.marker_icon_html;
+ }
+
// create div-based marker icon
//L.divIcon({className: 'my-div-icon'});
@@ -139,7 +261,8 @@ jQuery( function() {
'map_id': strMapID,
'marker': {
'position': posMarker,
- 'icon_class': 'ui-leaflet-div-icon'
+ 'icon_class': 'ui-leaflet-div-icon',
+ 'icon_html': strMarkerIcon,
},
} );
diff --git a/includes/functions.php b/includes/functions.php
new file mode 100644
index 0000000..144209e
--- /dev/null
+++ b/includes/functions.php
@@ -0,0 +1,23 @@
+_post_load_assets();
+ }
+ }
+}
+
+if( !function_exists( '_ui_leaflet_preload_assets' ) ) {
+ function _ui_leaflet_preload_assets() {
+ if( !defined( '_UI_LEAFLET_LOAD_ASSETS' ) ) {
+ define( '_UI_LEAFLET_LOAD_ASSETS', true );
+ }
+ }
+}
diff --git a/includes/leaflet-map.class.php b/includes/leaflet-map.class.php
index b513795..03d1f4b 100644
--- a/includes/leaflet-map.class.php
+++ b/includes/leaflet-map.class.php
@@ -2,21 +2,25 @@
/**
* Insert leaflet map plus options into post (or anywhere else)
*
- * @version 0.8.1
+ * @version 0.9.4
*/
class _ui_LeafletIntegration extends _ui_LeafletBase {
public $pluginPrefix = 'ui_leaflet_',
$pluginPath = '',
$pluginURL = '',
- $pluginVersion = '0.8.1';
+ $pluginVersion = '0.9.4';
public static function init() {
- new self();
+ new self( true );
}
- function __construct() {
+ function __construct( $init_plugin = false ) {
+ if( empty( $init_plugin ) ) {
+ return;
+ }
+
$this->_setup();
add_shortcode( 'ui_leaflet_map', array( $this, 'shortcode_map' ) );
@@ -110,13 +114,30 @@ function preload_assets() {
//new __debug( $arrDetectedShortcode, 'detected shortcodes - ' . __METHOD__ );
+ //new __debug( $arrDetectedShortcode, 'detected shortcodes - ' . __METHOD__ );
if( !empty( $arrDetectedShortcode ) ) { // load assets
+ $this->bPreloadAssets = true;
+ }
+
+ if( defined( '_UI_LEAFLET_LOAD_ASSETS' ) ) { // enforce assets loading
+ $this->bPreloadAssets = true;
+ }
+
+
+ if( !empty( $this->bPreloadAssets ) ) { // load assets
- add_action( 'wp_enqueue_scripts', array( $this, 'init_assets' ), 9 );
- add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ), 15 );
+ add_action( 'wp_enqueue_scripts', array( $this, 'init_assets' ) );
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ) );
}
}
+ // explicitely initialize asset loading
+
+ function post_load_assets() {
+ add_action( 'wp_enqueue_scripts', array( $this, 'init_assets' ), 9 );
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ), 15 );
+ }
+
function init_assets() {
/**
* Change the version number (string!) to load a different version of the leaflet map library, eg. for backward compatiblity.
@@ -129,6 +150,16 @@ function init_assets() {
$leaflet_version = apply_filters( $this->pluginPrefix . 'load_leaflet_version', '1.3.3' );
$leaflet_version = apply_filters( $this->pluginPrefix . 'load_leaflet_version', '1.6' );
+ /**
+ * URL of the main Leaflet.js JS file
+ * @hook ui_leaflet_js_url
+ *
+ */
+
+ /**
+ * URL of the main Leaflet.js CSS file
+ * @hook ui_leaflet_css_url
+ */
$leaflet_js_url = apply_filters( $this->pluginPrefix . 'js_url', trailingslashit( $this->pluginURL ). "assets/leaflet/$leaflet_version/leaflet.js");
$leaflet_css_url = apply_filters( $this->pluginPrefix . 'css_url', trailingslashit( $this->pluginURL ) . "assets/leaflet/$leaflet_version/leaflet.css");
@@ -138,6 +169,7 @@ function init_assets() {
//$leaflet_geocoder_css_url = apply_filters( $this->pluginPrefix . 'geocoder_css_url', trailingslashit( $this->pluginURL ) . 'assets/extensions/Control.Geocoder.css' );
+ //new __debug( array( 'url' => $this->pluginURL, 'path' => $this->pluginPath ), 'plugin path settings' );
$load_in_footer = apply_filters( $this->pluginPrefix . 'load_in_footer', true );
@@ -145,12 +177,30 @@ function init_assets() {
wp_register_script( $this->pluginPrefix . 'geocoder_js', $this->pluginURL . 'assets/extensions/Control.Geocoder.min.js', array( $this->pluginPrefix . 'js' ), '1.10.0', $load_in_footer );
+ /**
+ * Enqueue additional Leaflet extensions (Javascript files). Default array includes the Geocoder Control (v1.10.0) supplied with this plugin.
+ * @hook ui_leaflet_add_extensions_js
+ *
+ * @param array $extension_handles Pre-registered handles for loading them as dependencies of the plugin JS file.
+ */
+
+ $extension_js_handles = apply_filters( $this->pluginPrefix . 'add_extensions_js', array( $this->pluginPrefix . 'geocoder_js' ) );
+ $plugin_js_deps = array( 'jquery', $this->pluginPrefix . 'js' );
- //wp_register_script( $this->pluginPrefix . 'plugin_simple', trailingslashit( $this->pluginURL ). 'assets/plugin.js', array( 'jquery', $this->pluginPrefix . 'js' ), $this->pluginVersion, $load_in_footer );
+ if( !empty( $extension_js_handles ) ) {
+ /**
+ * NOTE: $plugin_js_deps need to be loaded IN THE FOOTER, else everything explodes!
+ */
+
+ $plugin_js_deps = wp_parse_args( $plugin_js_deps, $extension_js_handles );
+ }
+ //new __debug( $plugin_js_deps, 'plugin_js_deps' );
+
// full
- wp_register_script( $this->pluginPrefix . 'plugin', trailingslashit( $this->pluginURL ). 'assets/plugin.js', array( 'jquery', $this->pluginPrefix . 'geocoder_js' ), $this->pluginVersion, $load_in_footer );
+
+ wp_register_script( $this->pluginPrefix . 'plugin', trailingslashit( $this->pluginURL ). 'assets/plugin.js', $plugin_js_deps, $this->pluginVersion, $load_in_footer );
/**
@@ -159,9 +209,30 @@ function init_assets() {
*/
- wp_register_style( $this->pluginPrefix . 'css_simple', $leaflet_css_url );
+ wp_register_style( $this->pluginPrefix . 'base_css', $leaflet_css_url );
+
+ wp_register_style( $this->pluginPrefix . 'geocoder_css', trailingslashit( $this->pluginURL ) . 'assets/extensions/Control.Geocoder.css', array(), '1.10.0' );
+
+ /**
+ * Enqueue additional Leaflet extensions (Javascript files). Default array includes the Geocoder Control (v1.10.0) supplied with this plugin.
+ * @hook ui_leaflet_add_extensions_css
+ *
+ * @param array $extension_handles Pre-registered handles for loading them as dependencies of the plugin JS file.
+ */
+
+ $extension_css_handles = apply_filters( $this->pluginPrefix . 'add_extensions_css', array( $this->pluginPrefix . 'geocoder_css' ) );
+
+
+ $plugin_css_deps = array( $this->pluginPrefix . 'base_css' );
+
+ if( !empty( $extension_css_handles ) ) {
+ $plugin_css_deps = wp_parse_args( $plugin_css_deps, $extension_css_handles );
+ }
+
+ //new __debug( $plugin_css_deps, 'plugin_css_deps' );
+
+ wp_register_style( $this->pluginPrefix . 'css', $this->pluginURL . 'assets/plugin.css', $plugin_css_deps, $this->pluginVersion );
- wp_register_style( $this->pluginPrefix . 'css', trailingslashit( $this->pluginURL ) . 'assets/extensions/Control.Geocoder.css', array( $this->pluginPrefix . 'css_simple' ) );
//wp_register_style( $this->pluginPrefix . 'plugin_simple', trailingslashit( $this->pluginURL ) . 'assets/plugin.css', array( $this->pluginPrefix . 'css' ), $this->pluginVersion, false );
@@ -255,10 +326,11 @@ function reset_queue() {
*/
protected function _get_default_params() {
+
return array(
'enable_map_shortcode' => false,
'enable_marker_shortcode' => false,
- 'tile_server' => 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
+ 'tile_server' => 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'map_height' => '400px', /* default height */
);
}
@@ -363,7 +435,7 @@ function get_tile_server( $handle = '' ) {
case 'osmbw':
case 'black_white':
case 'bw':
- // 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
+ // 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
$return = 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png';
break;
case 'nolabels':
@@ -371,13 +443,13 @@ function get_tile_server( $handle = '' ) {
case 'mapnik_no_labels':
case 'osm_no_labels':
case 'osm_blank':
- $return = 'http://www.toolserver.org/tiles/osm-no-labels/{z}/{x}/{y}.png';
+ $return = 'https://www.toolserver.org/tiles/osm-no-labels/{z}/{x}/{y}.png';
break;
case 'mapnik':
case 'mapnick':
default:
- $return = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
+ $return = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
break;
case 'skobbler':
@@ -400,7 +472,7 @@ function get_tile_server( $handle = '' ) {
* @param string $routing Possible routing apps: google (Google Maps)
*
* 48.1372568,11.5759285 <= fischbrunnen = base coordinates
- * lat=48.13733&lon=11.57599 (acc. to OSM) => http://openstreetmap.de/karte.html?zoom=18&lat=48.13733&lon=11.57599&layers=000BTT
+ * lat=48.13733&lon=11.57599 (acc. to OSM) => https://openstreetmap.de/karte.html?zoom=18&lat=48.13733&lon=11.57599&layers=000BTT
*/
function shortcode_map( $attr = array(), $content = '' ) {
@@ -423,12 +495,19 @@ function shortcode_map( $attr = array(), $content = '' ) {
'layer_api_key' => '',
'class' => 'ui-leaflet-map',
'marker_class' => 'ui-leaflet-marker',
+ 'marker_icon_class' => '', // defaults to 'fa fa-fw fa-marker-map fa-2x' (= FontAwesome 4.x / Fork Awesome 1.x)
+ 'marker_icon_fa_class' => '', // Font/ForkAwesome
+ 'marker_icon_far_class' => '', // FoRtAwesome
+ 'marker_icon_html' => '', // custom html for the icon, eg. an or