====== OpenLayers, ricette e trucchi ======
* [[http://www.openlayers.org/|Home Page]]
* [[http://dev.openlayers.org/apidocs/files/OpenLayers-js.html|Documentazione devel]]
* [[http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers-js.html|Documentazione 2.10]]
* [[http://trac.osgeo.org/openlayers/wiki/Documentation|More documentation]]
* [[http://openlayers.org/dev/examples/|Examples gallery]]
* [[http://ole.geops.de/|OpenLayers Editor]] extend OpenLayers functionality
===== Layer supportati da OpenLayers =====
^ OSM | OpenStreetMap, l'uso di questo layer richiede il caricamento di **''OpenLayers.js''**. Gestisce le tile, il caricamento asincrono e la proiezione EPSG:900913. |
^ Markers | Visualizza delle icone, è possibile attivare un pop-up al click sull'icona. Ogni feature può avere un'icona diversa. I marker vengono aggiunti o rimossi da programma. |
^ Text | Del tutto simile al ''Marker'', ma carica le feature, i nomi delle icone e il contenuto del pop-up da un file di testo. Carica il layer una sola volta, per aggiornarne il contenuto bisogna svuotarlo e forzare la funzione **''loadText()''**. |
^ GeoRSS | Carica un elenco di features da un file XML, ogni feature viene mostrata con un simbolo eventualmente personalizzato con un uno stile. Lo stile può dipendere dagli attributi della singola feature, non può essere un'icona bitmap. Carica il file .xml una sola volta, per aggiornarne il contenuto bisogna svuotarlo e forzare la funzione **''loadRSSt()''**. |
^ Vector | Carica una geometria con un dato protocollo (es. HTTP) in un dato formato (es. GPX, GML, KML, ecc). La vestizione può essere fatta con uno stile, non si possono usare icone bitmap. Il file viene caricato con un protocollo specificato (es. HTTP) e con delle strategie specificate (ad esempio al variare della bounding box). La strategia **''BBOX''** fa uso di richieste XMLHttpRequest per caricare nuovi dati in modo asincrono, al cambiare della bounding box. Per forzare l'aggiornamento da programma si modifica l'URL di origine con **''setUrl()''** aggiungendo un parametro univoco (ad esempio un ''t=timestamp''), in tal modo si invalida la cache. |
^ KML | Layer vettoriale. Supporta diverse strategie di caricamento, in generale si richiede via HTTP e può essere circoscritto alla BBOX inquadrata in quel momento. I vari attributi inclusi nello standandard KML possono essere utilizzati da OpenLayers per definire lo stile, ecc. |
^ WFS | |
^ TMS | |
Esempi:
var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik (updated weekly)");
var markers = new OpenLayers.Layer.Markers("Markers");
var pois = new OpenLayers.Layer.Text("My Points", {
location:"./textfile.txt", projection: map.displayProjection });
var track_style = new OpenLayers.Style();
track_style.strokeColor = "#6636e1";
track_style.strokeWidth = 7;
track_style.strokeOpacity = 0.7;
var object_trk = new OpenLayers.Layer.GML("GPX Track", "track.gpx", {
format: OpenLayers.Format.GPX,
style: track_style,
projection: map.displayProjection});
map.addLayer(object_trk);
var gsat = new OpenLayers.Layer.Google(
"Google Satellite", {type: G_SATELLITE_MAP, numZoomLevels: 20});
===== Using Blue Marble imagery with OpenLayers =====
==== Raster datasets from NASA ====
Several imagery sets exists from NASA, among them:
* **[[http://earthobservatory.nasa.gov/Features/BlueMarble/|Blue Marble next generation]]** (1 pixel = 500x500 m)
* **[[http://onearth.jpl.nasa.gov/|Land Sat 7]]** (1 pixel = 15x15 m)
The original Blue Marble images came from **[[http://modis.gsfc.nasa.gov/|MODIS]]**, the spectroradiometer aboard of **[[http://terra.nasa.gov/|Terra]]** and **[[http://aqua.nasa.gov/|Aqua]]** satellites. //Blue Marble Next Generation// added more spatial resolution.
==== Blue Marble WMS Server ====
**[[http://onearth.jpl.nasa.gov/]]**
OnEarth WMS server by NASA offers a standard WMS service plus a "Tiled WMS" (prerendered tiles).
* http://onearth.jpl.nasa.gov/wms.cgi?request=GetCapabilities
* http://onearth.jpl.nasa.gov/wms.cgi?request=GetTileService
==== World Wind ====
**[[http://worldwind.arc.nasa.gov/index.html|NASA World Wind]]**
**World Wind** is a software (open source but MS-Windows only) developed by NASA which allows to pan and zoom into several raster datasets offered by NASA servers. World Wind uses (among others) Blue Marble imagery.
The same imagery server can be used by other software, e.g. OpenLayers via the ''OpenLayers.Layer.WorldWind()'' function.
==== Blue Marble WMS Tiled Server ====
* **[[http://onearth.jpl.nasa.gov/tiled.html|Tiled WMS]]**
This is an extension to the standard WMS protocol, the capabilities of such services are exposed at:
* [[http://onearth.jpl.nasa.gov/wms.cgi?request=GetTileService]]
Some of the tags announced by the service are:
^ OnlineResource | Server prefix (%%http://...%%) |
^ LatLonBoundingBox | Covered area |
^ width, height | Tile size |
^ format | Tile format () |
^ bbox | Tile coverage |
^ Name | |
^ Title | |
^ Abstract | |
===== Dynamic layer update =====
We want to refresh the contents of a layer using a timer, every time we want to fetch new data from the server.
==== OpenLayers.Layer.GeoRSS ====
This is an example of a **GeoRSS** layer, updated every 120 seconds. Every point is drawn with the same icon, a pop-up will appear when the icon is clicked.
var friends;
function init() {
...
// Add tangoGPS friends layer.
friends = new OpenLayers.Layer.GeoRSS("Friends", "tangogps-friend.php", {
projection: map.displayProjection
});
friends.icon = new OpenLayers.Icon(
"icons/tangogps-friend.png");
map.addLayer(friends);
...
var tim = setInterval ("updateFriends()", 120000);
}
function updateFriends() {
friends.clearMarkers();
friends.clearFeatures();
friends.loaded = false;
friends.loadRSS();
}
The code **''tangogps-friend.php''** should return GeoRSS formatted text (like **{{.openlayers:georss.xml|this example}}**), with proper expire and no cache headers:
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
header("Content-Type: text/xml");
...
==== OpenLayers.Layer.GML ====
This is a more complex example, using a **GML** layer in GML format. The GML geometry is drawn with the default style. The layer is reloaded by a timer every 120 seconds. We use a BBOX strategy, so that the layer is reloaded also when the bounding box changes. Layer is loaded via HTTP protocol.
var friends;
function init() {
...
// Add tangoGPS friends layer.
friends = new OpenLayers.Layer.GML("GML", "friends-gml.php", {
strategies: [new OpenLayers.Strategy.BBOX()],
projection: map.displayProjection,
protocol: new OpenLayers.Protocol.HTTP({
url: "friends-gml.php",
format: new OpenLayers.Format.GML()
}),
});
map.addLayer(friends);
...
var tim = setInterval ("updateFriends()", 120000);
}
function updateFriends() {
var now = new Date().valueOf();
var bbox = map.getExtent().toBBOX();
friends.setUrl("friends-gml.php?bbox=" + bbox + "&time=" + now);
}
The **''friends-gml.php''** should return a valid GML file (like **{{.openlayers:gml.xml|this example}}**) and it should be non cacheable (using the same headers of GeoRSS layer above). The script will be called with the following arguments:
var friends;
function init() {
...
// Add tangoGPS friends layer.
friends = new OpenLayers.Layer.Text("Friends", {
location:"friends-text.php",
projection: map.displayProjection});
map.addLayer(friends);
...
var tim = setInterval ("updateFriends()", 120000);
}
function updateFriends() {
// Remove markers and features.
friends.clearMarkers();
friends.clearFeatures();
// Pretend the layers is not yet loaded.
friends.loaded = false;
friends.location = "friends-text.php";
friends.loadText();
}
The text returned by **''friends-text.php''** should be non cacheable as always and contains a tab separated text, like **{{.openlayers:layertext.txt|this example}}**.
This recipe can be improved by adding a ''bbox'' parameter (calculated at runtime) to the location of the layer, and forcing a call to ''updateFriends()'' whenever the viewport of the map changes.
===== Overview mappa =====
Il rapporto di scala tra la mappa principale e l'overview fornita dall'oggetto **''OpenLayers.Control.OverviewMap()''** è controllato dalle proprietà **''minRatio''** e **''maxRatio''**.
Per entrambi i valori si intende il rapporto **''overview_map_resolution / main_map_resolution''**. Se la mappa è in metri la risoluzione si misura in metri/pixel.
Il valore di ''minRatio'' deve essere minore di ''maxRatio''.
Se ad esempio si impostano i seguenti valori:
minRatio: 2.0
maxRatio: 10.0
il **rettangolo che evidenzia l'estensione** nella overview potrà variare dalla **metà** dell'estensione dell'overview fino a **un decimo**. Oltre questi limiti l'overview viene zoommata opportunamente.
===== Sistemi di riferimento extra =====
OpenLayers supporta alcuni sistemi di riferimento, di questi è posibile fare la riproiezione al volo (layer vettoriali). Tra i sistemi supportati nativamente ci sono:
* EPSG:900913
* EPSG:4326
Per supportare altri sistemi di riferimento è possibile utilizzare la **[[http://trac.osgeo.org/proj4js/|libreria proj4js]]**. Basta scompattare l'archivio nella DocumentRoot e includere il codice nel progetto web (oltre a quello di OpenLayers) con qualcosa del genere:
In teoria OpenLayers dovrebbe scoprire automaticamente che è disponibile la libreria proj4js, senza bisogno di includere lo script. ma non è chiaro come.
Sistemi di riferimento aggiuntivi vengono definiti con la stessa sintassi di PROJ.4, aggiungendo dei file nella directory **''proj4js/lib/defs/''**, nell'esempio sopra sono stati inclusi ''EPSG:3003'' e ''EPSG:23032''.
Ecco ad esempio il file **''EPSG3003.js''**:
Proj4js.defs["EPSG:3003"] = "+title=Monte Mario / Italy zone 1 \
+proj=tmerc +lat_0=0 +lon_0=9 +k=0.999600 +x_0=1500000 +y_0=0 \
+ellps=intl +units=m +no_defs";
Dopo aver incluso il JavaScript di cui sopra, diventa possibile fare operazioni del tipo:
var lonLat = new OpenLayers.LonLat(1554000, 4678000);
alert("lonLat = " + lonLat);
lonLat.transform(new OpenLayers.Projection('EPSG:3003'), new OpenLayers.Projection('EPSG:23032'));
alert("lonLat = " + lonLat);
:!: **ATTENZIONE!** Se non si aggiunge manualmente la definizione del sistema di riferimento (inline nel codice o tramite un file in **''lib/defs/''**) proj4js tenta di scaricarla da spatialreference.org. L'operazione **viene effettuata a runtime e in modo asincorno**, quindi potrebbe causare **problemi difficili da risolvere**. Un sintomo è che l'oprazione ''transform()'' pare non avere effetto sull'oggetto, in quanto il JavaScript non ha fatto in tempo a recuperare la definizione del sistema di riferimento.
===== i18n =====
OpenLayers offre supporto per la internazionalizzazione (i18n) delle applicazioni tramite la classe **[[http://dev.openlayers.org/apidocs/files/OpenLayers/Lang-js.html|OpenLayers.Lang]]**.
Ecco un esempio di come usarla:
OpenLayers.Lang.it = {
'string1': 'Traduzione di string1',
'string2': 'Traduzione di string2'
};
OpenLayers.Lang.setCode('it');
alert(OpenLayers.i18n('string1'));
===== Click destro =====
Per gestire il click destro sulla mappa bisogna anzitutto disabilitare il //context menu// che presenta il browser al click destro. Ci sono due metodi.
Con questa istruzione si disabilita il context menu nel
map.div.oncontextmenu = function noContextMenu(e) {return false;};
In alternativa si fa in modo che il ''OpenLayers.Control.Navigation'' lo intercetti (ad esempio con il doppio click destro si esegue uno zoom indietro):
map = new OpenLayers.Map("map", {
controls: [
new OpenLayers.Control.Navigation({handleRightClicks: true}),
...
Infine si registra la funzione handler per l'evento.
Per vedere gli eventi supportati dalla mappa basta vedere la proprietà **''map.events.eventTypes''**. Stranamente l'evento **''rightclick''** esiste, ma non si riesce ad agganciarlo. Per aggirare il problema ci si registra per l'evento **''mousedown''** e nell'handler si verifica quale pulsante lo ha scatenato:
function mousedown_handler(e) {
if (OpenLayers.Event.isRightClick(e)) {
alert("mouse right click event!");
OpenLayers.Event.stop(e);
return false;
}
}
map.events.register('click', map, click_handler);
map.events.register('mousedown', map, mousedown_handler);
===== Problema con Layer.Markers e pop-up =====
Se si disegna un layer di tipo **''OpenLayers.Layer.Markers()''** che contiene delle **''OpenLayers.Feature()''** con il relativo attributo **''popupClass''**, bisogna fare in modo che questi layer siano aggiunti alla mappa per ultimi, altrimenti si rischia che un altro layer (es. un **''OpenLayers.Layer.Vector()''**) aggiunto sopra intercetti il clik e impedisca la comparsa del popup.
È possibile anche usare il metodo **''raiseLayer()''** per abbassare di livello un layer, in modo che venga messo in fondo e non intercetti il clik che fa apparire il popup:
map.addLayer(vectorLayer);
map.raiseLayer(vectorLayer, 2 - map.getNumLayers());
Si decrementa di 2 per tenere in conto il layer stesso e un solo baselayer, di 3 se i baselayer sono due, ecc.