"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!
OpenLayers offre un ensemble de fonctionnalités permettant d'interagir avec la carte. Par défaut, les interactions de zoom et pan sont actives, et nous avons entre aperçu le contrôle OpenLayers.Control.LayerSwitcher. Il existe de nombreux autres OpenLayers.Control (voir aussi http://docs.openlayers.org/library/controls.html et la section 8).
En plus de la gestion événementielle offerte par ces contrôleurs, OpenLayers permet d'enregistrer des écouteurs sur de nombreux événements, comme ceux en lien avec la vie d'un OpenLayers.Map (voir OpenLayers.Map.events, OpenLayers.Layer.Vector.events).
Voir aussi un autre workshop sur le sujet : http://softlibre.gloobe.org/openlayers/workshop/introduction/module3.
A présent que les techniques de visualisation cartographique sont maîtrisées, tant côté serveur que client, il s'agit de découvrir comment interagir avec les objets géographiques représentés.
Cet exemple illustre l'interrogation des objets de la carte par le simple clic d'un pixel sur la carte. On utilise le contrôle OpenLayers.Control.WMSGetFeatureInfo qui permet d'enregistrer un écouteur sur l'événement onGetFeatureInfo.
<html> <head> <title>Ex7A - interaction with WMS GetFeatureInfo control</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { OpenLayers.ProxyHost = myProxy; map = new OpenLayers.Map('map'); wms = new OpenLayers.Layer.WMS("World boundaries", myWMS, { layers: 'public.world_simple', format: 'image/png' }, { singleTile: true } ); map.addLayer(wms); map.zoomToMaxExtent(); info = new OpenLayers.Control.WMSGetFeatureInfo({ url: myWMS, infoFormat: 'text/plain' }); map.addControl(info); info.events.register('getfeatureinfo', info, onGetFeatureInfo); info.activate(); }); function onGetFeatureInfo(event) { $("#info").html(event.text.replace(":", "<br>")); } </script> <style type="text/css"> #map { width: 100%; height: 100%; } #info { position: absolute; top: 20px; left: 50px; background-color: white; border: solid gray 1px; padding: 5px; font-size: smaller; z-index: 1000000000; } </style> </head> <body> <div id="map"></div> <div id="info">Click on the map to get feature info</div> </body> </html>
TODO
info = new OpenLayers.Control.WMSGetFeatureInfo({ url: myWMS, infoFormat: 'text/plain', vendorParams: { radius: 5 } });
Dans Ex7A, c'est une version standardisé du contrôle d'interrogation lié au standard OGC WMS. L'exemple suivant montre comment mettre cela en oeuvre par nous-même. On s'assure ainsi de maîtriser tout le processus client/serveur.
Côté client :
<html> <head> <title>Ex7B - homemade GetFeatureInfo</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { map = new OpenLayers.Map('map'); wms = new OpenLayers.Layer.WMS("World boundaries", myWMS, { layers: 'public.world_simple', format: 'image/png' }, { singleTile: true } ); map.addLayer(wms); map.zoomToMaxExtent(); map.events.register('click', map, getFeatureInfo); }); function getFeatureInfo(e) { // Conversion du graphique (Pixel) au géographique (LonLat) px = new OpenLayers.Pixel(e.xy.x,e.xy.y); xy = map.getLonLatFromPixel(e.xy); // On forme et lance la requête en veillant à enregistrer la function de callback getInfo = "GetCountriesByXY.php?x=" + xy.lon + "&y=" + xy.lat; $.ajax({ type: "GET", url: getInfo, success: function(response){ $("#info").html(response.features[0].properties.name); } }); } </script> <style type="text/css"> #map { width: 100%; height: 100%; } #info { position: absolute; top: 20px; left: 50px; background-color: white; border: solid gray 1px; padding: 5px; font-size: smaller; z-index: 1000000000; } </style> </head> <body> <div id="map"></div> <div id="info">Click on the map to get feature info</div> </body> </html>
Côté serveur : GetCountriesByXY.php
<?php require_once 'GeoManager.php'; $XY = $_GET["x"] . " " . $_GET["y"]; $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $api_key = "2e957be5f1e9c0793ca1725aab08274a795f2c3f"; $q = "SELECT name, ST_AsGeoJSON(the_geom) AS geom FROM world_simple" . " WHERE ST_Intersects(the_geom, ST_GeomFromText('POINT(" . $XY . ")', 4326))"; $url = "http://oertz.cartodb.com/api/v2/sql?api_key=" . $api_key. "&q=" . urlencode($q); curl_setopt($ch, CURLOPT_URL, $url); $result = curl_exec($ch); $rows = json_decode($result)->rows; header("Content-type: application/json"); $i = 0; $fc = new FeatureCollection(); foreach ($rows as $row) { $fc->addFeature(new Feature($i++, json_decode($row->geom), array("name" => $row->name))); } echo json_encode($fc); ?>
TODO
$("#info").html("Loading... please wait...");
vectors = new OpenLayers.Layer.Vector("FeatureInfo overlay"); map.addLayer(vectors);
et remplacer l'appel AJAX comme suit :
$.ajax({ type: "GET", url: getInfo, dataType: "text", success: function(response){ json = new OpenLayers.Format.GeoJSON(); fc = json.read(response); $("#info").html(fc[0].attributes.name); vectors.addFeatures(fc); } });
selectControl = new OpenLayers.Control.SelectFeature(vectors, {hover:true}); map.addControl(selectControl); selectControl.activate(); vectors.events.register("featureselected", vectors, function(e){ $("#info").html(e.feature.attributes["name"]); });
Le chargement d'entités géographiques peut s'avérer néfaste en terme d'expérience utilisateur du fait d'une latence provoquée (1) par le volume important de données à charger pour une bande passante donnée et (2) par les performances et l'aptitude du moteur de rendu cartographique à digérer ces données.
L'exemple suivant montre déjà des limites avec la stratégie OpenLayers.Strategy.Fixed() qui charge simplement tous les objets dans l'enveloppe de visualisation. Il s'agit alors d'opter pour tes stratégies pour éviter ces écueils.
<html> <head> <title>Ex7C - Vector overlay loading strategies</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map, lyr; $(document).ready(function() { OpenLayers.ProxyHost = myProxy; map = new OpenLayers.Map('map'); map.addControl(new OpenLayers.Control.LayerSwitcher()); osm = new OpenLayers.Layer.OSM("Simple OSM Map"); map.addLayer(osm); lyr = new OpenLayers.Layer.Vector("WFS - cities (capitals)", { protocol: new OpenLayers.Protocol.WFS({ version: "1.0.0", url: myWFS, featureType: "cities" }), strategies: [new OpenLayers.Strategy.Fixed()], projection: new OpenLayers.Projection("EPSG:4326") }); map.addLayer(lyr); map.setCenter(new OpenLayers.LonLat(8, 47).transform("EPSG:4326", "EPSG:3857"), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
featureType: "world_simple"
strategies: [new OpenLayers.Strategy.BBOX()],
et tout en naviguant dans la carte, compter les appels au serveur géographique et revérifier le(s) volume(s) des entités géographiques transférées.
... lyr.setVisibility(false); map.addLayer(lyr); ...
de plus, ajouter les instructions ci-dessous en fin de fonction ready :
... map.myZoom = map.zoomTo; map.zoomTo = function(zoom, xy) { lyr.setVisibility(zoom >= 8 ? true : false); map.myZoom(zoom, xy); };
Le chargement d'entités géographiques (plutôt que leur représentation graphique image) offre des possibilités d'interaction plus directe sur les objets vectoriels qui les représentent. Voyons quelques exemples.
TODO
defaultPoint = new OpenLayers.Symbolizer.Point({ graphicName: 'circle', pointRadius: 6, fillColor: '#0000ff', fillOpacity: 0.8 }); selectPoint = defaultPoint.clone(); selectPoint.fillColor = '#ff0000';
puis les connecter en ajoutant un styleMap sur la couche Vector comme suit :
... styleMap: new OpenLayers.StyleMap({ "default": new OpenLayers.Style(defaultPoint), "select": new OpenLayers.Style(selectPoint) }) ...
enfin ajouter et activer un contrôle SelectFeature sur cette couche Vector comme suit :
selectControl = new OpenLayers.Control.SelectFeature(lyr, {hover:true}); map.addControl(selectControl); selectControl.activate();
lyr.events.register("featureselected", lyr, function(event) { var feature = event.feature; $("#info").html(feature.attributes.wup_aggl); });