A Websuli legutóbbi két leckéjében, miután megismerkedtünk a HTML5 helymeghatározó (geolocation) funkciójával, megnéztük, hogyan illeszthetünk oldalainkba interaktív térképeket, és azokat különféle módokon hogyan tudjuk testre szabni. Ezt követően a térképeken először standard, majd saját helyjelölő bójákat és azokhoz kapcsolódó információs buborékokat helyeztünk el, amelyekben adott pontokhoz kapcsolódó szöveges-képes információkat jelenítettünk meg.
Mindkét rész példaállományai között megtalálható volt egy hasznos kis „segédprogram”, amellyel a térképen kattintással lerakható-áthelyezhető bója aktuális koordinátáit tettük egyszerűen olvashatóvá, sőt másolhatóvá. Azok, akik kipróbálták a példaprogramot, láthatták, hogy egy új funkcióval bővült, a cím szerinti kereséssel.
Címből koordináták
Kis programunk HTML-kódjában két kisebb változtatást hajtottunk végre az elmúlt havihoz képest. Egyrészt az űrlapelemeket egy form-ba illesztettük, és a Geokódolás gombot kineveztük submit, vagyis küldés típusnak, így a cím beírása után már nemcsak a gomb megnyomásával, hanem az Enter billentyű leütésével is elindíthatjuk a keresést. Másrészt létrehoztunk egy új számmezőt (ami Google Chrome-ban és Operában már tényleg számmezőként működik), amelyben megadhatjuk, hogy hány tizedesjegy pontossággal szeretnénk kiíratni a helyjelölő bója koordinátáit (getcoords.html: 13–24. sorok).
A Google Térképek szolgáltatás (maps.google.hu) egyik legismertebb és leggyakrabban használt funkciója az úgynevezett geokódolás, amikor is beírunk egy „emberi fogyasztásra is alkalmas” címet (például 1075 Budapest, Madách Imre út 13-14.), amit azután a program megpróbál megkeresni és megjeleníteni a térképen. Ezt a funkciót a google.maps.Geocoder objektum geocode() metódusán keresztül érhetjük el saját szoftvereinkben, ezért – az inicializáláskor már szokásosnak mondható lépéseken túl – létre kell hoznunk egy ilyen geokodolásra használható objektumot (getcoords.js: 11. sor), amit majd az űrlapunk eseményeként beállított codeAddress() függvény fog majd munkára bírni.
Gyorsabban navigálhatunk a térképen, ha tudjuk a pontos címet
Ez a függvény először is kiolvassa a címet tartalmazó űrlapelem aktuális értékét (55. sor), majd azt átadja Geocoder típusú objektum már említett geocode() metódusának. E metódusnak két paramétert adjunk át: egyrészt természetesen azt a címet, amelynek a koordinátáit keressük, másrészt azt a függvényt, ami akkor fog elindulni, amikor a Google Térképek – sikerrel vagy sikertelenül, de – befejezte a cím feldolgozását (56–63. sorok). Egyes esetekben előfordulhat, hogy biztos, ami biztos alapon akár koordináták (bounds), akár régiókódok (region) megadásával egyértelművé kell tennünk, hogy mely területen is keressük az adott címe(ke)t, különben „Budapest”-re keresve egy floridai vagy egy georgiai címet kaphatunk vissza.
Persze egyáltalán nem biztos, hogy a művelet sikerrel zárul, éppen ezért először meg kell néznünk, hogy minden rendben volt-e (57. sor). Ha igen, akkor biztos, hogy az eredmény tömbünknek legalább egy eleme lesz, amiből jelenleg nekünk csak a koordinátákra lesz szükségünk(results[0].geometry.location), hogy áthelyezzük oda a bóját és a térkép középpontját (58–59. sorok). Abban az esetben pedig, ha valami hiba történt (a cím nem található [ZERO_RESULTS], túl sok kérés érkezett az adott oldalról [OVER_QUERY_LIMIT] stb.), akkor erről egy rövid értesítést küldünk a felhasználónak.
Koordinátákból cím
A címkereséshez képest – egy átlagos felhasználónál legalábbis – sokkal ritkábban, de előfordul(hat) az is, hogy egy pont koordinátái ismertek, és meg kell tudnunk az ehhez a ponthoz tartozó címet (például ha egy geokódolt fotókról szeretnénk kideríteni a készítés helyének pontos adatait). Az ilyen esetekben is nyugodtan segítségül hívhatjuk a google.maps.Geocoder objektum geocode() metódusát, ám ilyenkor első paraméterként nem egy címet, esetleg egy címrészletet adunk meg, hanem egy LatLng formátumú koordinátapárt (inversgeocode.js: 49. sor).
Ennyi mindent tudhatunk meg egy koordinátáról
Eredményül természetesen ugyanúgy egy eredménytömböt kapunk – már amennyiben nem valamilyen hibaüzenetet –, amiben a talált címről kapunk nagyon részletes információkat. Az, hogy mennyi és milyen típusú adatot kapunk egy pontról, az egyrészt függ attól, hogy melyik országban található (például milyen közigazgatási szintek vannak az adott országban), másrészt attól, hogy hova is mutat a megadott koordinátapár (például egy konkrét cím közvetlen közelében, valahol az országúton, esetleg egy mezőn található a keresett pont). Éppen ezért minden egyes címhez kapunk egy „címrészletező” tömböt (address_components) is, amelyben a rövid (short_name) és a hosszú megnevezés (long_name) mellett megtaláljuk az adott címrészlet típusát (types) is.
A típus mintegy két tucat különböző értéket vehet fel az ország- és városnévtől, az adott országra jellemző különböző területi szinteken (állam, megye, kerület stb.) át egészen a házszámig. Ezenkívül pedig még az is előfordulhat, hogy kiderül: a megadott pont egy nagyobb útkereszteződést, egy (nemzeti) parkot vagy éppen egy repülőteret jelöl.
Mintaszoftverünk éppen ezért valamennyi komponens típusát és hosszú megnevezését megjeleníti az információs ablakban az „olvasható cím” alatt, így megnézhetjük azt is, miként változnak az elérhető típusok a különböző országokban, sőt akár országokon belül is.
Merre menjek?
A Google Térképek másik népszerű funkciója - főként az okostelefonokon - az útvonaltervezés, amikor is a program két pont között megkeresi a legrövidebb vagy leggyorsabb, autóval vagy gyalogosan – jelenleg kizárólag az Egyesült Államokban kerékpárral – szabályosan megtehető útvonalat, emellett megmondja azt is, hogy az egyes kereszteződésekben vagy útelágazásoknál merre kell fordulnunk.
Természetesen az alkalmazásnak ezt a szolgáltatását is elérhetjük a Google Maps API-n keresztül, és használhatjuk például arra, hogy az oldalunkra látogatóknak megmutassuk, hogyan jutnak el a legegyszerűbben üzletünkhöz, irodánkhoz stb.
Így juthatunk el autóval A pontból B pontba
Az útvonal megterveztetéséhez egy google.maps.DirectionsService (route.js: 4. sor), a megjelenítéséhez pedig egy google.maps.DirectionsRenderer típusú objektumra (5. sor) lesz szükségünk, amelyek közül utóbbit – például a helyjelölőkhöz hasonlóan – hozzá kell kapcsolnunk a térképünkhöz (14. sor). Az útvonaltervezéshez a directionsService objektum route() metódusát használjuk, amelynek össze kell állítanunk egy DirectionsRequest típusú „paramétercsomagot”. Ebben szerepelnie kell a kezdő- és a végpontnak (mindkettő lehet cím- vagy koordinátapár), valamint a közlekedés módjának (autóval: DRIVING, gyalog: WALKING, esetleg az Egyesült Államokban kerékpár: BICYCLING).
Ezenkívül megadhatjuk még, hogy metrikus vagy angolszász mértékegységben szeretnénk-e megkapni az eredmény(eke)t, akarunk-e köztes pontokat érinteni, ha igen, akkor azok optimalizálását kérjük-e, vagy ragaszkodunk a megadott sorrendhez, valamint, hogy autóval történő utazás esetén engedélyezzük-e az autópályákon és/vagy fizetős utakon történő közlekedést vagy sem.
Eredményül persze nemcsak magát – a térképünkhöz kapcsolt DirectionsRenderer objektummal megjelenített – az útvonalat (routes) kapjuk meg (28. sor), hanem a teljes útvonal vagy a köztes pontok közötti szakaszok (legs), hosszát és az ezek megtételéhez szükséges várható időtartamot is (29–30. sorok).
Akár részletes navigációt is kérhetünk
Sőt mi több, szükség esetén hozzáférhetünk az út vagy az egyes útszakaszok fontosabb „töréspontjainak” pontos koordinátáihoz, az ezek közötti távolságokhoz és a becsült időadatokhoz, valamint az ezekhez a pontokhoz tartozó navigációs instrukciókhoz is (routedetailed.js: 39–49. sorok), így lehetőségünk nyílik akár saját „itinerek” készítésére is, ha éppen esetleg erre lenne szükségünk.
Két pont közötti legrövidebb távolság
Előfordulhatnak olyan esetek is – mint hamarosan látni fogjuk, olyankor is, amikor arra eredetileg nem gondolnánk –, amikor két pont között nem a bejárható, hanem a legrövidebb távolságra van szükségünk. Első pillantásra ez nagyon egyszerűnek tűnik, hiszen ha ismerjük két pont koordinátáit, akkor Pitagorasz tétele segítségével ez a feladat nem jelenthet gondot. Pontosabban nem jelenthetne, ha a Föld sík lenne, ahogyan azt sok száz évvel ezelőtt gondolták.
Mivel azonban a koordinátáink egy gömb felületén határoznak meg pontokat, és nekünk a távolságot a gömb felületén kellene meghatároznunk, máris nem is olyan egyszerű ez a feladat. Persze némi keresgélés után megtalálhatjuk azt a képletet, amivel egy R sugarú gömb felületén a két koordinátapár ismeretében meg tudjuk határozni a köztük levő távolságot, de szerencsére erre nem lesz szükségünk. Egész pontosan nem erre lesz szükségünk, hanem a Google Maps API geometriai könyvtárára, amelynek a használatát előre kell jeleznünk a HTML-kódunkban (distance.html: 6. sor), ugyanis ezen könyvtárra viszonylag ritkán van szükség, így a betöltése nem automatikus.
Ha távolságot akarunk mérni, akkor csatolnunk kell a Geometry könyvtárat is
E könyvtár aktiválása után mégiscsak egyszerű lesz a feladat megoldása, hiszen az ebben található spherical.computeDistanceBetween függvény méterben kiszámolja a paraméterként megadott két pont közötti távolságot (distance.js: 45. sor), amit azután már arra és úgy használunk, amire és ahogy szeretnénk.
Például arra, hogy szeretnénk megtudni, hány pixel távolságra van egymástól a két pont a térképen – ami ugyebár attól is függ, hogy mekkora felületen jelenítjük meg a térképet, ahogyan az sem mindegy, hogy mekkora a térkép aktuális nagyítása.
Először tehát szükségünk lesz egy olyan váltószámra, amely megmondja, hogy az aktuális beállítások mellett egy méter hány pixelt jelent. Ezt a legegyszerűbben és leggyorsabban úgy határozhatjuk meg, ha lemérjük a térkép délnyugati és északkeleti pontjai közötti távolságot méterben (distancepx.js: 32–35. sorok), valamint kiszámoljuk a térképnek helyet adó div átlóját pixelben (37–39. sorok). Ezután osszuk el egymással a kettőt, és ezt a váltószámot a következő nagyításváltásig használhatjuk a pontok közötti távolság meghatározásához.
A távolság méterben nem válzotik, de pixelben már igen
Ebben az esetben két dologra kell nagyon odafigyelnünk. Az egyik, hogy a térkép létrehozásakor – a megadott paraméterek ellenére – még nem ismertek a szükséges pontok koordinátái, meg kell várnunk, amíg a program kiszámolja ezeket (21. sor). A másik, hogy természetesen figyelnünk kell arra is, hogy a térkép nagyításának megváltozásakor ne felejtsük el újraszámolni a váltószámot, persze megint megvárva, amíg a Google Térképek elvégzi a szükséges számításokat (22. sor és 27–29. sorok).
Sok jó bója kis helyen is elfér?
Mikor érdekel(het) minket, hogy milyen messze vannak egymástól a helyjelölő bóják? Például akkor, amikor nagyon sokkal kell dolgoznunk, és szeretnénk elkerülni az áttekinthetetlen „bójaerdők” megjelenését. Ilyenkor sokkal elegánsabb megoldás, ha az egymáshoz túl közel kerülő bójákat összevonjuk, persze valamilyen módon jelölve, hogy az adott ikon több pontot is jelöl éppen.
Persze „élesben” ezeknek a bójáknak a helyét valamilyen adatbázisból szedjük össze, de nekünk most tökéletesen megfelel, hogy a kezdéskor látható területen létrehozunk például 1000 véletlenszerűen elhelyezett jelölőt (clustering.js: 19–33. sorok).
Még 1000 jelölő is elfér egy ekkora területen - csoportokba rendezve
Ilyen kis helyen ilyen sok jelölő gyakorlatilag már átláthatatlan, ezért a megjelenítésüket „szervezzük ki” a showMarkers() függvényünkbe. Ez először is – a korábban már bemutatott módon – kiszámolja a méter–pixel váltószámot (41–50. sorok), majd miután eltüntetett minden bóját a térképről és alapértelmezett állapotra állított őket (54–57. sorok), páronként meghatározza a bóják közötti távolságot (62. sor). Ha az kisebb, mint a beállított alapérték (63. sor), akkor a sorban előrébb levőben egyesíti őket (64–65. sorok). Persze ezen az „algoritmuson” bőven lehetne finomítani (például vegye figyelembe az ikonok kiterjedését, az esetleges „lánchatást” stb.), de ez esetben nem ez a lényeg.
Miután valamennyi párral végzett, végigmegy az összes helyjelölőn, és ha az látható, vagyis a „benne található jelölők” száma, vagyis a status tulajdonság értéke nagyobb nullánál (72–73. sorok), akkor megjeleníti. E megjelenítéshez a thydzik.com bójakészítő funkcióját hívjuk segítségül, aminél „röptében” beállíthatjuk a bója szövegét (text) és színét (color). Így a „szólóbóják” a Google-től „lopott” kék pontozottak lesznek, az 5 vagy kevesebb pontot jelzők zöldek, a 6 és 10 közöttieket jelzők sárgák, a 11 és 20 közöttieket jelzők narancssárgák, a 20-nál többet helyettesítők pedig pirosak. Mindegyikbe írjuk is bele, hogy hány pontot is „érnek” (74–85. sorok). Így a térképünk jelentős mértékben áttekinthetőbbé válik – persze a teljességhez még arra is szükség lesz, hogy az egyes pontokhoz, illetve „pontcsoportokhoz” rendelt információs ablakok tartalmát megfelelően menedzseljük.
A cikkhez kapcsolódó mintaoldal innen tölthető le.