This work (tutorial and code) is licensed under a Creative Commons License. You may change and share it under same conditions, NO COMMERCIAL USE ALLOWED.
Download all-in-one-file solution with PHP, Javascript and example.
Google Maps already support unique links to come back later and continue a map search. Such a link contains ideally of the spatial coordinates (Latitude, Longitude) and the current level or altitude. These links are often called permalinks.
ExploreOurPla.net instead provides labeled permalinks. They have a title with the next geographic feature like a city or a place near to the coordinates. If you save one of these links on your desktop or bookmark folder, they are human readable and work better in mails. Continents, countries, cities and even streets are possible items.
This tutorial explains how to get the hierarchical geographic data from geonames.org and how to program an agent in Javascript which controls the presentation. The solution works with FireFox 1.5 and IE 6.0 and should work with other browsers which support AJAX and XMLHttpRequest Object. Needed version for PHP is 4.2.1 or later (domxml_open_mem, CURL) and 1.5 for Javascript.
- Preparation
- First make sure you have a valid API key for your page.
- Download the code (labeled-permalinks.zip, ~10kb).
- Unzip and open labeled-permalinks.php, enter your API Key.
- Save labeled-permalinks.php somewhere on your server.
- If you want to check out the all-in-one-file demo:
- Simply open it in your browser.
- If you want to integrate a map with labeled permalinks into your page:
- php http include it in the <head> section of your html code.
<?php include 'http://server.com/labeled-permalinks.php?act=script'; ?>
- Call the initialization from body.onload .
<body onload='loadMap();' >
- Place a div for the map into the body of the page
<div id='mapPost' style='width: 492px; height: 300px; overflow: hidden; position: relative; background-color: #333333;border:3px solid #E5E3DF;' > </div>
- and a div for the permalink.
<div id = 'postPermaLink' > </div>
- change the target URL in method agentPermaLink.prototype.request() decribed below.
- php http include it in the <head> section of your html code.
- If you want to extend your existing map with labeled permalinks
- Check out section above.
- Do not add duplicate code (getXMLRequester).
- Init events you need.
- Use FireFox and FireBug for debugging resulting code.
- If you simply want to include ExploreOurPla.net with labeled permalinks in your page as iframe use this code as a starting point:
<iframe src='http://exploreourpla.net/explorer/?geoLink=999&lat=40.73268976628568&lon=-73.99429321289062&alt=65536&mid=1&nbl=1,10' id='eopframe' width='500' height='300' scrolling='no' marginheight='0' marginwidth='0' frameborder='0' border='0' > </iframe>
The interactive example with map and permalink will help you to understand what’s going on behind the screen.
In the div above the generated permalink will be written. Just drag the map or zoom it using mousewheel to recenter and watch the answer. The permalink refers to the fullscreen map in a new window.
Some quicklinks to interesting places:
[ Germany, Frankfurt - Europe, Praha - US, White House - Australia, Alice Springs]
The map, some variables and the laocation agent are initialized with the minimum code just like the API suggests. The following lines called from body.onload() event:
var map, mapDiv, mouseLat, mouseLon;
var locAgent = new agentLocation();
function loadMap() {
mapDiv = document.getElementById('mapPost');
map = new GMap2(mapDiv);
map.setCenter(new GLatLng(41.8782527053381, -87.62317657470703), 14);
init();
}
The init() function called at the end prepares needed events to update the permalink everytime map center changes. ‘movestart’ kills any awaiting request because it would be outdated when it arrives. ‘moveend’ triggers a request against geonames.org to retrieve actual geograhic name of map center.
ExploreOurPla.net uses Google Maps API version 2.46, so the mousewheel support is ‘hard’ coded and ‘mousemove’, mouseLat, mouseLon and ’scalerelative’ are needed as well. You may ignore them in your map solution.
function init()
{
if (mapDiv.addEventListener ){GEvent.addDomListener(mapDiv, 'DOMMouseScroll', doMouseWheel);}
else {mapDiv.onmousewheel = doMouseWheel;}
GEvent.addListener(map, 'movestart', function() {locAgent.clear();});
GEvent.addListener(map, 'moveend', function() {locAgent.refreshlater(1);});
GEvent.addListener(map, 'mousemove', function(p){mouseLat = p.lat(); mouseLon = p.lng();});
GLatLng.prototype.scaleRelative = function(a, z) {
var nx = ((this.lng() - a.lng()) / z) + a.lng();
var ny = ((this.lat() - a.lat()) / z) + a.lat();
return new GLatLng( ny, nx );
};
}
The constructor saves the map, the xmlHTTP object and the used language local. The clear() method stops awaiting timer events and http requests.
function agentPermaLink(m, x, l) {
var timer, self = this;
this.xmlhttp = x; this.gmap = m; this.lang = l;
}
agentPermaLink.prototype.clear = function (){
window.clearTimeout(this.timer);
if (this.xmlhttp && this.xmlhttp.abort) {this.xmlhttp.abort();}
}
Refresh() accepts a single parameter, which triggers the request later. This is useful to reduce server load and bandwith. One second is good value to ensure user has stopped navigation.
agentPermaLink.prototype.refresh = function (t) {
this.clear();
if (t) {this.timer = window.setTimeout('permAgent.refresh()', t * 1000);}
else {divPerma.innerHTML = 'Detecting...'; this.request();}
}
This method creates a URL with the coordinates and language, stops any ongoing and old request and send the new request. The callback function onreadystatechange() extracts the answer from the incoming XML and displays directly the location.
agentPermaLink.prototype.request = function () {
var xUrl = '< ?php echo $HTTPURL . '?act=location'; ?>' ;
xUrl += '&LAT=' + this.gmap.getCenter().lat();
xUrl += '&LON=' + this.gmap.getCenter().lng();
xUrl += '&LAG=' + this.lang;
this.xmlhttp.abort();
this.xmlhttp.open('GET', encodeURI(xUrl), true);
this.xmlhttp.onreadystatechange = function()
{
if (permAgent.xmlhttp.readyState == 4){
var url, htm, ret;
ret = permAgent.getXMLdata('pl');
if (ret){
url = 'http://exploreourpla.net/?geoLink=999';
url += '&lat=' + permAgent.gmap.getCenter().lat();
url += '&lon=' + permAgent.gmap.getCenter().lng();
url += '&alt=' + Math.pow(2, 26 - permAgent.gmap.getZoom());
htm = '<a target=\'_blank\' href=\'' + url + '\' >';
htm += ret + '</a>';
divPerma.innerHTML = htm;
}}}
this.xmlhttp.send();
}
getXMLdata() checks for valid XML and returns the content of given tag.
agentPermaLink.prototype.getXMLdata = function (t)
{
var x = this.xmlhttp;
if (!x.responseXML){return false;}
if (!x.responseXML.getElementsByTagName(t)[0].firstChild) {return false;}
var data = x.responseXML.getElementsByTagName(t)[0].firstChild.data;
if (data === ''){return false;} else {return data; }
}
The requested results from geonames.org differ depending on available data. The answer is always XML encoded and provides more information about the found place than used for labeled permalinks. This is the answer for Europe, Prague as in the example above: XML.
The service used for the labeled permalinks is an extended nearby service combined with a street level reverse geocoder for US only and the hierarchy service discussed in the geonames forum.
When you start with AJAX or Google Maps, it is definetly a good idea to prepare everything with FireFox and FireBug first and later then for Internet Explorer and the other browsers.
When you have FireBug installed have a look at the answer coming from the PHP proxy, they have the used geonames URL inside. Check out other useful plugins for programming.
Hopefully the tutorial has helped you, you are invirted to discuss any solution or problem at the end of this posting: Tutorial for labeled permalinks is online