Leaflet.TileLayer.Swiss is a Leaflet plugin for displaying national maps of Switzerland using map tiles from Swisstopo. This plugin is not affiliated with or endorsed by Swisstopo.
The following code explains all steps required to get started with Leaflet.TileLayer.Swiss. It corresponds to the example at the top of the page. In order to run it locally, copy the 2 files below into a folder on your computer, then open quick-start.html
in your browser.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Quick start</title>
<!-- Include Leaflet CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.css"
crossorigin integrity="sha384-o/2yZuJZWGJ4s/adjxVW71R+EO/LyCwdQfP5UWSgX/w87iiTXuvDZaejd3TsN7mf">
<style>
/* Set full width and height for the map */
, body, #mapid { height: 100%; margin: 0; }
html</style>
</head>
<body>
<!-- Element where the map will be attached -->
<div id="mapid"></div>
<!-- Include Leaflet and Leaflet.TileLayer.Swiss JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.js"
crossorigin integrity="sha384-okbbMvvx/qfQkmiQKfd5VifbKZ/W8p1qIsWvE1ROPUfHWsDcC8/BnHohF7vPg2T6">
</script>
<script src="https://cdn.jsdelivr.net/npm/leaflet-tilelayer-swiss@2.3.0/dist/Leaflet.TileLayer.Swiss.umd.js"
crossorigin integrity="sha384-M4p8VfZ8RG6qNiPYA3vOCApQXAlLtnJXVPdydMYPAsvvIDsWp2dqqzF2OEeWWNhy">
</script>
<!-- Include quick start JavaScript -->
<script src="quick-start.js"></script>
</body>
</html>
// Create map and attach id to element with id "mapid"
var map = L.map('mapid', {
// Use LV95 (EPSG:2056) projection
crs: L.CRS.EPSG2056,
;
})
// Add Swiss layer with default options
.tileLayer.swiss().addTo(map);
L
// Center the map on Switzerland
.fitSwitzerland();
map
// Add a marker with a popup in Bern
.marker(L.CRS.EPSG2056.unproject(L.point(2600000, 1200000))).addTo(map)
L.bindPopup('Bern')
.openPopup();
You can either include this plugin from a Content Delivery Network (CDN) as shown above, or download the latest version of Leaflet.TileLayer.Swiss and host your own copy.
If you are using npm, use this command to install:
npm install leaflet-tilelayer-swiss
A map layer from this plugin is created like this:
var swissLayer = L.tileLayer.swiss(/* options */);
// The layer also needs to be added to a map
.addTo(map); swissLayer
If you do not pass any options, you get the default base map layer:
var baseMapLayer = L.tileLayer.swiss();
Swisstopo offers many other layers in addition to the default base map.
// Satellite image layer
var satelliteLayer = L.tileLayer.swiss({
layer: 'ch.swisstopo.swissimage',
maxNativeZoom: 28
;
})
// Cycling route overlay
var cyclingOverlay = L.tileLayer.swiss({
format: 'png',
layer: 'ch.astra.veloland',
maxNativeZoom: 26,
opacity: 0.5
;
})
// Historic base map from the year 2010
var historicMap2010 = L.tileLayer.swiss({
format: 'png',
layer: 'ch.swisstopo.zeitreihen',
maxNativeZoom: 26,
timestamp: '20101231'
; })
Note that options must correspond to what is available on Swisstopo servers, e.g. if you specify format: 'jpeg'
for the historic base map, it will not work. See layer list below to find correct combinations of options.
Overview of all available options with their default values:
.tileLayer.swiss({
L// Attribution. The required attribution to Swisstopo is added by default.
attribution: '© <a href="https://www.swisstopo.ch/">Swisstopo</a>',
// Coordinate reference system. EPSG2056 and EPSG21781 are available.
crs: L.CRS.EPSG2056
// Image format (jpeg or png). Only one format is available per layer.
format: 'jpeg',
// Layer name.
layer: 'ch.swisstopo.pixelkarte-farbe',
// Minimum zoom. Levels below 14 exist for technical reasons,
// but you probably do not want to use them.
minZoom: 14,
// Maximum zoom. Availability of zoom levels depends on the layer.
maxNativeZoom: 27,
// Plugin attribution. Display a small Swiss flag with a link to this plugin. 🇨🇭
// (Like the "🇺🇦 Leaflet" prefix, this is enabled by default but not required)
pluginAttribution: true,
// Timestamp. Most (but not all) layers have a 'current' timestamp.
// Some layers have multiple versions with different timestamps.
timestamp: 'current',
// Map tile URL. Appropriate defaults are chosen based on the crs option.
url: 'https://wmts{s}.geo.admin.ch/1.0.0/{layer}/default/{timestamp}/2056/{z}/{x}/{y}.{format}'
; })
LV95 is the new reference frame used in Switzerland since 2016. LV95 coordinates are by convention designated by the letters E
for the easting and N
for the northing, with origin at E = 2 600 000 m
/ N = 1 200 000 m
. The origin is not at 0 / 0
to avoid confusion between easting and northing, this is sometimes called “false easting” and “false northing”.
LV95 is the CRS in which Swiss maps are currently produced, and is the default for this plugin. While it is technically possible to reproject maps to another CRS, this always involves changes in scale and/or rotation and decreases the quality of the map.
Leaflet uses EPSG codes to refer to CRS. This plugin adds LV95 as a Leaflet CRS:
.CRS.EPSG2056; L
Leaflet always uses geographic coordinates, aka latitude and longitude to refer to points on the map.
If you already know the geographic coordinates of your points, you can use them directly:
// Add a marker in Zurich
.marker([47.378, 8.538]).addTo(map);
L
// Center the map on Bern
.setView([46.951, 7.439], 20); map
If your points are in LV95, they have to be transformed to geographic coordinates first by creating a Leaflet Point and calling unproject()
:
// Add a marker in Zurich
.marker(L.CRS.EPSG2056.unproject(L.point(2683000, 1248000))).addTo(map);
L
// Center the map on Bern
.setView(L.CRS.EPSG2056.unproject(L.point(2600000, 1200000)), 20); map
If you receive coordinates from Leaflet, e.g. from a click event, you will also get geographic coordinates. Call project()
to transform them to LV95. Note that it returns a Leaflet Point, so coordinates have to be accessed using the x
and y
attributes:
.on('click', function (event) {
mapvar latlng = event.latlng;
var EN = L.CRS.EPSG2056.project(latlng);
console.log('Clicked on (lat/lng): ' + latlng.lat + '/' + latlng.lng);
console.log('Clicked on (E/N): ' + EN.x + '/' + EN.y);
; })
The old Swiss CRS, LV03 (EPSG code 21781), is also added by this plugin. You will probably not need this:
.CRS.EPSG21781; L
This plugin adds a convenience function to the Leaflet Map interface to set the map view, such that the entire country is visible.
.fitSwitzerland(); map
The list of all available map layers is currently available on a separate page.
Uses the mix-blend-mode CSS property with value multiply
to add outdoor route overlays without hiding map details underneath.
Uses the leaflet-hash plugin to encode the current map view in the URL. Shows LV95 coordinates of current mouse position and opens a popup with projected and geographic coordinates when the user clicks on the map.
This plugin uses Swisstopo base maps and other datasets available through Swisstopo’s Web Map Tile Service (WMTS).
Technically, this means that small square images are loaded from Swisstopo servers. Careful observers will notice requests to URLs starting with https://wmts{n}.geo.admin.ch
in their browser developer tools.
Since 2021-03-01, this data is available for free under an open license as part of Swisstopo’s Open Government Data (OGD) strategy. Please note that the following terms apply:
© Swisstopo
is added below the map by this plugin by default in order to comply with the OGD terms of use.
© Roman Karavia, MIT license
Thanks to Swisstopo, the Geoinformation Act, and the Ordinance on geoinformation for providing excellent geodata.
Thanks to @procrastinatio whose blog post taught me how to use Swisstopo layers in Leaflet a few year ago.