"The explosive growth of the GeoWeb and geographic information has made GIS powerful media for the general public to communicate, but perhaps more importantly, GIS have also become media for constructive dialogs and interactions about social issues." - Sui & Goodchild
This is an old revision of the document!
Avec OpenLayers (acronyme OL3, http://openlayers.org), on monte d'un niveau dans la pyramide de productivité. Il s'agit d'une librairie permettant de fabriquer une carte en ligne par un ensemble de couches associée à des contrôles pour gérer l'interaction avec l'utilisateur. Une carte se construit avec trois ingrédients de base : du balisage HTML, des déclarations de style CSS, et du code JavaScript.
Pour la suite, le point d'entrée pour se documenter sur l'utilisation de cette API est ici (en version 3.19.1 3.20.1 pour ce tutoriel) : (docs/API, examples, code). Aussi, profitez de cette présentation OL3 partagée par les collègues du département Géomatique.
<html> <head> <title>ol3 - Create a first map with an OGC WMS layer</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function () { map = new ol.Map({ target: 'map' }); var wmsLayer = new ol.layer.Image({ source: new ol.source.ImageWMS({ url: blWMS, ratio: 1, params: { VERSION: "1.0.0", LAYERS: "ne_10m_admin_0_countries", FORMAT: "image/png" } }) }); map.addLayer(wmsLayer); // Configuration of the map view var v0 = new ol.View({projection: "EPSG:4326"}); var extent_init = [-18, 37, 38, 57]; // or v0.getProjection().getExtent(); v0.fit(extent_init, map.getSize()); map.setView(v0); //showExtent(extent_init); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
var v2 = new ol.View({projection: "EPSG:4326"}); var cbox = [10, 47]; // NB: c'est le centre de l'extent_init ci-dessus v2.setCenter(cbox); v2.setZoom(5); map.setView(v2);
map.getView().setCenter(ol.proj.transform([10, 47], "EPSG:4326", "EPSG:3857")); map.getView().setZoom(5); console.log(map.getView().getProjection().getCode());
var wmsLayer = new ol.layer.Tile({ source: new ol.source.TileWMS({ url: blWMS, ratio: 1, params: { VERSION: "1.0.0", LAYERS: "ne_10m_admin_0_countries", FORMAT: "image/png" } }) });
Avec une source ol.source.TileWMS c'est le client qui contrôle une grille de tuiles et il peut la garder en cache. Néanmoins, à chaque requête initiale de tuile, tout le processus de rendu cartographique se fait. Mais puisqu'une couche de tuiles fait des requêtes d'images selon une grille régulière, il est possible pour le serveur de préparer un cache de ces images.
Le service cartographique WMS permet une grande flexibilité en terme de ce que le client peut demander. Côté serveur, cela rend difficile la mise en cache. A l'extrême opposé, un service peut aussi offrir des tuiles pour un ensemble prédéfini de niveaux de zoom et pour une grille régulière prédéfinie. On parle de couches de tuiles avec une source XYZ - avec X et Y indiquant la colonne et la rangée de la grille et Z le niveau de zoom. Il faut voir cela comme une pyramide de tuiles.
<html> <head> <title>ol3 - webmap with layer from tile server</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function(){ map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ] }); map.getView().setCenter(ol.proj.transform([6.15,46.2],"EPSG:4326","EPSG:3857")); map.getView().setZoom(10); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO http://localhost/geoinf/oltuto18/Ex2a.html
source: new ol.source.OSM({ url:"http://api.tiles.mapbox.com/v3/oertz.map-i2ak2ozc/{z}/{x}/{y}.png", attributions: [ new ol.Attribution({ html: "Restyled & based on <a href='www.openstreetmap.org'>OpenStreetMap</a>" }) ] })
et ajouter l'instruction CSS suivante :
.ol-attribution { background-color: CornflowerBlue !important; right: 10px; left: initial; bottom: initial; top: 10px; }
source: new ol.source.XYZ({ url: "http://urbangene.heig-vd.ch/tilecache/{z}/{x}/{y}.png" })
L'utilisation d'un cache serveur de tuiles a largement été popularisé par des services propriétaires comme Bing Maps. OpenLayers étant indépendant de toute source de données, l'API offre également un type de couche pour dialoguer avec de tels services. La classe ol.source.BingMaps s'occupe de construire les requêtes pour interagir avec le service de tuiles cartographiques BingMaps : https://msdn.microsoft.com/en-us/library/ff701716.aspx#Anchor_0.
TODO https://www.mediamaps.ch/oltuto/Ex2b.html
map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.BingMaps({ key: 'AqE05oJsq-bWa50FPOW2S0eQm9Oqqygc1VTi_WPhUIoKR_-jgA559CRbfndgWAIz', imagerySet: 'Aerial' }) }) ] }); map.getView().setCenter(ol.proj.transform([6.15,46.2],"EPSG:4326","EPSG:3857")); map.getView().setZoom(10);
Some imagerySet values: - AerialWithLabelsOnDemand - RoadOnDemand - CanvasGray - OrdnanceSurvey (notice: visible only for the London area) - ...
source: new ol.source.XYZ({ url: "http://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}" })
… mais pas de ol.source.GoogleMaps ? La réponse ici https://github.com/openlayers/ol3/issues/2205 et ici https://gist.github.com/elemoine/e82c7dd4b1d0ef45a9a4.
Swisstopo offre un service de tuiles basé sur le standard WMTS et que l'on peut exploiter comme suit.
<html> <head> <title>ol3 - webmap with Swisstopo WMTS</title> <script type="text/javascript" src="js/config.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/proj4js/2.2.1/proj4.js"></script> <script src="http://epsg.io/21781.js"></script> <script type="text/javascript"> var map; $(document).ready(function () { var projection = ol.proj.get('EPSG:21781'); projection.setExtent([485869.5728, 76443.1884, 837076.5648, 299941.7864]); map = new ol.Map({ target: 'map', view: new ol.View({ projection: ol.proj.get("EPSG:21781"), center: [600000, 200000], zoom: 6 }) }); var tileGrid = new ol.tilegrid.WMTS({ origin: [420000, 350000], resolutions: [4000, 3750, 3500, 3250, 3000, 2750, 2500, 2250, 2000, 1750, 1500, 1250, 1000, 750, 650, 500, 250, 100, 50, 20, 10, 5, 2.5, 2, 1.5, 1, 0.5], matrixIds: [0, 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] }); var layer = new ol.layer.Tile({ source: new ol.source.WMTS(({ url: "http://wmts.geo.admin.ch/1.0.0/{Layer}/default/20140520/21781/{TileMatrix}/{TileRow}/{TileCol}.jpeg", tileGrid: tileGrid, layer: "ch.swisstopo.pixelkarte-farbe", requestEncoding: 'REST' })) }); map.addLayer(layer); console.log(map.getView().getProjection().getCode()); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO https://www.mediamaps.ch/oltuto/Ex2c.html
navigator.geolocation.getCurrentPosition(locationFixed, locationError);
ainsi que les deux fonctions callback qui vont avec :
function locationFixed(position) { map.getView().setCenter(ol.proj.transform([position.coords.longitude, position.coords.latitude],"EPSG:4326","EPSG:21781")); } function locationError(e) { console.log(e); }
{ "considerIp": "false", "wifiAccessPoints": [ { "macAddress": "00:25:9c:cf:1c:ac" }, { "macAddress": "00:25:9c:cf:1c:ad" } ] }
Dans la section précédente, la composition de couches est pilotée “une fois pour toute” côté serveur. Ci-dessous un pilotage de la composition “à la demande” côté client (et donc plus il y a de couches disponibles sur le serveur cartographique, plus il y a de combinaisons possibles).
<html> <head> <title>ol3 - one WMS request for two layers</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function(){ map = new ol.Map({ target: 'map', layers: [ new ol.layer.Image({ source: new ol.source.ImageWMS({ url: mcWMS, params:{ VERSION: "1.1.1", LAYERS: 'public.world_simple,public.cities', FORMAT: 'image/png' } }), }) ] }); // default view is used here, that is with the Mercator EPSG:3857 projection map.getView().setCenter(ol.proj.transform([7, 47],"EPSG:4326","EPSG:3857")) map.getView().setZoom(5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
Une application de cartographie en ligne se doit de permettre à l'utilisateur de personnaliser sa carte par ses choix pour la couche de référence (baselayer) et les couches à activer en superposition (overlays). Elle doit fournir la capacité de gérer la composition côté client.
<html> <head> <title>ol3 - two WMS overlayed layers</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function () { map = new ol.Map({ target: 'map', layers: [ new ol.layer.Image({ title: 'World simple', source: new ol.source.ImageWMS({ url: mcWMS, params: { VERSION: "1.1.1", LAYERS: 'public.world_simple', FORMAT: 'image/png' } }) }), new ol.layer.Image({ title: 'Cities', source: new ol.source.ImageWMS({ url: mcWMS, params: { VERSION: "1.1.1", LAYERS: 'public.cities', FORMAT: 'image/png' } }) }) ] }); map.getView().setCenter(ol.proj.transform([7, 47], "EPSG:4326", "EPSG:3857")) map.getView().setZoom(5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO https://www.mediamaps.ch/oltuto/Ex3b.html
new ol.layer.Image({ title: "Countries", source: new ol.source.ImageWMS({ url: blWMS, params: { VERSION: "1.0.0", LAYERS: "ne_10m_admin_0_countries", FORMAT: "image/png" } }) }), new ol.layer.Image({ title: "Lakes", source: new ol.source.ImageWMS({ url: blWMS, params: { VERSION: "1.0.0", LAYERS: "ne_10m_lakes", FORMAT: "image/png" } }) })
Visualiser le résultat. Qu'est-ce qui est “baselayer”, qu'est-ce qui est “overlays” ?
OL3 n'offre pour l'instant pas nativement de “UI manager” de composition cartographique. Néanmoins l'API offre ce qu'il faut pour concevoir son propre LayerSwitcher.
<html> <head> <title>ol3 - MyLayerSwitcher</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map, lyrs; $(document).ready(function () { map = new ol.Map({ target: 'map', layers: [ new ol.layer.Image({ source: new ol.source.ImageWMS({ url: blWMS, params: { VERSION: "1.0.0", LAYERS: "ne_10m_admin_0_countries", FORMAT: "image/png" } }), }), new ol.layer.Image({ source: new ol.source.ImageWMS({ url: mcWMS, params: { VERSION: "1.1.1", LAYERS: 'public.world_simple', FORMAT: 'image/png' } }) }), new ol.layer.Image({ source: new ol.source.ImageWMS({ url: blWMS, params: { VERSION: "1.0.0", LAYERS: "ne_10m_lakes", FORMAT: "image/png" } }), }), new ol.layer.Image({ source: new ol.source.ImageWMS({ url: mcWMS, params: { VERSION: "1.1.1", LAYERS: 'public.cities', FORMAT: 'image/png' } }) }) ] }); map.getView().setCenter(ol.proj.transform([7, 47], "EPSG:4326", "EPSG:3857")) map.getView().setZoom(5); initMyLayerSwitcher(); }); /*** * initMyLayerSwitcher: a first attempt to manage baselayers and overlayers. * * Remark: in the current state, the main drawback is that it is absolutly * not flexible and adaptative! * * @returns {undefined} */ function initMyLayerSwitcher(){ lyrs = map.getLayers().getArray(); // Set visibility of the baselayer lyrs[0].setVisible(true); lyrs[1].setVisible(false); // Set visibility of the overlays lyrs[2].setVisible(false); lyrs[3].setVisible(false); $('#overlay option').prop('selected', false); // Define the callback when the user does change the baselayer $("#base").change(function (e) { // Reset all baselayers lyrs[0].setVisible(false); lyrs[1].setVisible(false); // Activate the one that is selected (based on index) var idxVisible = $(this).find(":selected").index(); lyrs[idxVisible].setVisible(true); }); // Define the callback when the user does change the overlays $("#overlay").change(function (e) { $(this).find("option").each(function (i, e) { // i + 2 because the 1st and 2nd elements in the table of layers are the baselayers lyrs[i + 2].setVisible(e.selected); }); }); } </script> <style type="text/css"> #map { width: 80%; height: 100%; } #switcher { position: absolute; left: 82%; top: 2%; } </style> </head> <body> <div id="map"></div> <div id="switcher"> <p>Choose baselayer:</p> <select id="base"> <option value="base1">Countries</option> <option value="base2">World simple</option> </select> <p>Choose overlays:</p> <select id="overlay" size="2" multiple> <option value="overlay1">Lakes</option> <option value="overlay2">Cities</option> </select> </div> </body> </html>
TODO https://www.mediamaps.ch/oltuto/Ex3c.html
new ol.layer.Tile({ source: new ol.source.OSM() })
opacity: 0.5
A partir des capacités offertes par l'API, la communauté de développeurs gravitant autour du core OL3 développe des controls parmi lesquels un LayerSwitcher un peu plus malin. Merci @walkermatt https://github.com/walkermatt/ol3-layerswitcher.
<html> <head> <title>ol3 - A clever LayerSwitcher</title> <script type="text/javascript" src="js/config.js"></script> <link rel="stylesheet" href="lib/layerswitcher/ol3-layerswitcher.css" type="text/css"> <script src="lib/layerswitcher/ol3-layerswitcher.js" type="text/javascript"></script> <script type="text/javascript"> var map, lyrs; $(document).ready(function () { map = new ol.Map({ target: 'map', layers: [ new ol.layer.Image({ title: "Countries", type: "base", source: new ol.source.ImageWMS({ url: blWMS, params: { VERSION: "1.0.0", LAYERS: "ne_10m_admin_0_countries", FORMAT: "image/png" } }), }), new ol.layer.Image({ title: 'World simple', type: "base", source: new ol.source.ImageWMS({ url: mcWMS, params: { VERSION: "1.1.1", LAYERS: 'public.world_simple', FORMAT: 'image/png' } }) }), new ol.layer.Image({ title: "Lakes", source: new ol.source.ImageWMS({ url: blWMS, params: { VERSION: "1.0.0", LAYERS: "ne_10m_lakes", FORMAT: "image/png" } }), }), new ol.layer.Image({ title: 'Cities', source: new ol.source.ImageWMS({ url: mcWMS, params: { VERSION: "1.1.1", LAYERS: 'public.cities', FORMAT: 'image/png' } }) }) ] }); map.getView().setCenter(ol.proj.transform([7, 47], "EPSG:4326", "EPSG:3857")) map.getView().setZoom(5); var layerSwitcher = new ol.control.LayerSwitcher(); map.addControl(layerSwitcher); }); </script> <style type="text/css"> #map { width: 80%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO https://www.mediamaps.ch/oltuto/Ex3d.html