Calculating Leaflet scale ratio for the particular zoom level

coordinate systemleafletscale

Is there any way we can calculate the scale ratio using L.CRS.scale?

For example, if I execute the following code L.CRS.scale(this._map.getZoom()), the pixel coordinates value for a particular zoom would be 1763487.599042158.
So, my question is how to find what ratio (i.e. 1:500, 1:1000 etc) is and how to calculate it from the return value of scale?

The table below shows the resolution (meters per pixel) and scale of the zoom levels within the EPSG:27700 tile matrix set. The resolution is calculated at a DPI of 96.

enter image description here

Best Answer

Is there any way we can calculate the scale ratio using L.CRS.scale?

Using L.CRS.scale for that kind of calculation is cumbersome and most probably unreliable in the end. The result of L.CRS.scale() has to be multiplied by a CRS-dependant constant (the world bounds according to that CRS) in order to make the numbers meaningful, which IMO leads to confusion. As explained elsewhere, the implementation of L.CRS is geared towards quickly displaying things on a screen, and not towards an abstract GIS understanding of CRSs.

Instead, I suggest doing as L.Control.Scale does: calculate the distance in meters between two points at known places in the screen, with a known distance in pixels between them.

The relevant code from L.Control.Scale I'm referring to is

    var y = map.getSize().y / 2;
    var maxMeters = map.distance(
        map.containerPointToLatLng([0, y]),
        map.containerPointToLatLng([this.options.maxWidth, y]));

That calculates the distance in map meters between two points in a horizontal line in the middle of the map, measuring this.options.maxWidth CSS pixels wide.

So if you're assuming 96 DPI, that means (after a tiny bit of math) a centimeter is 38 pixels. So if you replace this.options.maxWidth with 38 in the aforementioned code, you'll end up with the amount of map meters that correspond to a screen centimeter. Deriving a scale factor from those numbers is trivial.

This approach has the advantage of not needing any constants from the CRS definition, since the distance() function does the heavy lifting for you.

This approach has the disadvantage of a varying scale factor for the same zoom level (which might in fact be desireable if the projection distorts lengths). This can be worked around by replacing the implementation of L.CRS.distance with a cartesian distance of projected coordinates implementation.