GIS and Media fusion

"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

User Tools

Site Tools


geoinf16:ol3tuto

Workshop OpenLayers (2016, part 1)

Dans OpenLayers (acronyme OL3, http://openlayers.org), une carte est 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 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.

1. Les éléments de base

  • Pour ce workshop, télécharger le matériel de départ geoinf16-ol3.zip
  • Décompresser l'archive dans un répertoire projet dans votre serveur web et découvrez le fichier js/config.js
  • De nombreux exemples sont basés sur les géodonnées suivantes : cities.zip, world.zip
  • Il est aussi nécessaire d'avoir les logiciels suivants fonctionnels (ou équivalents) : Firebug, REST Client
  • (optionnel) Vous pouvez télécharger la librairie OL3 en local dans le répertoire lib depuis http://openlayers.org/download/

Ex1A : créer une carte, un premier exemple pour comprendre

<html>
    <head>
        <title>ol3 - Ex1A - 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,
                        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 bbox_earth = v0.getProjection().getExtent();
                v0.fit(bbox_earth, map.getSize());
                console.log("Map extent for entire view: " + v0.calculateExtent(map.getSize()));
                map.setView(v0);
                showExtent(bbox_earth);
            });
        </script>
        <style type="text/css">        
            #map {
                width: 100%;
                height: 100%;
            }            
        </style>   
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

Balisage HTML et déclarations CSS

  • Le bloc <div> d'ID map est la cible de visualisation (la vue cartographique)
  • C'est la position et la taille de cette div qui déterminent comment la vue s'intègre dans l'interface
  • OpenLayers est accompagné de nombreuses prédéfinitions de déclarations CSS

TODO (I)

  1. Repérez les déclarations qui habillent les boutons zoomin/zoomout !
  2. Ajustez-les de sorte que ces boutons ressemblent à ça :

