Flickr api, google maps i javascript

W tutorialu prześledzimy kod jednego z moich dem na Dev Derby Where am I?. Jest to aplikacja, która na podstawie aktualnej pozycji (geolocation api) pokazuje Twoją pozycję na mapie (google maps api) oraz pobiera zdjęcia z flickr w jej pobliżu (Flickr api). Taki prosty mashup.

Najlepiej testować ją na smartfonie lub tablecie, ponieważ na desktopie mogą się zdarzyć problemy z ustaleniem pozycji. flickr api i google maps - Where am I Szablon html wygląda następująco.
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Where am I?</title>
        <meta name="description" content="App show your location (lat, lon) and photos from Flickr near that location.">
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="css/styl.css">
		<script type="text/javascript" src="js/cufon-yui.js"></script>
		<script type="text/javascript" src="js/Remachine_Script_400.font.js"></script>
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
		<script type="text/javascript" src="js/main.js"></script>
		<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=TWOJ_API_KEY&amp;sensor=false"></script>
    </head>
    <body>
		<h1>Where am I?</h1>
		<div>
		<table>
			<tr><td>Latitude:</td><td id="latitude"></td></tr>
			<tr><td>Longitude:</td><td id="longitude"></td></tr>
			<tr><td>Altitude:</td><td id="altitude"></td></tr>
			<tr><td>Current time:</td><td id="time"></td></tr>
		</table>
		</div>
		<div id="map">
		</div>
		<div id="images">
		</div>
	</body>
