"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
Dans OpenLayers, 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 d'initialisation.
<html> <head> <title>Ex1a - create a first map with a WMS layer</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, { version: "1.1.1", layers: 'ogo:world_simple', format: 'image/png' }, { singleTile: true } ); map.addLayer(wms); map.zoomToMaxExtent(); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
<a href="#" id="olZoomInLink"><img src="images/zoomin.png" class="zoomHover"></a> <a href="#" id="olZoomOutLink"><img src="images/zoomout.png" class="zoomHover"></a>
.zoomHover:hover { background: lightskyblue; }
TODO
//singleTile: true singleTile: false
border: 1px solid red;
styles: "green"
//map.zoomToMaxExtent(); map.zoomToExtent([6,46,9,49]); console.log(map.getProjection());
Avec singleTile à false, le client contrôle la grille de tuiles qu'il peut 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 permettant 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>Ex2a - webmap with tiled layer</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { map = new OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM Map"); map.addLayer(osm); map.zoomToMaxExtent(); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
//map.zoomToMaxExtent(); map.setCenter(new OpenLayers.LonLat(6.15,46.2).transform("EPSG:4326","EPSG:3857"), 10);
console.log("Map projection: " + map.getProjection()); console.log("Map extent: " + map.getExtent()); console.log("LonLat Mercator: " + new OpenLayers.LonLat(6.15,46.2).transform("EPSG:4326","EPSG:3857")); console.log("LonLat Google: " + new OpenLayers.LonLat(6.15,46.2).transform("EPSG:4326","EPSG:900913"));
osm = new OpenLayers.Layer.OSM("UrbanGene Custom OSM", "http://urbangene.heig-vd.ch/tilecache/${z}/${x}/${y}.png");
osm = new OpenLayers.Layer.OSM("OSM tiles restyled by MapBox", "http://api.tiles.mapbox.com/v3/oertz.map-i2ak2ozc/${z}/${x}/${y}.png", { attribution: "Based on <a href='www.openstreetmap.org'>OpenStreetMap</a> / MapBox restyled by oertz :: HEIG-VD" } );
et ajouter l'instruction CSS suivante :
.olControlAttribution { background-color: lightgray; opacity: 0.6; position: relative !important; left: 50px; top: 0px; }
L'utilisation d'un cache serveur de tuiles a largement été popularisé par des services propriétaires comme Google 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
<script type="text/javascript" src="js/config.js"></script> <script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script> <script type="text/javascript"> var map; $(document).ready(function() { map = new OpenLayers.Map('map', { projection: new OpenLayers.Projection("EPSG:3857"), maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508), }); goog = new OpenLayers.Layer.Google("Google layer", { type: google.maps.MapTypeId.TERRAIN, sphericalMercator: true } ); map.addLayer(goog); map.setCenter(new OpenLayers.LonLat(8, 47).transform("EPSG:4326", "EPSG:900913"), 6); }); </script>
Swisstopo offre un service de tuiles basé sur le standard WMTS et que l'on peut exploiter comme suit.
<html> <head> <title>Ex2c - use of Geoadmin WMTS</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript" src="js/jquery/jquery-1.9.1.js"></script> <script type="text/javascript" src="js/proj4js/proj4js-compressed.js"></script> <script type="text/javascript" src="js/proj4js/defs/EPSG21781.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { map = new OpenLayers.Map({ div: "map", projection: "EPSG:21781", units: "m", resolutions: [650, 500, 250, 100, 50, 20, 10, 5, 2.5, 2, 1.5], }); pixelkartefarbe = new OpenLayers.Layer.WMTS({ name: "Swisstopo PK", url: ["http://wmts0.geo.admin.ch/", "http://wmts1.geo.admin.ch/", "http://wmts.geo.admin.ch/"], layer: "ch.swisstopo.pixelkarte-farbe", requestEncoding: "REST", formatSuffix: "jpeg", matrixSet: "21781", format: "image/jpeg", serverResolutions: [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], style: "default", maxExtent: new OpenLayers.Bounds(420000, 30000, 900000, 350000), isBaseLayer: true, opacity: 1.0, dimensions: ['TIME'], params: {'time': 20130213} }); map.addLayer(pixelkartefarbe); map.zoomToMaxExtent(); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
map.setCenter(new OpenLayers.LonLat(7.658, 45.98).transform("EPSG:4326", "EPSG:21781"), 6);
map.setCenter(new OpenLayers.LonLat(600000, 200000), 8);
layer: "ch.swisstopo.hiks-dufour", ... formatSuffix: "png", ... format: "image/png", ... params: {'time': 18450101}
Pour le moment, c'est le serveur qui fait tourner son moteur cartographique pour créer un représentation image des données géographiques. Le client peut dire son mot et le piloter “à distance”.
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 possible d'envoyer au serveur cartographique des instructions personnalisées de style.
<html> <head> <title>Ex3a - use of a custom SLD style</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: 'world_simple', format: 'image/png' } ); map.addLayer(wms); map.zoomToMaxExtent(); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
styles: "giant_polygon"
wms = new OpenLayers.Layer.WMS( "World boundaries", myWMS, { format: 'image/png', SLD: remoteSLD + '/pinkWorld.sld.xml' } );
<?xml version="1.0" encoding="UTF-8"?> <DescribeFeatureType version="1.1.0" service="WFS" xmlns="http://www.opengis.net/wfs" xmlns:ogo="http://mediamaps.ch/ogo" 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>ogo: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:ogo="http://mediamaps.ch/ogo" 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="ogo:world_simple"> <PropertyName>ogo:REGION</PropertyName> </Query> </GetFeature>
... <Rule> <Filter xmlns="http://www.opengis.net/ogc"> <PropertyIsEqualTo> <PropertyName>REGION</PropertyName> <Literal>NorthAfrica</Literal> </PropertyIsEqualTo> </Filter> <PolygonSymbolizer> ...
... </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> ...
L'API Google Maps permet de personnaliser le style des couches habituelles par des manipulations de couleurs (hue, saturation, …) et de façon programmatique (code JavaScript).
Voir Style syntax, Feature types.
<html> <head> <title>Ex3b - Google Maps with StyledMapType</title> <script type="text/javascript" src="js/config.js"></script> <script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script> <script type="text/javascript"> var map; $(document).ready(function(){ // définition de notre ID de MapTypeId (comme google.maps.MapTypeId.TERRAIN) var NIGHT_MAPTYPE_ID = 'ogo.gmaps.nightview'; // Création d'une instance de google.maps.StyledMapType basé sur une description de style "mode nuit" var nightStyle = [ { featureType: "road", elementType: "geometry", stylers: [{hue: "#00ff00"}, {saturation: 100}] }, { featureType: "landscape", elementType: "geometry", stylers: [{hue: "#000000"}, {saturation: 75}, {lightness: -100}] } ]; var nightStyledMapType = new google.maps.StyledMapType(nightStyle); // Création d'une OpenLayers.Layer.Google lié à notre MapTypeId var nightGmap = new OpenLayers.Layer.Google("Google Night", {type: NIGHT_MAPTYPE_ID}); // Création de la map et ajout de notre couche nightGmap map = new OpenLayers.Map('map'); map.addLayer(nightGmap); // le mapObject étant instancié par map.addLayer, // on peut associer notre description de style à notre couche nightGmap, le MapTypeId servant de lien nightGmap.mapObject.mapTypeId = NIGHT_MAPTYPE_ID; nightGmap.mapObject.mapTypes.set(NIGHT_MAPTYPE_ID, nightStyledMapType); // on centre la map sur un point longitude/latitude // on veille à le transformer vers la projection EPSG:900913 qu'utilise Google Maps v3 map.setCenter(new OpenLayers.LonLat(6, 46).transform("EPSG:4326","EPSG:900913"), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
Un intérêt d'une carte en ligne est de pouvoir la composer à partir de plusieurs couches.
La composition peut se faire par un assemblage côté serveur, éventuellement sur demande comme ci-dessous.
<html> <head> <title>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 OpenLayers.Map('map'); wms = new OpenLayers.Layer.WMS( "ogo:world_simple + ogo:cities", myWMS, { // les couches à assembler dans une image cartographique layers: 'ogo:world_simple,ogo:cities', // les styles à appliquer respectivement aux couches listées styles: 'giant_polygon,capitals', format: 'image/png' } ); map.addLayer(wms); map.setCenter(new OpenLayers.LonLat(7, 47), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
Un cadre applicatif de cartographie en ligne se doit de fournir la capacité de gérer la composition côté client. C'est le cas d'OpenLayers comme ci-dessous :
<html> <head> <title>Ex4b - two WMS base layers</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function(){ map = new OpenLayers.Map('map'); map.addControl(new OpenLayers.Control.LayerSwitcher()); world = new OpenLayers.Layer.WMS( "World admin boundaries", myWMS, { layers: 'ogo:world_simple', styles: 'giant_polygon', format: 'image/png' } ); map.addLayer(world); cities = new OpenLayers.Layer.WMS( "World cities", myWMS, { layers: 'ogo:cities', styles: 'capitals', format: 'image/png' } ); map.addLayer(cities); map.setCenter(new OpenLayers.LonLat(7, 47), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
{ SLD: remoteSLD + "/capitals.sld.xml", format: 'image/png', transparent: true }
TODO
Dans les sections précédentes nous avons inséré des couches cartographique 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 OpenLayers.Layer.Vector c'est le client qui joue le rôle de moteur cartographique pour créer la visualisation de données géographiques.
Une couche OpenLayers.Layer.Vector peut être alimentée par une source de données au format OpenLayers.Format.GeoJSON (voir aussi http://geojson.org). Il existe de nombreux autres formats : OpenLayers.Format.GPX, OpenLayers.Format.GML, OpenLayers.Format.KML, …)
<html> <head> <title>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 OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); vectorLyr = new OpenLayers.Layer.Vector("Vector layer from GeoJSON", { protocol: new OpenLayers.Protocol.HTTP({ url: "data/4capitals.json", format: new OpenLayers.Format.GeoJSON({ignoreExtraDims: true}) }), strategies: [new OpenLayers.Strategy.Fixed()], projection: new OpenLayers.Projection("EPSG:4326") }); map.addLayer(vectorLyr); map.setCenter(new OpenLayers.LonLat(738600,5840171),5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
Pourquoi cela ne fonctionne pas ? …
protocol: new OpenLayers.Protocol.HTTP({ url: "http://cafleman.phpnet.org/caf/gpx/480.gpx", format: new OpenLayers.Format.GPX() }),
et recentrer par ici :
map.setCenter(new OpenLayers.LonLat(750000,5840171),12);
En général, un service WMS est associé à un service WFS (Web Feature Service). Ce dernier permet d'interroger côté serveur une base de données géographiques de manière standardisée. On peut utiliser un tel service comme source de données répondant à des requêtes d'interrogation (“à la SQL”).
<html> <head> <title>Ex5b - WFS vector overlay</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'); world = new OpenLayers.Layer.WMS( "World admin boundaries", myWMS, { layers: 'ogo:world_simple', styles: 'giant_polygon', format: 'image/png' } ); map.addLayer(world); capitals = new OpenLayers.Layer.Vector("WFS - cities (capitals)", { protocol: new OpenLayers.Protocol.WFS({ version: "1.1.0", url: myWFS, featureType: "cities", featurePrefix: "ogo", featureNS: "http://mediamaps.ch/ogo" }), strategies: [new OpenLayers.Strategy.Fixed()], projection: new OpenLayers.Projection("EPSG:4326") }); map.addLayer(capitals); map.setCenter(new OpenLayers.LonLat(6,40), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm);
et comme le SRS de cette couche est en projection Mercator (EPSG:900913), ajustez le centrage comme suit :
map.setCenter(new OpenLayers.LonLat(6,40).transform("EPSG:4326","EPSG:900913"), 5);
Quelle est le SRS des coordonnées reçues du serveur WFS ?
capitals = new OpenLayers.Layer.Vector("WFS - cities (capitals)", { protocol: new OpenLayers.Protocol.WFS({ version: "1.1.0", url: "http://ogo.heig-vd.ch/geoserver/wfs", featureType: "cities", featurePrefix: "ogo", featureNS: "http://mediamaps.ch/ogo", srsName: "EPSG:900913" }), strategies: [new OpenLayers.Strategy.Fixed()], projection: new OpenLayers.Projection("EPSG:900913") });
Quelle est la différence ?
strategies: [new OpenLayers.Strategy.BBOX()],
Analysez le trafic client/serveur. Qu'en déduisez-vous par rapport à précédemment ?
filter = new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.EQUAL_TO, property: "geo_region", value: "Africa" });
et ajouter ce filtre à la définition OpenLayers.Protocol.WFS avec le paramètre suivant :
defaultFilter: filter
L'exemple ci-dessous décrit en détail ce qu'est une couche OpenLayer.Layer.Vector en montrant comment la créer et l'alimenter à partir d'un format de source de données “fait maison”.
En résumé, une couche OpenLayer.Layer.Vector est composée d'entités géographiques (OpenLayers.Feature.Vector) chacune composée d'une géométrie (ex. OpenLayers.Geometry.Point) 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 OpenLayers.Feature.Vector.
<html> <head> <title>Ex5c - 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 OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); $.ajax({ type: "GET", url: "data/4capitals.txt", dataType: "text", success: createCustomOverlay }); map.setCenter(new OpenLayers.LonLat(6, 46).transform("EPSG:4326", "EPSG:3857"), 5); }); function createCustomOverlay(response) { // Créer/ajouter une nouvelle couche vide vectors = new OpenLayers.Layer.Vector("Custom vector overlay"); map.addLayer(vectors); // Préparer un tableau pour accueillir des entités géographiques (des "features") features = new Array(); // On analyse et décompose notre flux géographique encodé "maison" tabCapitals = response.split(","); for(i = 0; i < tabCapitals.length; i++){ tabCapital = tabCapitals[i].split(" "); // on construit et ajoute au tableau une feature composé d'une géométrie (ici Point) ptGeom = new OpenLayers.Geometry.Point(tabCapital[0],tabCapital[1]); ptGeom = ptGeom.transform("EPSG:4326", "EPSG:900913"); // que le constructeur utilise pour alimenter la propriété feature.geometry features[i] = new OpenLayers.Feature.Vector(ptGeom); // et d'un tableau asssociatif feature.attributes pour chaque attribut à y associer (ici un seul, nom) features[i].attributes["nom"] = tabCapital[2]; } // le tableau est ajouté à la couche pour afficher les entités vectors.addFeatures(features); } </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
2.3332999999999999 48.866700000000002 Paris France,7.4333 46.950000000000003 Bern Germany,12.5 41.883299999999998 Rome Italy,-3.71 40.409999999999997 Madrid Spain
OpenLayers met à disposition un Styling Framework permettant de configurer le moteur de rendu cartographique à appliquer sur une couche OpenLayers.Layer.Vector. Il offre de nombreux paramètres de style (voir Symbolizer properties).
OpenLayers permet d'associer directement un style à une entité géographique OpenLayers.Feature.Vector.
<html> <head> <title>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 OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); vectorLyr = new OpenLayers.Layer.Vector("Vector layer"); map.addLayer(vectorLyr); feature = new OpenLayers.Feature.Vector(); feature.geometry = new OpenLayers.Geometry.Point(738600, 5840171); feature.attributes = { name: "The precious is here!", author: "Gollum" }; feature.style = { graphicName: 'cross', pointRadius: 10, fillColor: '#ff0000', fillOpacity: 0.8, strokeColor: '#000000', strokeWidth: 1 }; vectorLyr.addFeatures([feature]); map.setCenter(new OpenLayers.LonLat(738600, 5840171), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
{ externalGraphic: "http://www.cretasolaris.gr/gfx/marker.png", graphicWidth: 36, graphicHeight: 33, graphicOpacity: 1 }
L'approche la plus répandue consiste à associer un style à une couche. Ce style est alors composé de règle cartographique et il est alors possible de configurer la représentation en contexte des données attributaires.
<html> <head> <title>Ex6b - One layer, one style</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { map = new OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); ptSymbolizer = new OpenLayers.Symbolizer.Point({ externalGraphic: "http://www.cretasolaris.gr/gfx/marker.png", graphicWidth: 36, graphicHeight: 33, graphicOpacity: 1 }); vectorLyr = new OpenLayers.Layer.Vector("Vector layer", { styleMap: new OpenLayers.Style(ptSymbolizer) }); map.addLayer(vectorLyr); feature = new OpenLayers.Feature.Vector(); feature.geometry = new OpenLayers.Geometry.Point(738600, 5840171); feature.attributes = { name: "The precious is here!", author: "Gollum" }; vectorLyr.addFeatures([feature]); map.setCenter(new OpenLayers.LonLat(738600, 5840171), 5); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
label: "${name}, ${author}", labelYOffset: -30, fontColor: "red", fontSize: "20px"
feature = new OpenLayers.Feature.Vector(); feature.geometry = new OpenLayers.Geometry.Point(1938600, 6840171); feature.attributes = { name: "The hobbits are far away...", author: "Gandalf" }; vectorLyr.addFeatures([feature]);
OpenLayers offre un outil puissant de rendu capable d'adapter une valeur de propriété de style selon le contexte de l'entité (géographique et attributaire). Il se base sur la syntaxe de remplacement attributaire vu ci-dessus.
<html> <head> <title>Ex6c - styling context function</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'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); ctxCategorize = { getColor: function(feature) { switch (feature.attributes["geo_region"]) { case "Europe": noClass = 0; break; case "Africa": noClass = 1; break; default: noClass = 2; } colors = ["#ff0000", "#00ff00", "#0000ff"]; return colors[noClass]; } }; ptSymbolizer = new OpenLayers.Symbolizer.Point({ graphicName: 'circle', pointRadius: 5, fillColor: '${getColor}' }); capitals = new OpenLayers.Layer.Vector("WFS - cities (capitals)", { protocol: new OpenLayers.Protocol.WFS({ url: myWFS, featureType: "cities", featurePrefix: "ogo", featureNS: "http://mediamaps.ch/ogo", srsName: "EPSG:900913" }), strategies: [new OpenLayers.Strategy.Fixed()], styleMap: new OpenLayers.Style(ptSymbolizer, {context: ctxCategorize}) }); map.addLayer(capitals); map.setCenter(new OpenLayers.LonLat(0, 0), 3); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
TODO
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).
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.
<html> <head> <title>Ex7a - controlling controls</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { var map = new OpenLayers.Map('map', {controls: []}); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); if (!map.getCenter()) map.setCenter(new OpenLayers.LonLat(8, 47).transform("EPSG:4326", "EPSG:900913"), 6); }); </script> <style type="text/css"> #map { width: 1000px; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
map.addControl(new OpenLayers.Control.Zoom()); map.addControl(new OpenLayers.Control.Navigation());
map.addControl(new OpenLayers.Control.Permalink());
map.addControl(new OpenLayers.Control.Permalink({ div: document.getElementById("permalink") }));
et le HTML suivant :
<div id="permalink"></div>
OpenLayers offre des facilités pour créer ses propres boutons de contrôles permettant par exemple de contrôler l'activation/désactivation de fonctionnalités.
Il existe trois types de Button :
L'exemple ci-dessous contrôle l'activation de OpenLayers.Control.MousePosition.
<html> <head> <title>Ex7b - button control activation </title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function() { map = new OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); map.setCenter(new OpenLayers.LonLat(8, 47).transform("EPSG:4326", "EPSG:900913"), 6); pnl = document.getElementById("pnl"); mp = new OpenLayers.Control.MousePosition({div: coord, prefix: "Current mouse Position: "}); map.addControl(mp); mp.activate(); btn1 = new OpenLayers.Control.Button({ displayClass: 'MyButton1', type: OpenLayers.Control.TYPE_TOGGLE, eventListeners: { activate: function() { mp.activate(); }, deactivate: function() { mp.deactivate(); } } }); pnl = document.getElementById("pnl"); panel = new OpenLayers.Control.Panel({div: pnl, defaultControl: btn1}); panel.addControls([btn1]); map.addControl(panel); }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } .MyButton1ItemInactive, .MyButton1ItemActive { background-image: url("http://img855.imageshack.us/img855/7876/dhit.jpg"); border: 1px solid black; width: 27px; height: 27px; } .MyButton1ItemActive { border-color: red; } #coord { font-size: small; } </style> </head> <body> <div id="pnl"></div> <div id="coord"></div> <div id="map"></div> </body> </html>
TODO
btn2 = new OpenLayers.Control.Button({ displayClass: 'MyButton2', type: OpenLayers.Control.BUTTON, trigger: function(){ alert("Centre de la carte sont en " + map.getProjection() + " : " + map.getCenter()); } });
en l'accompagnant de son bout de CSS suivant :
.MyButton2ItemInactive { background-image: url("http://www.geomreze.rgz.gov.rs/gmm/fugue_sm_readcord.png"); width: 32px; height: 32px; }
Les deux exemples suivants illustrent l'interrogation des objets de la carte par une interaction utilisateur, par exemple au clic. D'abord, on illustre l'interrogation d'un pixel de la carte avec OpenLayers.Control.WMSGetFeatureInfo.
<html> <head> <title>Ex7c - 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("OGO WMS", myWMS, { layers: 'ogo:world_simple', format: 'image/png' } ); map.addLayer(wms); map.zoomToMaxExtent(); info = new OpenLayers.Control.WMSGetFeatureInfo({ url: myWMS, title: 'Identify features by clicking', queryVisible: true, infoFormat: 'text/html' }); map.addControl(info); info.events.register('getfeatureinfo', info, onGetFeatureInfo); info.activate(); }); function onGetFeatureInfo(event) { for (i = 0; i < map.popups.length; i++) map.removePopup(map.popups[i]); map.addPopup(new OpenLayers.Popup.FramedCloud("popup", map.getLonLatFromPixel(event.xy), null, event.text, null, true ) ); } </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
layers: 'ogo:world_simple,ogo:cities',
Le contrôle OpenLayers.Control.SelectFeature offre des facilités pour interroger un objet d'une couche OpenLayers.Layer.Vector.
<html> <head> <title>Ex7d - vector overlay interaction with popup</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'); map.addControl(new OpenLayers.Control.LayerSwitcher()); world = new OpenLayers.Layer.WMS("World admin boundaries", myWMS, { layers: 'ogo:world_simple', styles: 'giant_polygon', format: 'image/png' } ); map.addLayer(world); cities = new OpenLayers.Layer.WMS("Cities", myWMS, { layers: 'ogo:cities', format: 'image/png', transparent: true } ); map.addLayer(cities); var defaultPoint = new OpenLayers.Symbolizer.Point({ graphicName: 'square', pointRadius: 6, fillColor: '#ffff00', fillOpacity: 0, stroke: 0 }); var selectPoint = defaultPoint.clone(); selectPoint.fillOpacity = 0.8; capitals = new OpenLayers.Layer.Vector("WFS - cities (capitals)", { strategies: [new OpenLayers.Strategy.BBOX()], protocol: new OpenLayers.Protocol.WFS({ url: myWFS, featureType: "cities", featurePrefix: "ogo", featureNS: "http://mediamaps.ch/ogo" }), styleMap: new OpenLayers.StyleMap({ "default": new OpenLayers.Style(defaultPoint), "select": new OpenLayers.Style(selectPoint) }) }); map.addLayer(capitals); selectControl = new OpenLayers.Control.SelectFeature(capitals, {hover:true}); map.addControl(selectControl); selectControl.activate(); capitals.events.register("featureselected", capitals, onFeatureSelect); capitals.events.register("featureunselected", capitals, onFeatureUnselect); map.setCenter(new OpenLayers.LonLat(7, 47), 5); }); function onPopupClose(evt) { // 'this' is the popup. selectControl.unselect(this.feature); } function onFeatureSelect(evt) { feature = evt.feature; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(100,100), "<h2>" + feature.attributes.wup_aggl + "</h2>" + feature.attributes.cntry_name, null, true, onPopupClose ); feature.popup = popup; popup.feature = feature; map.addPopup(popup); } function onFeatureUnselect(evt) { feature = evt.feature; if (feature.popup) { popup.feature = null; map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; } } </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
label: "${wup_aggl}", labelYOffset: 12
SLD: remoteSLD + "/capitals.sld.xml",
OpenLayers.Control.DrawFeature est un contrôle fort utile pour les WebGIS et les applications de PPGIS (crowdsourcing) permettant à l'utilisateur de créer un objet géographique sur la carte.
L'exemple ci-dessous illustre cela pour la saisie d'une ligne (OpenLayers.Handler.Path), mais il est bien sûr possible de créer des points, des polygones, des polygones réguliers.
<html> <head> <title>Ex7e - draw line feature</title> <script type="text/javascript" src="js/config.js"></script> <script type="text/javascript"> var map; $(document).ready(function(){ var map = new OpenLayers.Map('map'); osm = new OpenLayers.Layer.OSM("Simple OSM layer"); map.addLayer(osm); lnSymbolizerDef = new OpenLayers.Symbolizer.Line({ strokeWidth: 3, strokeColor: "#ff0000" }); lnSymbolizerTmp = lnSymbolizerDef.clone(); lnSymbolizerTmp.strokeDashstyle = "dash"; drawLayer = new OpenLayers.Layer.Vector("Draw layer", { styleMap: new OpenLayers.StyleMap({ "default": new OpenLayers.Style(lnSymbolizerDef), "temporary": new OpenLayers.Style(lnSymbolizerTmp) }) }); map.addLayer(drawLayer); drawControl = new OpenLayers.Control.DrawFeature(drawLayer, OpenLayers.Handler.Path); map.addControl(drawControl); drawControl.activate(); map.setCenter(new OpenLayers.LonLat(738600,5880171),10); // vers le Lausanne }); </script> <style type="text/css"> #map { width: 100%; height: 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
drawControl.events.register('featureadded', drawControl, function(evt){ alert("Vraiment une bien belle ligne !"); });
nbPts = evt.feature.geometry.getVertices().length; alert("Une belle ligne composée de " + nbPts + " points !");
La librairie, malgré ses 10 ans d'âge est prête pour les applications mobiles. Une version allégée de la librairie JS est disponible pour cet usage, offrant un jeu restreint de fonctionnalités. Une CSS y est également adaptée.
<!DOCTYPE html> <html> <head> <title>Ex8a : OpenLayers Mobile</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="apple-mobile-web-app-capable" content="yes"> <link rel="stylesheet" href="js/openlayers/theme/default/style.mobile.css" type="text/css"> <script src="js/openlayers/OpenLayers.mobile.js"></script> <script type="text/javascript"> var map; window.onload = function() { map = new OpenLayers.Map("map", {theme: null, controls: []}); map.addControl(new OpenLayers.Control.Zoom()); map.addControl(new OpenLayers.Control.TouchNavigation( { dragPanOptions: { enableKinetic: false } } )); osm = new OpenLayers.Layer.OSM("OpenStreetMap", null, { transitionEffect: 'resize' }); map.addLayer(osm); map.setCenter(new OpenLayers.LonLat(6.65, 46.77).transform("EPSG:4326", "EPSG:3857"), 10); }; </script> <style> html, body { margin : 0; padding : 0; height : 100%; width : 100%; } #map { position : relative; width : 100%; height : 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
<!DOCTYPE html> <html> <head> <title>Ex8b : OpenLayers Geolocation</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="apple-mobile-web-app-capable" content="yes"> <link rel="stylesheet" href="js/openlayers/theme/default/style.mobile.css" type="text/css"> <script src="js/openlayers/OpenLayers.mobile.js"></script> <script type="text/javascript"> var map; window.onload = function() { map = new OpenLayers.Map("map", {theme: null, controls: []}); map.addControl(new OpenLayers.Control.Zoom()); map.addControl(new OpenLayers.Control.TouchNavigation( { dragPanOptions: { enableKinetic: true } } )); osm = new OpenLayers.Layer.OSM("OpenStreetMap", null, { transitionEffect: 'resize' }); map.addLayer(osm); map.setCenter(new OpenLayers.LonLat(6.65, 46.77).transform("EPSG:4326", "EPSG:3857"), 12); var ptSymb = { externalGraphic: 'images/markerBlue.png', graphicWidth: 36, graphicHeight: 33 }; tracker = new OpenLayers.Layer.Vector("tracker", {style: ptSymb}); map.addLayer(tracker); navigator.geolocation.getCurrentPosition(newPoint, locationError); //6.65, 46.77 }; function newPoint(position) { ptGeom = new OpenLayers.Geometry.Point(position.coords.longitude, position.coords.latitude); point = new OpenLayers.Feature.Vector(ptGeom.transform("EPSG:4326", "EPSG:3857")); tracker.addFeatures([point]); } function locationError(e) { alert(e); } </script> <style> html, body { margin : 0; padding : 0; height : 100%; width : 100%; } #map { position : relative; width : 100%; height : 100%; } </style> </head> <body> <div id="map"></div> </body> </html>
TODO
navigator.geolocation.watchPosition(newPoint, locationError);
et saisir les positions (lon, lat) suivantes “à la main” dans l'émulateur : (6.60, 46.77) - (6.61, 46.77) - (6.62, 46.77) - (6.63, 46.77) …
function createZone() { var points = [ new OpenLayers.Geometry.Point(6.632, 46.778), new OpenLayers.Geometry.Point(6.658, 46.777), new OpenLayers.Geometry.Point(6.652, 46.761) ]; var linearRing = new OpenLayers.Geometry.LinearRing(points); polygon = new OpenLayers.Geometry.Polygon([linearRing]); var feature = new OpenLayers.Feature.Vector(polygon.transform("EPSG:4326", "EPSG:3857")); zone = new OpenLayers.Layer.Vector("zone"); zone.addFeatures([feature]); map.addLayer(zone); }
et ajouter la fonctionnalité qui surveille le déplacement de l'utilisateur provoquant un message d'alerte dès que sa position entre en intersection avec la zone de danger.