Initialisation de la carte

  • L'objet ol.Map est associé à l'ID de la cible de visualisation
  • L'objet ol.View représente la vue 2D de la map. Il permet de définir le centre, la résolution et la rotation de la map
  • L'objet ol.Layer est utilisé pour définir chaque couche à ajouter à la carte
  • L'objet ol.source.ImageWMS permet de définir les paramètres d'une requête WMS pour obtenir une couche servie par un serveur cartographique conforme au standard OGC WMS (http://www.opengeospatial.org/standards/wms)
  • La méthode fit termine l'initialisation en calculant l'enveloppe géographique de visualisation

TODO (II)

  1. Remplacer la configuration de la map view (v1) comme suit
    var v1 = new ol.View({projection: "EPSG:4326"});
    bbox = [-18, 38, 38, 55];
    v1.fit(bbox, map.getSize());
    console.log("Map extent for entire view: " + v1.calculateExtent(map.getSize()));
    map.setView(v1);
    showExtent(bbox);

    Jouez avec la taille de la fenêtre en rafraîchissant le navigateur à chaque fois.

  2. Remplacer la configuration de la map view (v2) comme suit
    var v2 = new ol.View({projection: "EPSG:4326"});
    var cbox = [10, 46.5]; // NB: c'est le centre de bbox ci-dessus
    v2.setCenter(cbox);
    v2.setZoom(5);
    map.setView(v2);

    De même, jouez avec la taille de la fenêtre en rafraîchissant le navigateur à chaque fois. Quelle différence avec la map view (v1) ?

TODO (III)

  1. Revenir à la configuration de la map view (v0) en adaptant le système de projection avec la projection dite Mercator comme suit
    var v0 = new ol.View({projection: "EPSG:3857"});

    Comparez avec précédemment.

  2. Revenir à la configuration de la map view (v1) et ajouter le callback ci-dessous :
    // Change, live, the view projection
    $(document).keypress(function () {
        if (map.getView().getProjection().getCode() === "EPSG:3857") {
            v0 = new ol.View({projection: "EPSG:4326"});
            var new_bbox = bbox;
        } else {
            v0 = new ol.View({projection: "EPSG:3857"});
            var new_bbox = ol.proj.transformExtent(bbox, "EPSG:4326", "EPSG:3857");
        }
        v0.fit(new_bbox, map.getSize());
        map.setView(v0);
        showExtent(new_bbox);
    });

TODO (IV)

  1. Supprimer le callback précédent et redéfinir la couche wmsLayer comme suit :
    var wmsLayer = new ol.layer.Tile({
        source: new ol.source.TileWMS({
            url: blWMS,
            params: {
                VERSION: "1.0.0",
                LAYERS: "ne_10m_admin_0_countries",
                FORMAT: "image/png"
            }
        }),
    })

    Quelle différence en ajoutant une couche Tile plutôt que Image?

  2. Rechercher et tester d'autres couches de serveurs cartographiques WMS, comme par exemple celui de Swisstopo (voir config.js et http://spatialreference.org/ref/epsg/21781/)

2. Cache de tuiles

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.

Ex2A : ol.source.OSM

<html>
    <head>
        <title>ol3 - Ex2A - 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()
                        })
                    ]
                });
                var extent = map.getView().getProjection().getExtent();
                map.getView().fit(extent, map.getSize());
                
                console.log("Map projection: " + map.getView().getProjection().getCode());
            });
        </script>
        <style type="text/css">        
            #map {
                width: 100%;
                height: 100%;
            }
        </style>   
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Modifier le centrage et le zoom de la carte comme suit :
    //map.getView().fit(extent, map.getSize());
    map.getView().setCenter(ol.proj.transform([6.15,46.2],"EPSG:4326","EPSG:3857"));
    map.getView().setZoom(10);
  2. Insérer en fin de code du callback ready les logs ci-dessous :
    console.log("LonLat Mercator: " + new ol.proj.transform([6.15,46.2],"EPSG:4326","EPSG:3857"));
    console.log("LonLat Google: " + new ol.proj.transform([6.15,46.2],"EPSG:4326","EPSG:900913"));
  3. Remplacer la source de la couche comme suit :
    source: new ol.source.OSM({
     url:"http://api.tiles.mapbox.com/v3/oertz.map-i2ak2ozc/{z}/{x}/{y}.png",
     attributions: [
      new ol.Attribution({
       html: "Based on <a href='www.openstreetmap.org'>OpenStreetMap</a> / MapBox restyled by oertz :: HEIG-VD"
      })
     ]
    })

    et ajouter l'instruction CSS suivante :

    .ol-attribution {
      background-color: CornflowerBlue !important;
      right: 10px;
      left: initial;
      bottom: initial;
      top: 10px;
    }
  4. Remplacer la source ol.source.OSM par une source ol.source.XYZ comme suit :
    source: new ol.source.XYZ({
      url: "http://urbangene.heig-vd.ch/tilecache/{z}/{x}/{y}.png"
    })
  5. Redéfinir la source ol.source.OSM par défaut et ajouter en fin du callback ready ce qui suit :
    defView = [];
    defView.push(new ol.View({projection: "EPSG:3857", center: new ol.proj.transform([6.865234, 45.832454], "EPSG:4326", "EPSG:3857"), zoom: 13}));
    defView.push(new ol.View({projection: "EPSG:3857", center: new ol.proj.transform([7.658360, 45.976536], "EPSG:4326", "EPSG:3857"), zoom: 14}));
    defView.push(new ol.View({projection: "EPSG:3857", center: new ol.proj.transform([86.9251707, 27.9878319], "EPSG:4326", "EPSG:3857"), zoom: 12}));
    idxAlea = Math.floor(Math.random() * 3);
    map.setView(defView[idxAlea]);    

    Rafraichissez le navigateur plusieurs fois. (a) Que se passe-t-il ? (b) Ajoutez votre(vos) vue(s) prédéfinie(s).

Ex2B : ol.source.BingMaps

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.

TODO

  1. Partir de l'état initial de l'exemple précédent en adaptant le code JavaScript comme suit :
    map = new ol.Map({
        target: 'map',
        layers: [
            new ol.layer.Tile({
                source: new ol.source.BingMaps({
                    key: 'AqE05oJsq-bWa50FPOW2S0eQm9Oqqygc1VTi_WPhUIoKR_-jgA559CRbfndgWAIz',
                    imagerySet: 'AerialWithLabels'
                })
            })
        ]
    });
    
    map.getView().setCenter(ol.proj.transform([6.15,46.2],"EPSG:4326","EPSG:3857"));
    map.getView().setZoom(10);
  2. Modifier le paramètre de type de couche selon la documentation Bing Maps (par exemple : 'OrdnanceSurvey'). Contrairement à un service WMS, le service de Bing Maps ne sait pas s'auto-décrire. Mais comme il n'y a qu'un seul service Bing Maps au monde, une documentation suffit.