</html>
Załączamy jquery, main.js (tutaj będzie kod aplikacji), style css oraz skrypty google maps. W prostej tabelce wyświetlimy naszą pozycję (latitude, longitude, altitude) oraz aktualny czas. W divie o id map wyświetlimy mapkę z Twoją pozycją, a w divie od id images zdjęcia pobrane z Flickra.
Zajmijmy się teraz plikiem main.js. Ważna uwaga już na początku: ze względu na ograniczenia flickr api nie pobierzemy zdjęć odrazu na podstawie pozycji ale najpierw za pomocą obiektu Geocoder googla zgeokodujemy naszą pozycję na składowe adresowe. Na ich podstawie zbudujemy tzw. tag i dopiero na jego podstawie odpytamy flickra.
Najpierw jak widać poniżej inicjalizujemy kilka zmiennych (bieżący czas, klucz api Flickr, obiekt geocoder i tag). Do elementu o id time wstawiamy aktualny czas. Następnie za pomocą geolocation api pobierzemy aktualną pozycję użytkownika. Wykorzystujemy metodę getCurrentPosition obiektu navigator.geolocation.
$(document).ready(function() {
	var datetime = new Date(), api_key = 'klucz_api_flickr', geocoder = new google.maps.Geocoder(), tag = '';
	$('#time').text(datetime);
	navigator.geolocation.getCurrentPosition(function (position) {
		//tutaj będzie dalszy kod aplikacji
	}, function(error) {
		alert('Error: '+error.code);
	});
});
Dalej wewnątrz metody getCurrentPosition pobieramy aktualne współrzędne i wstawiamy je do naszej tabelki.
var coords = position.coords;
$('#latitude').text(coords.latitude);
$('#longitude').text(coords.longitude);
$('#altitude').text(coords.altitude);
Poniższy listing pokazuje jak za pomocą google maps api wstawiamy mapkę z zaznaczonym na niej markerem z aktualną pozycją użytkownika.
var mapOptions = {
	center: new google.maps.LatLng(coords.latitude, coords.longitude),
	zoom: 14,
	mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var marker = new google.maps.Marker({
	position: new google.maps.LatLng(coords.latitude, coords.longitude)
});
marker.setMap(map);
Teraz najważniejsza część skryptu. Za pomocą obiektu geocoder geokodujemy nasze współrzędne. Jeśli wszystko przebiegnie pomyślnie dzielimy wynikowy rezultat na części składowe adresu (route, locality, country itd.). Na tej podstawie uzyskujemy tag potrzebny do zapytania do flickr api. Samo zapytanie do Flickr api odbywa się za pomocą jquery getJSON. Pobieramy dane z adresu http://api.flickr.com/services/rest, jako metodę podajemy flickr.photos.search tzn., że szukamy zdjęć. Musimy przekazać również klucz api flickra oraz nasz tag (tags=tag). Jako format danych, które chcemy otrzymać podajemy json. Ponadto podajemy parametr jsoncallback, dzięki któremu obsłużymy anonimową funkcją odbierającą otrzymane dane. Przechodzimy przez otrzymane w odpowiedzi dane pętlą. Każde zdjęcie znajduje się w obiekcie data.photos.photo[i], gdzie data to odebrane dane. Na podstawie otrzymanych danych budujemy wynikowy ciąg znaków img_str, który potem dodajemy do diva o identyfikatorze images. Warto zwrócić uwagę jak budujemy url do zdjęcia (photo_url) na podstawie item.farm, item.server, item.id oraz item.secret. Więcej na temat budowania urli oraz na temet samego api.
var latlng = new google.maps.LatLng(coords.latitude, coords.longitude);
geocoder.geocode({'latLng': latlng}, function(results, status) {

if (status == google.maps.GeocoderStatus.OK) {
	if (results) {
			var arrAddress = results[0].address_components;
			var itemRoute='';
			var itemLocality='';
			var itemCountry='';
			var itemPc='';
			var itemSnumber='';
			
			$.each(arrAddress, function (i, address_component) {
				if (address_component.types[0] == "route"){
					itemRoute = address_component.long_name;
				}
				if (address_component.types[0] == "locality"){
					itemLocality = address_component.long_name;
				}
				if (address_component.types[0] == "country"){ 
					itemCountry = address_component.long_name;
				}
				if (address_component.types[0] == "postal_code_prefix"){ 
					itemPc = address_component.long_name;
				}
				if (address_component.types[0] == "street_number"){ 
					itemSnumber = address_component.long_name;
				}
			});
			tag = itemLocality;
			//Flickr
			$.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.search&api_key='+api_key+'&tags='+tag+'&format=json&jsoncallback=?',
			function(data) {
				var i, item, photo_url = '', img_str = '', len = data.photos.photo.length;
				for (i = 0; i < len; i++) {
					item = data.photos.photo[i];
					photo_url = 'http://farm'+item.farm+'.staticflickr.com/'+item.server+'/'+item.id+'_'+item.secret+'_m.jpg';
					img_str += '<div><img src="'+photo_url+'" alt=""><div>'+item.title+'</div></div>';
				}
				$('#images').html(img_str);
			});
		}
	} else {
		alert("Geocoder failed due to: " + status);
	}
});
Cały kod pliku main.js poniżej.
$(document).ready(function() {
	var datetime = new Date(), api_key = 'klucz_api_flickr', geocoder = new google.maps.Geocoder(), tag = '';
	$('#time').text(datetime);
	navigator.geolocation.getCurrentPosition(function (position) {
		var coords = position.coords;
		$('#latitude').text(coords.latitude);
		$('#longitude').text(coords.longitude);
		$('#altitude').text(coords.altitude);
		var mapOptions = {
			center: new google.maps.LatLng(coords.latitude, coords.longitude),
			zoom: 14,
			mapTypeId: google.maps.MapTypeId.ROADMAP
		};
		var map = new google.maps.Map(document.getElementById("map"), mapOptions);
		var marker = new google.maps.Marker({
			position: new google.maps.LatLng(coords.latitude, coords.longitude)
		});
		marker.setMap(map);
		var latlng = new google.maps.LatLng(coords.latitude, coords.longitude);
		geocoder.geocode({'latLng': latlng}, function(results, status) {
		
		if (status == google.maps.GeocoderStatus.OK) {
			if (results) {
					var arrAddress = results[0].address_components;
                    var itemRoute='';
                    var itemLocality='';
                    var itemCountry='';
                    var itemPc='';
                    var itemSnumber='';

                    $.each(arrAddress, function (i, address_component) {
                        if (address_component.types[0] == "route"){
                            itemRoute = address_component.long_name;
                        }
                        if (address_component.types[0] == "locality"){
                            itemLocality = address_component.long_name;
                        }
                        if (address_component.types[0] == "country"){ 
                            itemCountry = address_component.long_name;
                        }
                        if (address_component.types[0] == "postal_code_prefix"){ 
                            itemPc = address_component.long_name;
                        }
                        if (address_component.types[0] == "street_number"){ 
                            itemSnumber = address_component.long_name;
                        }
                    });
					tag = itemLocality;
					//Flickr
					$.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.search&api_key='+api_key+'&tags='+tag+/*'&lat='+coords.latitude+'&lon='+coords.longitude+'&geo_context=2*/'&format=json&jsoncallback=?',
					function(data) {
						var i, item, photo_url = '', img_str = '', len = data.photos.photo.length;
						for (i = 0; i < len; i++) {
							item = data.photos.photo[i];
							photo_url = 'http://farm'+item.farm+'.staticflickr.com/'+item.server+'/'+item.id+'_'+item.secret+'_m.jpg';
							img_str += '<div><img src="'+photo_url+'" alt=""><div>'+item.title+'</div></div>';
						}
						$('#images').html(img_str);
					});
				}
			} else {
				alert("Geocoder failed due to: " + status);
			}
		});
		
	}, function(error) {
		alert('Error: '+error.code);
	});
});