What a lovely photograph! Where was it taken?
Since the rise of digital photography, more people have been snapping more photos than ever. Web sites such as Flickr have sprung up to help people manage and publish their photos, and Flickr itself has gone one step further and allows its users to "tag" their photographs with keywords that indicate what's being depicted. These tags can help you figure out who and what is being depicted, but wouldn't it be nice sometimesparticularly in the case of those lovely landscape photosto know where they were taken?
5.6.1. Tag, You're It
Fortunately, Flickr provides an API that allows you to query data from its system, and we can use this to find images that have been geotagged. Geotagged photos on Flickr have three special tags associated with them. First, they're tagged as geotagged, which allows us to find them using the Flickr API. Second, they have the tags geo:lat=…and geo:long=…associated with them, which gives us their geographic coordinates. Figure 5-18 shows one sort of map that can be made by mashing up the Flicker API and the Google Maps API.
In order to make use of the Flickr API, you need to sign up to Flickr, and then get yourself an API key from http://www.flickr.com/services/api/. Once you have a key, you can query Flickr using the flickr.photos.search call from their REST API, with a URL like:
http://www.flickr.com/services/rest/?method=flickr.photos.search&api_ key=[your API key]&tag_mode=all&tags=geotagged&per_page=20
This returns an XML document matching the latest photos tagged as geotagged. The XML looks something like the following:
Figure 5-18. A map of recent geotagged photos from Flickr
By querying the API for each particular photo, we can get the detailed tags for each one. For example, this URL returns the details of the "Tiny Sea Cave" photo above:
http://www.flickr.com/services/rest/?method=flickr.photos.getInfo&photo_id =30211741&api_key=[your API key]
The returned XML looks something like the following, which we've excerpted for brevity:
Tiny Sea Cave More of a hole worn in the rock, with lots of little seashells washed inside. carmel sand shells geolat365443288 geolon121933093 geotagged
As you can see, we have all the info we need to locate this photo on a map. All we need to do is search for photos with the geotagged tag, loop over each photo, and request the full information from Flickr. Once we have that, we can use the Google Maps API to generate the map itself and throw down some markers.
5.6.2. The Catch
It sounds easy, but there is one small catch: you're going to be running your photo map page on your server, and you want to get the XML from a different server. For security reasons, most modern browsers, particularly Firefox and Safari, won't allow you to do this. Unless your web page is sitting on Flickr's web site, you can't load the Flickr XML directly into your JavaScript.
What you can do, however, is run a proxy on your own server, which will call Flicker's API for you and pass the results back to your browser. Since the domain of your map page and your XML proxy will be the same, you won't trip any browser's security features. You'll need a web server somewhere that runs some form of server-side code. Within the JavaScript on the map page, we'll pass the URL of the XML you want to retrieve and the JavaScript function you want to handle the XML to the proxy script, and then the proxy will return a bit of executable JavaScript to your calling page.
Here's some PHP, which I put in a file called passThru.php on my web server, that does the trick:
Here's a snippet of JavaScript code that shows how we use the XML proxy to get Flickr metadata into our page:
1 var thisXML; 2 var sFlickrAPIKey = "[your API key ]"; 3 var sFlickrURL = 'http://www.flickr.com/services/rest/?method=flickr.photos. search' 4 + '&tag_mode=all&tags=geotagged&per_page=20&api_key=' + sFlickrAPIKey; 5 var sPassThruURL = 'http://www.geobloggers.com/googleMapHacks/passThru.cfm'; 6 7 var newJSElement = document.createElement("script"); 8 newJSElement.src=sPassThruURL + '?sURL=' + escape(sFlickrURL) 9 + '&sFunction=fnHandleFlickr( )'; 10 newJSElement.type = "text/JavaScript"; 11 12 document.getElementsByTagName("head")[0].appendChild(newJSElement);
Here's what's going on. In lines 1 through 5, we define thisXML as a global variable, set up our API key, set the URL we actually want the data from, and then set the URL where our XML proxy sits. Line 7 sets up a new HTML script element, and line 8 sets its src attribute, passing the URL we want to get, and the function we want to handle it when it comes back. In line 9, we set the type attribute of the new script element, so that the browser knows it's JavaScript. Line 10 sets everything in motion by attaching our JavaScript to the document's head element, causing the browser to fetch and execute the code via our XML proxy.
The function that gets called needs to convert the string representation of the XML into an actual XML document, so the function starts out like this:
function fnHandleFlickr() { try { var xmlDoc = xmlParser.parseFromString(thisXML, "application/xml"); } catch(er) { alert("Sorry, couldn't parse the XML returned by Flickr!"); } }
So why are we doing it this way, instead of, say, using XMLHttpRequest( )? The main advantage of getting XML by constructing a new
You Are Here: Introducing Google Maps
Introducing the Google Maps API
Mashing Up Google Maps
On the Road with Google Maps
Google Maps in Words and Pictures
API Tips and Tricks
Extreme Google Maps Hacks