Ex2C : OpenLayers.Layer.WMTS

Swisstopo offre un service de tuiles basé sur le standard WMTS et que l'on peut exploiter comme suit.

<html>
    <head>
        <title>ol3 - Ex2C - 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

  1. Ajouter l'instruction suivante :
    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);
    }
  2. Intéressant pour aider à démystifier le fonctionnement et l'utilisation de l'HTML5 Geolocation API :

3. Style de couche "image"

Pour le moment, c'est le serveur qui fait tourner son moteur cartographique pour créer une représentation image des données géographiques et ceci sur la base de styles prédéfinis. Voyons comment le client peut dire son mot et piloter le style “à distance”.

Ex3A : Styling avec WMS

Le standard WMS offre beaucoup de libertés, parfois au détriment de la performance. Comme il permet de demander ce que l'on veut en termes d'enveloppe géographique (paramètre bbox) et de style parmis un ensemble de styles pré-configurer, il est aussi possible d'envoyer au serveur cartographique des instructions personnalisées de style.

<html>
    <head>
        <title>ol3 - Ex3A - use of a custom SLD style</title>

        <link rel="stylesheet" href="https://openlayers.org/en/v3.20.1/css/ol.css" type="text/css">

        <script src="https://openlayers.org/en/v3.20.1/build/ol-debug.js" type="text/javascript"></script>
        <script src="https://code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script>

        <script type="text/javascript">
            var map;
            var mcWMS = "https://eu1.mapcentia.com/wms/oertz/public";
            var mcWFS = "https://eu1.mapcentia.com/wfs/oertz/public/4326";

            $(document).ready(function(){
                map = new ol.Map({
                    view: new ol.View({
                        projection: "EPSG:4326"
                    }),
                    target: 'map'
                });
                layer = new ol.layer.Image({
                            source: new ol.source.ImageWMS({
                                    url: mcWMS,
                                    params:{
                                        VERSION: "1.1.1",
                                        LAYERS: 'public.world_simple',
                                        FORMAT: 'image/png'
                                }
                            }),
                        });
                map.addLayer(layer);
                var extent = map.getView().getProjection().getExtent();
                map.getView().fit(extent, map.getSize());
            });
        </script>
        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Ajouter le paramètre SLD ci-dessous :
    SLD: 'http://www.mediamaps.ch/oltuto/sld/pinkWorld.sld.xml'
  2. Avec Firefox RESTClient (ou autre équivalent), lancer la requête POST suivante sur le serveur WMS mcWMS https://eu1.mapcentia.com/wms/oertz/public :
    <?xml version="1.0" encoding="UTF-8"?>
    <DescribeFeatureType version="1.1.0" service="WFS" 
                         xmlns="http://www.opengis.net/wfs" 
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                         xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> 
    	             <TypeName>public.world_simple</TypeName>
    </DescribeFeatureType> 

    puis lancer

    <?xml version="1.0" encoding="UTF-8"?>
    <GetFeature version="1.1.0" service="WFS" 
                    xmlns="http://www.opengis.net/wfs" 
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> 
    	<Query typeName="public.world_simple">
    	   <PropertyName>region</PropertyName>
    	</Query> 
    </GetFeature>
  3. Créer votre propre pinkWorld.sld.xml en y insérant l'instruction Filter suivante en début de Rule (:!: le serveur WMS doit pouvoir accéder à votre style personnalisé). Utiliser votre éditeur XML préféré type OxygenXML ou XMLSpy.
                    ...
                    <Rule>
                        <Filter xmlns="http://www.opengis.net/ogc">
                            <PropertyIsEqualTo>
                                <PropertyName>region</PropertyName>
                                <Literal>NorthAfrica</Literal>                            
                            </PropertyIsEqualTo>
                        </Filter>
                        <PolygonSymbolizer>
                        ...
  4. Ajouter la Rule suivante après la première :
                    ...
                </Rule>                
                <Rule>
                    <ElseFilter/>
                    <PolygonSymbolizer>
                        <Fill>
                            <CssParameter name="fill">#DDDDDD</CssParameter>
                            <CssParameter name="fill-opacity">1.0</CssParameter>
                        </Fill>
                        <Stroke>
                            <CssParameter name="stroke">#000000</CssParameter>
                            <CssParameter name="stroke-width">1</CssParameter>
                        </Stroke>
                    </PolygonSymbolizer>
                </Rule>
            </FeatureTypeStyle>
            ...
  5. Modifier le style pour que la Suisse soit représentée comme ci-dessous.
    1. voir la spécification Styled Layer Descriptor

Ex3B : Custom tiling service with CartoCSS

<html>
    <head>
        <title>ol3 - Ex3B - webmap with your own MapBox basemap</title>
        <script type="text/javascript" src="js/config.js"></script>
        <script type="text/javascript">
            var map;
            $(document).ready(function () {
                var token = "pk.eyJ1Ijoib2VydHoiLCJhIjoiT29aUVYyRSJ9.mz-_gaaigdhurQPHZf7fig";

                var styleIdClassic = "oertz.c80497f1";
                //var styleIdWeb = "oertz/civjyzx4o00hq2kl80xkaz832";

                map = new ol.Map({
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.XYZ({
                                // version avec le MapBox Studio "classic"
                                url: 'http://api.tiles.mapbox.com/v4/' + styleIdClassic + '/{z}/{x}/{y}.png?access_token=' + token

                                // version avec le MapBox Studio "web"
                                //url: 'https://api.mapbox.com/styles/v1/' + styleIdWeb + '/tiles/256/{z}/{x}/{y}?access_token=' + token
                            })
                        })
                    ],
                    target: 'map',
                    view: new ol.View({
                        center: ol.proj.transform([6.7, 46.7], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 10
                    })
                });
            })
        </script>        
        <style type="text/css">        
            #map {
                width: 100%;
                height: 100%;
            }
        </style>   
    </head>
    <body>
        <div id="map">
        </div>
    </body>
</html>

TODO

  1. Suivre les exercices proposés en fin du document d'introduction à MapBox et CartoCSS de J.Freyre
    1. le shapefile pour l'exercice 3 est ici g4cantons.zip
    2. exemple de rendu pour l'exercice 4
  2. Modifier le code nécessaire ci-dessus pour créer une application de webmapping utilisant votre style MapBox.

Corrigés des exercices MapBox/CartoCSS

  • Ex1: Dans la sidebar Layers du studio on découvre qu'il y a effectivement une couche de géodonnées nommé building. Définissons un style pour représenter ses entités :
        #building {
         polygon-fill: #c1b0ad;
        }

    On voit que la couche landuse dispose d'une propriété class dont l'une des valeurs peut être 'parks'. Définissons un style ne représentant que ces parcs :

        #landuse[class='parks'] {
         polygon-fill: #6db569;
        }

    La couche poi_label a une propriété name qui sert d'étiquette :

        #poi_label[zoom>=19] {
         text-name: '[name]';
         text-face-name: @sans_bold;
         text-size: 14;
        }

    Ce sont les couches road, tunnel et bridge qui vous servir comme suit :

        #road,
        #bridge,
        #tunnel {
          [class='motorway'],[class='motorway_link'] {
            line-color: #fc8;
            line-width: 3px;
          }
        }
  • Ex2: En utilisant les couches liés aux “thèmes” mapbox.mapbox-terrain-v1 et mapbox.mapbox-streets-v5, on ajoute aux layers de l'exercice 1 les couches hillshade, (?) et contour. On représente les courbes de niveaux de cette dernière comme suit :
    #contour[zoom>=14] {
      line-color: #b7b7b7;
      line-width: 1;
      text-name: '[ele]';
      text-face-name: @sans;
      text-fill: #838383;
      text-size: 12;
      text-placement: line;
      [index=5],[index=10] {
        line-width: 3;
      }
    }
  • Ex3: Le chargement de la source de géodonnées “dans MapBox” démarre une phase de découpage des données en tuiles vectoriels selon un découpage en pyramide (appelé gridset par MapBox). Il ne reste donc plus qu'à habiller ces tuiles vectoriels avec un style pour produire la pyramide des tuiles images qui seront demandées à la volée par les clients cartographiques.
  • Ex4: Après initialisation d'un nouveau style par la composition des couches des thèmes mapbox.mapbox-streets-v5,oertz.4bf1beab, on peut construire le style “by night” suivant : mynightstyle.mss.zip

4. Composition de couches

Ex4A : Composition "server-side"

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 - Ex4A - 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>

TODO

  1. Vérifier que la composition est bien faite côté serveur.
  2. Quel intérêt à utiliser cette technique ? Quels inconvénients ? Utilise-t-on tout le potentiel d'un client navigateur pour faciliter la composition “à la demande” par l'utilisateur ?

Ex4B : Composition "client-side"

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 - Ex4B - 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

  1. Apporter la preuve que l'assemblage s'est fait côté client.
  2. Analyser les paramètres WMS. Lequel représente l'indispensable capacité “server-side” pour permettre l'assemblage client-side par superposition ? Que constate-t-on aussi et plus généralement par rapport à ce paramètre ?
  3. Ajouter dans la table des couches les ne_10m_admin_0_countries et ne_10m_lakes du GeoServer de Boundless (blWMS) comme suit :
    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” ?

  4. Remettre un peu d'ordre là où c'est possible.

Ex4C : Gestion de composition cartographique - LayerSwitcher

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 - Ex4C - 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

  1. Analyser le code ci-dessus et identifier la principale capacité “client-side” de l'API sur laquelle repose ce LayerSwitcher.
  2. Adapter le code pour ajouter à l'équation la couche OSM suivante :
    new ol.layer.Tile({
        source: new ol.source.OSM()
    })
  3. Ajouter la propriété ci-dessous à la couche des lacs
    opacity: 0.5

Ex4D : Un contrôle LayerSwitcher plus souple

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.

<html>
    <head>
        <title>ol3 - Ex4D - 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

  1. Comment fonctionne ce ol3-layerswitcher ? (remarquez quelques nouvelles propriétés intéressantes sur ol.layer).
  2. Ajouter une baselayer sur un base Bing Maps comme vu à l'Ex2B (ex. Aerial)
  3. Ajouter un overlay basé sur la couche ch.swisstopo.pixelkarte-pk25.metadata-kartenblatt servie par le serveur WMS http://wms.geo.admin.ch de Swisstopo (chWMS, voir aussi la doc GeoAdmin)

    Illustration du résultat attendu :
  4. Utiliser la couche WMS world_simple en overlay en ne visualisant que les frontières des pays (pas de remplissage des zones).
  5. Ajouter une baselayer MapBox comme celle avec le mapID mapbox.pencil (voir https://www.mapbox.com/developers/api/maps/#mapids)
  6. Ajouter un overlay basé sur une couche MapBox de votre cru notamment avec le 3e exercice du tutoriel MapBox/CartoCSS (voir Ex3B, avec votre couche g4cantons)

Ex4E : CartoCSS "à la demande" avec CartoDB

Jusqu'à présent, les styles CartoCSS devaient être préparés et chargés avec le Studio vers un compte MapBox. Sur le même principe que WMS/SLD, la suite montre une approche plus souple permettant de définir “à la demande” le style à appliquer sur une couche de géodonnées chargées sur un compte CartoDB.

A partir de l'API CartoDB on peut construire une ol.layer.Tile ayant comme source la pyramide de tuiles construite par CartoDB sur la base des données de la couche des districts de Suisse https://ogo.cartodb.com/tables/g4districts98/public.

<html>
    <head>
        <title>ol3 - Ex4E - On demand CartoCSS</title>       
        <script type="text/javascript" src="js/config.js"></script>

        <script src="http://libs.cartocdn.com/cartodb.js/v3/3.11/cartodb.core.js"></script>

        <script type="text/javascript">
            var map;
            $(document).ready(function () {
                map = new ol.Map({
                    view: new ol.View({
                        center: ol.proj.transform([6.8, 46.9], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 11
                    }),
                    target: 'map',
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ]
                });

                cartodb.Tiles.getTiles({
                    type: 'cartodb', user_name: 'ogo', sublayers: [{
                            sql: 'SELECT * FROM g4districts98',
                            cartocss: "#g4districts98 { line-color: red; line-width: 2;}"
                        }]
                }, function (tileTemplate) { // create layer with generated tiles URL
                    tilesUrl = tileTemplate.tiles[0]
                            .replace('{s}', 'a')
                            .replace('{z}', '{z}')
                            .replace('{x}', '{x}')
                            .replace('{y}', '{y}');

                    admLyr = new ol.layer.Tile({
                        source: new ol.source.XYZ({
                            url: tilesUrl
                        })
                    })
                    map.addLayer(admLyr);
                });
            });
        </script>

        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Adapter le style pour afficher les districts Vaudois différemment des autres
  2. Pour une solution encore plus découplée et flexible, adapter l'application pour que le style CartoCSS soit chargé asynchronnement depuis un fichier g4districts.mss (on proclame le suffixe mss pour Map Style Sheet).

5. Couche "vector"

Dans les sections précédentes nous avons inséré des couches cartographiques sous la forme d'images construites par le serveur avec son moteur cartographique. Un serveur cartographique était donc nécessaire. A l'opposé, pour une couche ol.layer.Vector c'est le client qui joue le rôle de moteur cartographique pour créer la visualisation d'entités géographiques (Features en anglais).

  • Télécharger l'archive data.zip et la déployer dans votre dossier de projet web.

Ex5A : Source de données OpenLayers.Format

Une couche ol.layer.Vector peut être alimentée par une source de données au format ol.source.GeoJSON (voir aussi http://geojson.org). Il existe de nombreux autres formats : ol.format.GPX, ol.format.TopoJSON, ol.format.KML, …)

<html>
    <head>
        <title>ol3 - Ex5A - GeoJSON vector overlay</title>
        <script type="text/javascript" src="js/config.js"></script>
        <script type="text/javascript">
            var map;        
            $(document).ready(function(){
                map = new ol.Map({
                    view: new ol.View({
                        center:[738600, 5840171],
                        zoom: 3
                    }),
                    target: 'map',
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ]
                });
                vectorLayer = new ol.layer.Vector({
                    source: new ol.source.Vector({
                        url: "data/4capitals.json",
                        format: new ol.format.GeoJSON()
                    })
                });
                map.addLayer(vectorLayer)
            });
        </script>

        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Apporter la preuve que les données sont bien transformées en objets graphiques côté client !
  2. Qu'est-ce-que ce format GeoJSON http://geojson.org ? Remplacer l'URL source par
    http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson

    en dézoomant un peu le cas échéant.

  3. Ajouter une interaction utilisateur (ex. bouton) qui affiche (ex. dans une div HTML) la liste des descriptions des séismes (propriété title). Ces informations sont bien sûr associées aux entités rattachées à la classe ol.layer.Vector.

    Illustration du résultat attendu :

  4. Enlever l'interaction et modifier l'url comme suit et modifier le type de source de données en conséquence:
    url: 'http://www.visugpx.com/files/download.php?id=1416844831',
    format: new ol.format.GPX()

    en recentrant la carte par ici :

    view: new ol.View({
      center:[766225, 5908730],
      zoom: 12
    }),

    Pourquoi cela ne fonctionne pas?

  5. Notons aussi le Geographic Markup Language (ol.format.GML) de l'OGC qui “consiste en un ensemble de schémas XML qui permettent de construire des modèles de données spécifiques pour des domaines spécialisés, comme l'urbanisme, l'hydrologie, la géologie, et définissent un format ouvert pour l'échange de données géographiques” (source Wikipedia). Voir l'exemple : ./data/fourCapitals.gml

Ex5B : ol.source.Vector sous la loupe

L'exemple ci-dessous décrit en détail ce qu'est une source de donnée ol.source.Vector pour une couche ol.layer.Vector en montrant comment la créer et l'alimenter à partir d'un format de source de géodonnées “fait maison”. En résumé, une source ol.source.Vector est composée d'entités géographiques (ol.Feature) chacune composée d'une géométrie (ol.geom) et d'une liste d'attributs.

La source de données est un fichier texte formaté comme suit:

2.3332999999999999 48.866700000000002 Paris,7.4333 46.950000000000003 Bern,12.5 41.883299999999998 Rome,-3.71 40.409999999999997 Madrid

La structure de formatage est simple : c'est une suite de triplets “Longitude Latitude Nom” dont le séparateur interne est l'espace. Le séparateur entre triplets est la virgule. Chaque triplet correspond à une entité géographique. Le code ci-dessous déchiffre cette structure et transforme les triplets en ol.Feature.

<html>
    <head>
        <title>ol3 - Ex5B - custom format for vector overlay</title>
        <script type="text/javascript" src="js/config.js"></script>
        <script type="text/javascript">
            var map;
            $(document).ready(function () {
                map = new ol.Map({
                    view: new ol.View({
                        center: ol.proj.transform([2, 48], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 5
                    }),
                    target: 'map',
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM(),
                            opacity: 0.3
                        }),
                    ]
                });
                $.get("data/4capitals.txt", createCustomOverlay);
            });

            function createCustomOverlay(response) {
                // Create/add a new empty vector layer
                vectors = new ol.layer.Vector({
                    source: new ol.source.Vector()
                });
                map.addLayer(vectors);                
                // Declare an empty array ready to receive some features
                features = new Array();
                // Lets's decode the "home made" format
                tabCapitals = response.split(",");
                for (i = 0; i < tabCapitals.length; i++) {
                    tabCapital = tabCapitals[i].split(" ");
                    // Create a feature built of a geometry (a Point in our case) and a property (name)
                    var feature = new ol.Feature({
                        geometry: new ol.geom.Point(ol.proj.transform([parseFloat(tabCapital[0]), parseFloat(tabCapital[1])], 'EPSG:4326', 'EPSG:3857')),
                        name: tabCapital[2]
                    });
                    // Add the feature created to the array of features
                    features.push(feature);
                }
                // Add the set of features to the ol.source.Vector which is in relation to the ol.layer.Vector 
                vectors.getSource().addFeatures(features);
            }
        </script>

        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Adapter le code pour une source de données similaire contenant un attribut de plus comme suit :
    2.3332999999999999 48.866700000000002 Paris France,7.4333 46.950000000000003 Bern Suisse,12.5 41.883299999999998 Rome Italy,-3.71 40.409999999999997 Madrid Spain
  2. Montrer que l'attribut a bien été pris en compte (par exemple en créant une interaction similaire à celle demandée dans l'Ex5A).

6. Style "vector"

OpenLayers met à disposition un ensemble de classes ol.style permettant d'appliquer des styles aux features (entités géographiques) d'une couche ol.vector.

Ex6A : Style d'entité

Openlayers applique un style par défaut aux features, mais il est possible de redéfinir ce style (forme, couleur, etc.).

<html>
    <head>
        <title>ol3 - Ex6A - One feature, one style</title>
        <script type="text/javascript" src="js/config.js"></script>
        <script type="text/javascript">
            var map;
            $(document).ready(function () {
                map = new ol.Map({
                    view: new ol.View({
                        center: [750393, 5862618],
                        zoom: 15
                    }),
                    target: 'map',
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ]
                });

                vectLayer = new ol.layer.Vector({
                    source: new ol.source.Vector()
                });
                map.addLayer(vectLayer);

                // Prepare a stroke style 
                var redStroke = new ol.style.Stroke({
                    color: '#ff0000',
                    width: 3
                });
               
                var style = new ol.style.Style({
                    image: new ol.style.RegularShape({
                        points: 4,
                        stroke: redStroke,
                        radius: 10,
                        radius1: 0,
                        radius2: 0
                    })                    
                });

                // Create and style a feature
                var feature = new ol.Feature({
                    geometry: new ol.geom.Point([750393, 5862618])
                });
                feature.setStyle(style);
                vectLayer.getSource().addFeature(feature);
            });
        </script>

        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Remplacer le style avec les propriétés suivantes :
    var style =  new ol.style.Style({
        image: new ol.style.Icon({
            src: "http://urbangene.heig-vd.ch/css/img/icones/marker_saved.png"
        })
    });

    … c'est très joli, mais il semble qu'il y ait un problème ! Lequel ? Comment le résoudre ?

  2. Créer une entité de type LineString en remplaçant la propriété geometry comme suit :
    geometry: new ol.geom.LineString([[738600, 5840171],[1938600, 6840171]])

    et adapter un style adéquat utilisant l'option lineDash de ol.style.Stroke.

Ex6B : Style de couche

L'approche la plus répandue consiste à associer un style à une couche, c'est-à-dire qu'il s'applique automatiquement à toutes les entités de la couche.

<html>
    <head>
        <title>ol3 - Ex6B - One layer, one style</title>
        <script type="text/javascript" src="js/config.js"></script>
        <script type="text/javascript">
            var map;
            $(document).ready(function () {

                var fill = new ol.style.Fill({
                    color: '#acc000'
                });
                var stroke = new ol.style.Stroke({
                    color: '#ff0000',
                    width: 3
                });
                var style = new ol.style.Style({
                    image: new ol.style.Icon({
                        src: "http://urbangene.heig-vd.ch/css/img/icones/marker_saved.png",
                        anchor: [0.5, 1]
                    })
                });

                map = new ol.Map({
                    view: new ol.View({
                        center: ol.proj.transform([2, 48], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 5
                    }),
                    target: 'map',
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ]
                });

                vecLayer = new ol.layer.Vector({
                    source: new ol.source.Vector({}),
                    style: style
                });

                var feature1 = new ol.Feature({
                    geometry: new ol.geom.Point([738600, 5840171]),
                    name: "The precious is here!",
                    author: "Gollum"
                });
                map.addLayer(vecLayer);
                vecLayer.getSource().addFeature(feature1);
            });
        </script>

        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Ajouter une entité géographique de plus comme suit :
    var feature2 = new ol.Feature({
        geometry: new ol.geom.Point([1938600, 6840171]),
        name: "The hobbits are far away...",
        author: "Gandalf"
    });
    vecLayer.getSource().addFeature(feature2);
  2. Modifier la feature1 et la feature2 avec les deux LineString ci-dessous :
    var feature1 = new ol.Feature({
        geometry: new ol.geom.LineString([[738600, 6840171],[1938600, 6840171]])
    });
    
    var feature2 = new ol.Feature({
        geometry: new ol.geom.LineString([[738600, 5840171],[1938600, 7840171]])
    });

Adapter la représentation des lignes avec un style highway comme illustré ci-après :

Ex6C : Fonction de style

Plutôt que d'appliquer un style identique à toutes les entités d'une couche, il est possible d'appliquer un style différents basé sur les propriétés de chacune des entités. Pour cela, Openlayers propose de remplacer l'objet ol.style.Style par une fonction ol.style.StyleFunction(). Dans l'exemple ci-dessous on affiche une étiquette différente en fonction de la propriété “name” de chaque entité.

<html>
    <head>
        <title>ol3 - Ex6C - Styling function</title>
        <script type="text/javascript" src="js/config.js"></script>
        <script type="text/javascript">
            var map;
            $(document).ready(function () {

                var icon = new ol.style.Icon({
                    src: "http://urbangene.heig-vd.ch/css/img/icones/marker_saved.png",
                    anchor: [0.5, 1]
                });

                function createLordStyle(feature, resolution) {
                    var style = new ol.style.Style({
                        image: icon,
                        text: new ol.style.Text({
                            text: feature.get('name'),
                            offsetY: 25,
                            font: '18px Calibri,sans-serif',
                            fill: new ol.style.Fill({
                                color: "#000"
                            })
                        })
                    })
                    return [style];
                }
                ;

                map = new ol.Map({
                    view: new ol.View({
                        center: ol.proj.transform([2, 48], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 5
                    }),
                    target: 'map',
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM()
                        })
                    ]
                });

                vecLayer = new ol.layer.Vector({
                    source: new ol.source.Vector(),
                    style: createLordStyle
                });

                var feature = new ol.Feature({
                    geometry: new ol.geom.Point([738600, 5840171]),
                    name: "The precious is here!",
                    author: "Gollum"
                });
                map.addLayer(vecLayer);

                var feature2 = new ol.Feature({
                    geometry: new ol.geom.Point([1938600, 6840171]),
                    name: "The hobbits are far away...",
                    author: "Gandalf"
                });
                vecLayer.getSource().addFeatures([feature, feature2]);

            });
        </script>

        <style type="text/css">
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

TODO

  1. Modifier ce qu'il faut pour visualiser des étiquettes comme suit Gollum says: The precious is here! et Gandalf says: The hobbits are far away…
  2. Ajouter une couche vector utilisant le flux http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson (cf Ex5A) et faire en sorte que les points séismes de l'hémisphère Nord apparaissent différemment de l'autre.
  3. Sur la base de ce même flux, proposer une représentation thématique des points séismes en exploitant leur propriété d'intensité/magnitude (voir l'attribut mag, voir aussi Echelle de Richter).

geoinf16/ol3tuto.txt · Last modified: 2019/02/13 11:29 by oertz