Saltar a contenido

El mapa sin datos. Añadir una capa base

Autores

Bing Maps

Instanciamos un mapa que nos permita ver todo el mundo

Atención

Otra de las grandes diferencias entre Leaflet y OpenLayers es que si bien ambos tienen una arquitectura muy basada en la integración de funcionalidades mediante plugins, en OpenLayers muchos de estos plugins son mantenidos por el propio core, mientras que Leaflet prefiere mantenerse más ligero y los plugins son mantenidos por la comunidad.

En Leaflet no tenemos un origen de datos Bing o Google, pero existen plugins como leaflet-bing-layer que extienden las clases nativas de Leaflet como Leaflet.TileLayer para proporcionar esa funcionalidad de forma sencilla.

En el siguiente ejemplo instanciamos un mapa con unos límites que nos permitan ver todo el mundo y añadimos el plugin para Bing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Bing Maps</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <!-- Usar está url sólo para demos, o instalar con `npm install leaflet-bing-layer` -->
    <script src="http://lab.digital-democracy.org/leaflet-bing-layer/leaflet-bing-layer.js"></script>
    <script>
        let map = L.map('map');
        map.setView([0, 0], 1);

    </script>
</body>
</html>

Instanciamos las capas de Bing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Bing Maps</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <!-- Usar está url sólo para demos, o instalar con `npm install leaflet-bing-layer` -->
    <script src="http://lab.digital-democracy.org/leaflet-bing-layer/leaflet-bing-layer.js"></script>
    <script>
        const BING_API_KEY = 'AqU3C-Sa7exTZ1zqoy25oXm8H0MFgMxG3_ZKV87ZVZcX27RIzUrNQ5rQOV1DKt3t'
        let styles = ['Road', 'Aerial', 'AerialWithLabels'];
        let baseLayers = [];
        let i, ii;
        for (i = 0, ii = styles.length; i < ii; ++i) {
            baseLayers.push(L.tileLayer.bing({
                bingMapsKey: BING_API_KEY,
                imagerySet: styles[i],
            }));
        }
        let map = L.map('map', {
            center: [0, 0],
            zoom: 1,
            // layers: baseLayers
        });

    </script>
</body>
</html>

¿Todavía no vemos nada?. Hemos instanciado las capas pero no las hemos añadido al mapa. Podríamos añadirlas como en los ejemplos anteriores con map.addLayer. Pero si descomentamos la línea layers: baseLayers empezaremos a ver algo.

La siguiente pregunta es ¿que capa estoy viendo?. Si has copiado el ejemplo tal cual será la capa AerialWithLabels, pero si abres la pestaña de Network y exploras el Preview de las llamadas verás que se están pidiendo imágenes de las tres capas. ¿Intenta responder a porqué sólo estás viendo AerialWithLabels?. Pista: Prueba a cambiar el orden de los elementos del array styles.

Atención

Al contario que en OpenLayers en Leaflet no es habitual manejar el concepto de que una capa esté añadida al mapa pero no se visualice visible: false. En Leaflet para dejar de visualizar una capa lo más habitual es eliminarla del mapa.

Existen otras opciones como jugar con los pane en los que se pinta la capa, pero mejor no entrar ahí,...

Añadimos un control sencillo para seleccionar la capa

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Bing Maps</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <select id="layer-select">
        <option value="Aerial">Aerial</option>
        <option value="AerialWithLabels" selected>Aerial with labels</option>
        <option value="Road">Road (static)</option>
    </select>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <!-- Usar está url sólo para demos, o instalar con `npm install leaflet-bing-layer` -->
    <script src="http://lab.digital-democracy.org/leaflet-bing-layer/leaflet-bing-layer.js"></script>
    <script>
        const BING_API_KEY = 'AqU3C-Sa7exTZ1zqoy25oXm8H0MFgMxG3_ZKV87ZVZcX27RIzUrNQ5rQOV1DKt3t'
        let styles = ['Road', 'Aerial', 'AerialWithLabels'];
        let baseLayers = [];
        let i, ii;
        for (i = 0, ii = styles.length; i < ii; ++i) {
            baseLayers.push(L.tileLayer.bing({
                bingMapsKey: BING_API_KEY,
                imagerySet: styles[i],
            }));
        }
        let map = L.map('map', {
            center: [0, 0],
            zoom: 1,
        });
        let select = document.getElementById('layer-select');
        const onChange = () => {
            let style = select.value;
            for (let i = 0, ii = baseLayers.length; i < ii; ++i) {
                if (styles[i] === style) {
                    map.addLayer(baseLayers[i])
                } else {
                    map.removeLayer(baseLayers[i]);
                }
            }
        }
        select.addEventListener('change', onChange);
        onChange();

    </script>
