A feladat egy olyan webtérkép készítése, amelynek alapja a http://www.sat24.com/image2.ashx?region=hu címen található, rendszeresen frissülő műholdkép. További elvárások:
A térképnek készítünk egy div
elemet tárolónak, létrehozzuk az OpenLayers.Map objektumot és rajta egy image layert.
A műholdkép vetülete poláris sztereografikus vetület, 60°-os normálparallelkörrel és 10°-os kezdőmeridiánnal.
Ebben a vetületben a pixelméret kb. 1503m, és a kép bal felső sarkának koordinátái: (26154, -4160639).
Ezeket az értékeket használjuk a befoglaló téglalap és a képméret megadásakor:
<!DOCTYPE html> <html> <head> <META name="Author" content="Gede Mátyás"> <meta content="text/html; charset=utf-8" http-equiv=Content-Type> <LINK href="../../../../style.css" rel="stylesheet" type="text/css"> <title>Gede Mátyás - OpenLayers esettanulmány - 1. lépés</title> <script src="http://openlayers.org/api/OpenLayers.js"></script> <script type="text/javascript"> function init() // az oldal betöltésekor végrehajtandó függvény { // létrehozzuk a térképet a 'terkep_helye' azonosítójú div elemben var map = new OpenLayers.Map('terkep_helye', { maxExtent: new OpenLayers.Bounds(26154, -4160639-615*1503, 26154+845*1503, -4160639) }); // létrehozunk egy WMS réteget var bmp = new OpenLayers.Layer.Image( "Közép-Európa műholdkép", 'http://www.sat24.com/image2.ashx?region=hu', new OpenLayers.Bounds(26154, -4160639-615*1503, 26154+845*1503, -4160639), new OpenLayers.Size(845*1503,615*1503), { numZoomLevels: 4, maxResolution: 1503 // pixelméret méterben }); // hozzáadjuk a réteget a térképhez map.addLayer(bmp); // kb. Magyarországra nagyítunk map.zoomToMaxExtent(); } </script> </head> <body onload="init()"> <div style="width:845px; height:615px" id="terkep_helye"></div> </body> </html>
1. lépés: a weboldal a raszteres képpel.
Mivel a továbbiakhoz szükséges a térkép vetületének ismerete, itt az ideje ezt is megadni. Mivel a poláris szereografikus vetület egyenletei egyszerűek, adjuk meg a transzformációkat.
Ezek után már használhatjuk a Graticule
controlt is a fokhálózat megjelenítésére.
... var rad=Math.PI/180; // fok/radián váltószám var R=6378137; // közepes földsugár var c=1+Math.sqrt(3)/2; // c=1+sin(60°) function sign(x) { return x>=0?1:-1; } // signum függvény // vetületi transzformáció definiálása a metsző sztereografikus vetülethez (la0=10) OpenLayers.Projection.addTransform("EPSG:4326","meteo_stereo", function (point) { var fi=point.y; var la=point.x-10; var ro,x,y; with(Math) { ro=c*tan(PI/4-fi*rad/2); point.x=R*ro*sin(la*rad); point.y=-R*ro*cos(la*rad); } return point; }); // inverz vetületi transzformáció definiálása a metsző sztereografikus vetülethez (la0=10) OpenLayers.Projection.addTransform("meteo_stereo","EPSG:4326", function (point) { var x=point.x,y=point.y; with(Math) { ro=sqrt(x*x+y*y); if (ro==0) la=0; else la=acos(-y/ro)*sign(x)/rad; la+=10; if (la>180) la-=360; point.x=la; point.y=(PI/4-atan(ro/R/c))/rad*2; } return point; }); ... // létrehozzuk a térképet a 'terkep_helye' azonosítójú div elemben var map = new OpenLayers.Map('terkep_helye', { projection: new OpenLayers.Projection('meteo_stereo'), maxExtent: new OpenLayers.Bounds(26154, -4160639-615*1503, 26154+845*1503, -4160639) }); ... // legyen fokhálózat is map.addControl(new OpenLayers.Control.Graticule( { layerName: 'Fokhálózat', lineSymbolizer: { strokeColor: "#ffff00", strokeWidth: 1 }, labelSymbolizer: { fontColor: "#ffff00" }, } )); // és egy layerswitcher map.addControl(new OpenLayers.Control.LayerSwitcher()); ...
2. lépés: definiáltuk a vetületet és rajzoltatunk fokhálózatot is.
A vízrajzhoz legcélszerűbb valami kész alapanyagot felhasználni. A k_eu_viz.kml fájlban megtalálható Közép-Európa erősen generalizált vízrajza, ez most tökéletesen megfelel.
A KML fájlt Vector
layerként adjuk a térképhez:
... // Közép-Európa vízrajz KML layer var kml=new OpenLayers.Layer.Vector( "Vízrajz", { projection : new OpenLayers.Projection("EPSG:4326"), strategies: [ new OpenLayers.Strategy.Fixed() ], protocol: new OpenLayers.Protocol.HTTP( { url: "k_eu_viz.kml", format: new OpenLayers.Format.KML() }), style : { 'fillColor': '#8080ff', 'fillOpacity' : 1, 'strokeColor' : '#0000ff', 'strokeWidth' : 1 } }); map.addLayer(kml); ...
A következő lépés a geokódolás megvalósítása, azaz mutassa meg egy földrajzi név helyét, és fordítva. A geokódoláshoz az OSM Nominatim-ot fogjuk hasznáni. A helynév alapján való kereséshez a HTML kódban elhelyezünk egy input dobozkát, amibe írhatunk, és egy hozzá tartozó gombot:
... <body onload="init()"> Település:<input type="text" id="helynev" onkeypress="if (event.keyCode==13) geokod(this.value);" /> <input type="button" value="Mutat" onclick="geokod(document.getElementById('helynev').value)" /> <div style="width:845px; height:615px" id="terkep_helye"></div> </body> ...
A geokódolást script
node-ok létrehozásával valósítjuk meg. Az eredményt egy külön erre a célra létrehozott "pts" nevű rétegen pontokként jelenítjük meg:
... // Geokódolás az OSM Nominatim használatával function geokod(hely) { if (hely=='') return; var s=document.createElement('script'); s.src='http://nominatim.openstreetmap.org/search?q='+hely+'&format=json&json_callback=helyetMutat&addressdetails=1'; document.body.appendChild(s); } // Geokódolás callback függvénye function helyetMutat(valasz) { if (valasz[0]) { var name=valasz[0].display_name; var w=new OpenLayers.Projection("EPSG:4326"); var p=new OpenLayers.Projection("meteo_stereo"); var pt={x:valasz[0].lon,y:valasz[0].lat}; OpenLayers.Projection.transform(pt,w,p); var marker=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(pt.x, pt.y), {}, { label: name, labelAlign: 'lb', labelXOffset: 10, labelYOffset: 0, fontColor: '#ff50ff', fontWeight: 'bold', externalGraphic: valasz[0].icon, graphicHeight: 20, graphicWidth: 20, graphicYOffset:-15, graphicXOffset:-10 }); pts.addFeatures(marker); } else // ha nincs eredmény alert('Nincs találat.'); } ... // pts layer a geokódolt pontoknak pts=new OpenLayers.Layer.Vector( "Pontok", { isBaseLayer: false, projection: new OpenLayers.Projection('meteo_stereo') }); map.addLayer(pts); ...
Hasonlóan megvalósíthatjuk az inverz geokódolást is: itt a térképre kattintva megjelenik az adott hely neve.
... // Inverz geokódolás az OSM Nominatim használatával function inverzGeokod(loc) { var s=document.createElement('script'); s.src='http://nominatim.openstreetmap.org/reverse?lat='+loc.lat+'&lon='+loc.lon+'&zoom=10&format=json&json_callback=inverzHelyetMutat&addressdetails=1'; document.body.appendChild(s); } // Inverz geokódolás callback függvénye function inverzHelyetMutat(valasz) { if (valasz.display_name) alert(valasz.display_name); else alert('Nem tartozik helynév ehhez a ponthoz.') } ... // egérkattintás eseménykezelő ( geokódolás ) map.events.register("click", map, function(e) { // a kattintás helye a térképet tartalmazó div-ben var pxPos=map.events.getMousePosition(e); // átszámítva az aktuális vetületi rendszerbe var projPos=map.getLonLatFromPixel(pxPos); // átszámítva földrajzi koordinátákra var geoPos=projPos.clone().transform(new OpenLayers.Projection("meteo_stereo"),new OpenLayers.Projection("EPSG:4326")); inverzGeokod(geoPos); }); ...
Adjunk egy újabb gombot a kezelőfelülethez (területmérés), és definiáljunk egy helyet, ahova a mérési eredmény kerülhet:
... <input type="button" id="teruletmero" value="Területmérés" onclick="terulet(this)" /> <span id="meret"></span> ...
A területméréshez a OpenLayers.Control.Measure
controlt használjuk, poligon handlerrel.
... var mero, meres=false; // globális változók a térképi mérésekhet ... // területmérő control mero=new OpenLayers.Control.Measure( OpenLayers.Handler.Polygon, { persist: true, immediate: true } ) map.addControl(mero); // területmérő eseménykezelői mero.events.on({"measurepartial": function (event) { document.getElementById("meret").innerHTML='Terület: '+(event.geometry.getArea()/1000000).toFixed(0)+" km²"; }}); mero.events.on({"deactivate": function (event) { document.getElementById("meret").innerHTML=''; }}); ...
A gomb megnyomásával ki-be kapcsolhatjuk a mérést, amit a gomb felirata is jelez:
... // területmérés indítása/befejezése function terulet(button) { meres=(button.value=='Területmérés'); button.value=meres?'Mérés befejezése':'Területmérés'; // a gomb felirata az állapottól függ if (meres) mero.activate(); else mero.deactivate(); } ...