I'm new to custom projections in Leaflet, and now I'm trying to set up a Leaflet map that uses a WMTS service for its tiles, with the custom projection EPSG:3008 (SWEREF99 13 30).
I'm using Proj4Leaflet to use this CRS with Leaflet, and when setting it up I'm required to specify the proj4 definition which I could easily find at https://spatialreference.org, along with options such as origin, scales/resolutions and bounds.
I've understood that I should be able to get/calculate these values by looking at the GetCapabilities document for this WTMS service. Here I'm using the layer ext_lm:topografiska_nedtonad_3008, the TileMatrixSet New_EPSG:3008 and the TileMatrix EPSG:3008.
As far as I can see, there are 11 levels in this TileMatrixSet. They all have a unique ScaleDenominator and TopLeftCorner values. I've tried to use these ScaleDenominator values for the resolution option without success.
I've read several threads here about calculating these values by multiplying the ScaleDenominator by pixel width (0.00028), and calculating bounds by multiplying TileWidth by MatrixWidth/MatrixHeight without success. I'm not sure how to get the correct options for this specific CRS, and make it work with Leaflet.
My current code is:
const crs = new L.Proj.CRS('EPSG:3008',
'+proj=tmerc +lat_0=0 +lon_0=13.5 +k=1 +x_0=150000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs', {
resolutions: [200000, 100000, 50000, 25000, 15000, 10000, 5000, 2000, 1000, 400, 200],
});
const defaultPosition = new L.LatLng(12.82956, 56.68970);
const eventMap = L.map('mapid', {
crs: crs
}).setView(defaultPosition, 0);
L.tileLayer('https://karta.halmstad.se/geoserver/gwc/service/wmts/rest/ext_lm:topografiska_nedtonad_3008/default/New_EPSG:3008/EPSG:3008:{z}/{y}/{x}?format=image/png', {
maxZoom: 10,
minZoom: 0,
continuousWorld: true
}).addTo(eventMap);
This results in some correctly rendered tiles, while most tiles are either wrong or outside the tile range.
I'm not sure what values to look at while calculating the correct option values.
Best Answer
As I wrote in my comment, this layer does not confirm to standard slippy map tiles (Google tiles), and besides that, not all zoom levels have the same origin. This makes it impossible to show layer with vanilla Leaflet, but with some hacking it can be done.
The fact that number of tiles for certain zoom does not conform with the slippy map tile standard can be overcome by overcome by extending L.Map object and using
getTileUrl
option to fetch the right tiles. Since at zoom level 0 there are 5 X 4 tiles which roughly conforms with zoom level 2, just zoom parameter has to be decreased by 2.Bigger problem are different map origins for different zoom levels. This can be overcome by catching
zoomstart
event and setting the right origin for target zoom there. But how to get target zoom? Fot thisL.Map
object has to be extended and in the_resetView
retrieve new zoom level with the internal_limitZoom
method and save direction of the zoom in the custom_zoomType
property. For his to work, map animation has to be disabled with thezoomAnimation: false
option.Resolutions are calculated from scale denominators by multiplying with 0.00028. Since actual map zoom now start at 2, zooms 0 and 1 are left to Leaflet to be extrapolated from level 2 by setting
minNativeZoom
option to 2.Code could the look something like this (tested):
That's how map looks like then at zoom 0: