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


geoinf18:oltuto3

OpenLayers3 (2018, part 3)

6. ol.layer de type "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é, avec 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 (rappel : Feature en anglais).

  • Si nécessaire, télécharger l'archive data.zip et insérer son contenu dans votre dossier de projet web.

A. 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, sans oublier 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 pour des domaines métiers spécifiques (urbanisme, hydrologie, géologie, …) et définissent un format ouvert pour l'échange de données géographiques” (source Wikipedia). Voir l'exemple dans votre dossier data : ./data/fourCapitals.gml

<html>
    <head>
        <title>ol3 - Ex6a - 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
    https://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: 'https://drive.switch.ch/index.php/s/ISW7xzNmVTAkwQM/download',
    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 ? Et pourquoi ça fonctionnait alors avant avec le flux GeoJSON des séismes ?

B. L'objet ol.source.Vector sous la loupe

Cette section 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écode cette structure et transforme les triplets en objects de type ol.Feature.

<html>
    <head>
        <title>ol3 - Ex6b - 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 le point A, avec une liste de descriptions des entités).

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

A. 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 - Ex7a - 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 ? → docs/API

  2. Ajouter une entité de plus dans la source - que constate-t-on ?
    var feature2 = new ol.Feature({
        geometry: new ol.geom.Point([759116, 5860375])
    });
    vectLayer.getSource().addFeature(feature2);
  3. Créer une entité de type LineString en remplaçant la propriété geometry comme suit et avec une représentation en ligne traitillé :
    geometry: new ol.geom.LineString([[750393, 5862618],[759116, 5860375]])

B. 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 (comme avec SLD/SE et CartoCSS).

<html>
    <head>
        <title>ol3 - Ex7b - 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({})
                });
                vecLayer.setStyle(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 :

C. 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 - Ex7c - 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 https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson et faire en sorte que les points séismes soient représentés différemment dans chaque hémisphère.
    function createQuakeStyle(feature, resolution) {
        var quakeStyleS = new ol.style.Style({
            image: new ol.style.Circle({
              radius: 5,
              fill: new ol.style.Fill({
                color: '#ff0000'
              })
            })
        });
    
        var quakeStyleN = new ol.style.Style({
            image: new ol.style.Circle({
              radius: 5,
              fill: new ol.style.Fill({
                color: '#0000ff'
              })
            })
        });
    
        coords = feature.getGeometry().getCoordinates();
        console.log(coords);
    
        if (coords[1] < 0)
          quakeStyle = quakeStyleS;
        else
          quakeStyle = quakeStyleN;
    
        return quakeStyle;
    }
  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).
    En quoi le paramètre renderOrder de ol.layer.Vector est ici particulièrement intéressant ?

geoinf18/oltuto3.txt · Last modified: 2018/12/18 09:14 by oertz