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();
}
...