Carte interactive OpenLayers avec contrôle de calques

Après avoir réalisé une carte historique de la ligne 2 du tramway d’Île-de-France avec Leaflet (voir le tutoriel), je me suis attaqué à la création de cette même carte avec OpenLayers.

Bien que plus complet sur certains points, OpenLayers n’inclus pas nativement deux fonctionnalités utilisées dans la carte :

  • Le contrôle de calques
  • Les tooltips.

Pour le contrôle de calques, j’ai utilisé le plugin ol-layerswitcher de Matt Walker.

Pour les tooltips, j’ai utilisé un overlay et une interaction sur les calques des stations. Le corps du tooltip consiste en une div incluse dans la div de la carte :

<div id="map" style="width: 800px;height: 600px;">
  <div id="tooltip" class="tooltip"></div>
</div>

Création des calques

Ici, contrairement à avec Leaflet, on déclare les calques et groupes de calques avant d’initialiser la carte.

Comme avec Leaflet, chaque étape de la vie de la ligne est représentée par un groupe de deux calques.

Aussi bien pour le tracé que pour les stations, la fonction de style est appelée par le paramètre « style » du calque.

Pour le tracé, la fonction renvoie un objet de style avec un attribut « stroke » :

function styleLine() {
  return new ol.style.Style({
    stroke: new ol.style.Stroke({
      color: '#a0006e',
      width: 3
    })
  });
}

Pour les stations, l’objet renvoyé a un attribut « image », qui lui-même possède plusieurs attributs :

function styleFeature() {
  return new ol.style.Style({
    image: new ol.style.Circle({
      fill: new ol.style.Fill({color: '#ffffff'}),
      radius: 6,
      stroke: new ol.style.Stroke({
        color: 'black',
        width: 2
      })
    })
  });
}

Pour créer un calque, on crée un nouvel objet de type calque vectoriel, avec une source vectorielle dont l’attribut « url » correspond au fichier que l’on veut charger, et l’attribut « format » indique qu’il s’agit de GeoJSON :

var pipLineLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: './trace-puteaux_issy-plaine.geojson',
    format: new ol.format.GeoJSON()
  }),
  style: function(feature){
    return styleLine();
  }
});

Pour les calques « composites », c’est-à-dire qui ont besoin de données présentes dans plusieurs fichiers GeoJSON, on ne dispose pas de méthode prête à l’emploi.

J’ai donc créé une fonction faisant un appel AJAX pour récupérer les données d’un autre fichier pour les rajouter à la source d’un calque, via la méthode « addFeatures » :

function get(url, target) {
  var client = new XMLHttpRequest();
  client.open('GET', url, true);
  client.onload = function() {
    // Ici il faut bien penser à convertir la projection
    var features = (new ol.format.GeoJSON({featureProjection:'EPSG:3857'})).readFeatures(client.responseText);
    target.addFeatures(features);
  };
  client.send();
}

L’appel à cette fonction se fait comme suit :

// On récupère la source du calque grace à la méthode getSource()
get('../leaflet/trace-nord_init.geojson', initLineLayer.getSource());

Une fois les deux calques d’un groupe, il est temps de créer le groupe de calques en lui-même :

var pip = new ol.layer.Group({
  layers:[pipLineLayer, pipStopsLayer],
  title: 'Paris – Issy-Plaine',
  type: 'base',
  visible: true,
  combine: true
});

Détail des attributs :

  • layers : array des calques à inclure dans le groupe
  • title : titre du groupe, qui est utilisé tel quel dans le contrôle
  • type : « base » permet d’indiquer que ce groupe sera sélectionnable avec un bouton radio
  • visible : visibilité du groupe
  • combine : indique que le groupe doit être considéré comme un seul et unique objet par le contrôle.

Après avoir créé tous les calques et groupes de calques dont on a besoin, on peut maintenant initialiser la carte :

var map = new ol.Map({
  layers: [
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png',
        attributions: '<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia maps</a> | Map data © <a href="http://openstreetmap.org/copyright">OpenStreetMap contributors</a>',
        minZoom: 1,
        maxZoom: 19
      })
    }),
    new ol.layer.Group({
      title: 'Tracés', // titre utilisé par le contrôle
      layers: [ext2, ext1, dev2006, init, pip] // l'ordre de ce tableau est inversé dans le contrôle
    })
  ],
  target: 'map',
  view: new ol.View({
    center: ol.proj.fromLonLat([2.258634567260742, 48.847886021323966]),
    zoom: 12
  })
});

Laisser un commentaire