</body>
</html>

Vuelve a abrir la pestaña de Network al moverte sobre el mapa. Ahora no añadimos todas las capas si no sólo la que hemos seleccionado, y eliminamos las demás del mapa. De este modo sólo pedimos al servidor lo que nos interesa.

Extra. El selector de capas nativo de leaflet

En lugar de usar código a medida para el selector de capas hemos usado usamos el de Leaflet. Hay muchos plugins de este estilo que aportan opciones adicionales. Jugaremos más con controles de capas en capítulos posteriores.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Bing Maps</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <!-- Usar está url sólo para demos, o instalar con `npm install leaflet-bing-layer` -->
    <script src="http://lab.digital-democracy.org/leaflet-bing-layer/leaflet-bing-layer.js"></script>
    <script>
        const BING_API_KEY = 'AqU3C-Sa7exTZ1zqoy25oXm8H0MFgMxG3_ZKV87ZVZcX27RIzUrNQ5rQOV1DKt3t'
        let styles = ['Road', 'Aerial', 'AerialWithLabels'];
        let baseLayers = {};
        let i, ii;
        for (i = 0, ii = styles.length; i < ii; ++i) {
            baseLayers[styles[i]] = L.tileLayer.bing({
                bingMapsKey: BING_API_KEY,
                imagerySet: styles[i],
            });
        }
        let map = L.map('map', {
            center: [0, 0],
            zoom: 1,
            layers: [baseLayers['Road']]
        });
        L.control.layers(baseLayers).addTo(map);

    </script>
</body>
</html>

Atención

Un par de conceptos importantes en este ejemplo.

El control de leaflet hace que sólo una capa base puede estar activa a la vez en un mapa. Mientras que puedes tener tantos overlays como quieras.

Añadimos una capa base de forma inicial para que al cargar el mapa se vea algo. También podríamos haberlo hecho con map.addLayer(baseLayers[0]). En el ejemplo anterior se forzaba esta situación llamando a onChange() a mano.

Google Maps

Usaremos el plugin Leaflet.GridLayer.GoogleMutant para visualizar capas de Google.

Debemos incluir el js del plugin y el js de la API Google Maps. Además usamos el selector de capas de Leaflet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Google Maps</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCqPQ0dabDFcqSrjGVLvWGyDU3RSgAXayo" async defer></script>
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <script src='https://unpkg.com/leaflet.gridlayer.googlemutant@latest/Leaflet.GoogleMutant.js'></script>
    <script>
        let baseLayers = {
            'Google Roads': L.gridLayer.googleMutant({
                type: 'roadmap'
            }),
            'Google Satellite': L.gridLayer.googleMutant({
                type: 'satellite'
            }),
            'Google Terrain': L.gridLayer.googleMutant({
                type: 'terrain'
            }),
            'Google Hybrid': L.gridLayer.googleMutant({
                type: 'hybrid'
            }),
        }
        let map = L.map('map').setView([0, 0], 1);
        baseLayers['Google Roads'].addTo(map);
        L.control.layers(baseLayers).addTo(map);

    </script>
</body>
</html>

Mapbox

Primero añadiremos una simple capa de Mapbox.

En este caso usamos la opción de L.tileLayer que nos permite usar placeholders en la configuración de la url, que pasamos al constructor mediante el parámetro de options. Es lo que estamos haciendo en este caso con el accessToken y el identificador de estilo del mapa a usar.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Mapbox y Leaflet</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <script>
        let map = L.map('map').setView([0, 0], 1);
        L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/256/{z}/{x}/{y}?access_token={accessToken}', {
            attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
            id: 'streets-v10',
            accessToken: 'pk.eyJ1IjoibWljaG9nYXIiLCJhIjoiY2ptN3UzNXJnMDhpcDNrbm9tczlibDMzbCJ9.zr2VPbydp2PhiAG5UxVn4w'
        }).addTo(map);

    </script>
</body>
</html>

Escoger entre varios estilos de capas de Mapbox

