--- layout: tutorial_v2 title: Zoom levels --- ## Zoom levels Leaflet works with [latitude](https://en.wikipedia.org/wiki/Latitude), [longitude](https://en.wikipedia.org/wiki/Longitude) and "zoom level". Lower zoom levels means that the map shows entire continents, while higher zoom levels means that the map can show details of a city. To understand how zoom levels work, first we need a basic introduction to geodesy. ## The shape of the earth Let's have a look at a simple map locked at zoom zero: ``` var map = L.map('map', { minZoom: 0, maxZoom: 0 }); var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', { attribution: cartodbAttribution }).addTo(map); map.setView([0, 0], 0); ``` {% include frame.html url="example-zero.html" %} Notice that the "whole earth" is just one image, 256 pixels wide and 256 pixels high:
Just to be clear: the earth is not a square. Rather, the earth is shaped like [a weird potato](https://commons.wikimedia.org/wiki/File:GRACE_globe_animation.gif) that can be approximated to [something similar to a sphere](https://en.wikipedia.org/wiki/Geoid).
GRACE globe animation
Potato earth image by NASA/JPL/University of Texas Center for Space Research
with help of the GRACE satellites.
So we *assume* that the earth is mosly round. To make it flat, we put an imaginary cylinder around, unroll it, and cut it so it looks square:
Usgs map mercator
This is called a "cylindrical map projection".
This is not the only way of displaying the surface on the earth on a plane. There are [hundreds of ways](https://en.wikipedia.org/wiki/Map_projection), each of them with its own advantages and disadvantages. The following 6-minute video is a nice introduction to the topic:
Things like geodesy, map projections and coordinate systems are hard, *very hard* (and out of scope for this tutorial). Assuming that the earth is a square is not always the right thing to do, but most of the time works fine enough, makes things simpler, and allows Leaflet (and other map libraries) to be fast. ## Powers of two For now, let's just ***assume*** that the world is a square:
When we represent the world at zoom level **zero**, it's 256 pixels wide and high. When we go into zoom level **one**, it doubles its width and height, and can be represented by four 256-pixel-by-256-pixel images:
At each zoom level, each tile is divided in four, and its size (length of the edge, given by the `tileSize` option) doubles, quadrupling the area. (in other words, the width and height of the world is 256·2zoomlevel pixels):
Zoom 0Zoom 1Zoom 2
This goes on and on. Most tile services offer tiles up to zoom level 18, depending on their coverage. This is enough to see a few city blocks per tile. ## A note about scale One of the disadvantages of using a cylindrical projection is that the scale is not constant, and measuring distances or sizes is not reliable, specially at low zoom levels. In [technical terms](https://en.wikipedia.org/wiki/Map_projection#Projections_by_preservation_of_a_metric_property), the cylindrical projection that Leaflet uses is conformal (preserves shapes), but not equidistant (does not preserve distances), and not equal-area (does not preserve areas, as things near the equator appear smaller than they are). By adding a `L.Control.Scale` to a map, and panning to the equator and to 60° north, we can see how the scale factor doubles. The following example uses [javascript timeouts](https://developer.mozilla.org/docs/Web/API/WindowTimers/setTimeout) to do this automatically: ``` L.control.scale().addTo(map); setInterval(function(){ map.setView([0, 0]); setTimeout(function(){ map.setView([60, 0]); }, 2000); }, 4000); ``` {% include frame.html url="example-scale.html" %} `L.Control.Scale` shows the scale which applies to the center point of the map. At high zoom levels, the scale changes very little, and is not noticeable. ## Controlling the zoom A leaflet map has several ways to control the zoom level shown, but the most obvious one is [`setZoom()`](/reference.html#map-setzoom). For example, `map.setZoom(0);` will set the zoom level of `map` to `0`. This example again uses timeouts to alternate between zoom levels `0` and `1` automatically: ``` setInterval(function(){ map.setZoom(0); setTimeout(function(){ map.setZoom(1); }, 2000); }, 4000); ``` {% include frame.html url="example-setzoom.html" %} Notice how the images shown at zoom levels 0 and one correspond with the images shown in the previous section! Other ways of setting the zoom are: * [`setView(center, zoom)`](/reference.html#map-setview), which also sets the map center * [`flyTo(center, zoom)`](/reference.html#map-flyto), like `setView` but with a smooth animation * [`zoomIn()` / `zoomIn(delta)`](/reference.html#map-zoomin), zooms in `delta` zoom levels, `1` by default * [`zoomOut()` / `zoomOut(delta)`](/reference.html#map-zoomout), zooms out `delta` zoom levels, `1` by default * [`setZoomAround(fixedPoint, zoom)`](/reference.html#map-setzoomaround), sets the zoom level while keeping a point fixed (what scrollwheel zooming does) * [`fitBounds(bounds)`](/reference.html#map-fitbounds), automatically calculates the zoom to fit a rectangular area on the map ## Fractional zoom A feature introduced in Leaflet 1.0.0 was the concept of fractional zoom. Before this, the zoom level of the map could be only an integer number (`0`, `1`, `2`, and so on); but now you can use fractional numbers like `1.5` or `1.25`. Fractional zoom is disabled by default. To enable it, use the [map's `zoomSnap` option](/reference.html#map-zoomsnap). The `zoomSnap` option has a default value of `1` (which means that the zoom level of the map can be `0`, `1`, `2`, and so on). If you set the value of `zoomSnap` to `0.5`, the valid zoom levels of the map will be `0`, `0.5`, `1`, `1.5`, `2`, and so on. If you set a value of `0.1`, the valid zoom levels of the map will be `0`, `0.1`, `0.2`, `0.3`, `0.4`, and so on. The following example uses a `zoomSnap` value of `0.25`: ``` var map = L.map('map', { zoomSnap: 0.25 }); ``` {% include frame.html url="example-fractional.html" %} As you can see, Leaflet will only load the tiles for zoom levels `0` or `1`, and will scale them as needed. Leaflet will snap the zoom level to the closest valid one. For example, if you have `zoomSnap: 0.25` and you try to do `map.setZoom(0.8)`, the zoom will snap back to `0.75`. The same happens with `map.fitBounds(bounds)`, or when ending a pinch-zoom gesture on a touchscreen. `zoomSnap` can be set to zero. This means that Leaflet will not snap the zoom level. There is another important map option related to `zoomSnap`: [the `zoomDelta` option](/reference.html#map-zoomdelta). This controls how many zoom levels to zoom in/out when using the zoom buttons (from the default [`L.Control.Zoom`](/reference.html#control-zoom)) or the `+`/`-` keys in your keyboard. For the mousewheel zoom, the [`wheelPxPerZoomLevel`](/reference.html#map-wheelpxperzoomlevel) option controls how fast the mousewheel zooms in our out. Here is an example with `zoomSnap` set to zero: ``` var map = L.map('map', { zoomDelta: 0.25, zoomSnap: 0 }); ``` Try the following, and see how the zoom level changes: * Pinch-zoom if you have a touchscreen * Zoom in/out with your mousewheel * Do a box zoom (drag with your mouse while pressing the `shift` key in your keyboard) * Use the zoom in/out buttons {% include frame.html url="example-delta.html" %} That concludes this tutorial. Now play with your zoom levels in your maps!