Similar a los ejemplos de Google y Bing, Mapbox también nos ofrece la opción de cargar distintos estilos/capas. La variable styles contiene el nombre de algunos de estos estilos.

A continuación construímos un array baseLayers con una instancia de L.TileLayer por cada estilo. Instanciamos un mapa "mundial".

Y por darle un poco de chicha, empleamos un nuevo plugin de selección de capas: Leaflet.BaseMaps. En la documentación del plugin se especifica que añade al mapa al primer elemento de la lista por lo que no es necesario hacerlo a mano.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Mapbox y Leaflet</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <!-- User esta url sólo para demos -->
    <link rel="stylesheet" href="https://consbio.github.io/Leaflet.Basemaps/L.Control.Basemaps.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <!-- User esta url sólo para demos -->
    <script src='https://consbio.github.io/Leaflet.Basemaps/L.Control.Basemaps.js'></script>
    <script>
        let styles = ['basic', 'streets', 'bright', 'light', 'dark', 'satellite'];
        const baseUrl = 'https://api.mapbox.com/styles/v1/mapbox/{style}-v9/tiles/256/{z}/{x}/{y}?access_token={accessToken}';
        const attribution = 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>';
        const accessToken = 'pk.eyJ1IjoibWljaG9nYXIiLCJhIjoiY2ptN3UzNXJnMDhpcDNrbm9tczlibDMzbCJ9.zr2VPbydp2PhiAG5UxVn4w';
        var baseLayers = styles.map(style => L.tileLayer(baseUrl, {
            attribution,
            style,
            accessToken,
            label: style,
        }));
        let map = L.map('map').setView([0, 0], 1);
        L.control.basemaps({
            basemaps: baseLayers,
            tileX: 0,
            tileY: 0,
            tileZ: 1,
        }).addTo(map)

    </script>
</body>
</html>

Atención

Te has fijado en los parámetros de tileX, tileY, tileZ del plugin. Recuperan una tile concreta del servidor de mapas que se usará como previsualización, ie:

https://api.mapbox.com/styles/v1/mapbox/basic-v9/tiles/256/1/0/0?access_token=pk.eyJ1IjoibWljaG9nYXIiLCJhIjoiY2ptN3UzNXJnMDhpcDNrbm9tczlibDMzbCJ9.zr2VPbydp2PhiAG5UxVn4w

Veremos el formato XYZ más adelante pero prueba a cambiar esos números y ver que pasa.

Servicios de mapas locales. PNOA

PNOA

Instanciamos un mapa en una posición en la que se muestre Vigo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>PNOA y Leaflet</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <script>
        let map = L.map('map').setView([40.2, -3.6], 6);

    </script>
</body>
</html>

Y añadimos la capa.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>PNOA y Leaflet</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css">
    <style>
        html,
        body,
        .map {
            height: 100%;
            margin: 0px;
        }

    </style>
</head>
<body>
    <div id="map" class="map"></div>
    <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
    <script>
        let map = L.map('map').setView([40.2, -3.6], 6);
        let pnoaOrthoWMS = L.tileLayer.wms('http://www.ign.es/wms-inspire/pnoa-ma?', {
            layers: 'OI.OrthoimageCoverage',
            attribution: 'PNOA cedido por © <a href="http://www.ign.es/ign/main/index.do" target="_blank">Instituto Geográfico Nacional de España</a>'
        }).addTo(map);

    </script>
</body>
</html>

Leaflet tiene su propio tipo de capa WMS para acceder a este tipo de servicios. Tan sólo debemos conocer la url base y la(s) capa(s) que queremos solicitar.

Si tienes interés en WMS el [tutorial de Leaflet](https://leafletjs.com/examples/wms/wms.html al respecto contiene mucha información de interés

Si buscas una forma fácil de añadir más WMS de España este es tu plugin.

¿Por qué en Leaflet no he tenido que transformar las coordenadas geográficas?

Leaflet usa por defecto internamente el CRS EPSG:3857 (coordenadas proyectadas, esos números tan grandes). Pero sus métodos para obtener y setear los límites de la vista, la posición del centro del mapa, etc... funcionan todos con coordenadas geográficas. Leaflet hace la transformación de coordenadas de forma transparente para el usuario en este caso.

https://github.com/Leaflet/Leaflet/blob/master/src/layer/tile/TileLayer.WMS.js#L106