keemor.com - Surfin' JavaScript Wave

Ładowanie na żądanie i Google Maps API

Zdarza się, że funkcjonalność, którą udostępniam na stronie jest rozbudowanym modułem JS, ale jednocześnie może nie być w ogóle użyta po załadowaniu strony. Wtedy warto się zastanowić czy ładować kod od razu z całą stroną (co oczywiście wpływa na prędkość ładowania) czy dociągać go dopiero po akcji użytkownika.

Przykładem realizacji wzorca projektowego ładowanie na żądanie, może być dynamiczne ładowanie API Google Map, aby pokazać dany adres na mapie.

Zobacz przykład

W tej chwili Google udostępnia już dynamiczne ładowanie różnych API przy pomocy AJAX API, ale udam, że tego nie ma, gdyż chce pokazać co się dzieje w tle.

Na początek zdefiniuje klasę z konstruktorem init i trzema metodami:
getMap – pobiera API map, loadMap – ładuję mapę i loadPoint – ładuję punkt na mapie.

Jeżeli nie znasz metody bind zapoznaj się z Tu Haczyk IStnieje – ‘this’ cz. I .

W linii 9. konstruktora rejestruję zdarzenie click na grupie linków zawartych w liście o id=”poi”.


var Gmap = {
	init: function() {
		this.apiKey = 'TWOJ-KLUCZ-G-API';
		this.location = '';
		this.mapObj = null;
		this.mapDiv = $('map');
		this.loadMap = this.loadMap.bind(this);
		this.loadPoint = this.loadPoint.bind(this);
		$$('#poi li > a')
		.invoke('observe','click',this.getMap.bind(this));
	},
	getMap : function(e){
	},
	loadMap : function() {
	},
	loadPoint: function(point) {
	}
};	
document.observe('dom:loaded', Gmap.init.bind(Gmap));

Pojedyńcze ładowanie na żądanie

Wywołanie metody getMap na początku powoduje pobranie do zmiennej location adresu, który chcę wyświetlić, ze zmiennej e (event), która w element() zawiera kliknięty tag a.
Następnie po sprawdzeniu, że obiekt mapObj jest pusty, tworzę element DOM gmScript zawierający tag script, który po otrzymaniu wartości parametru src i osadzeniu w tagu body zaczyna ładować API map. Kluczowy jest tutaj parametr callback, który otrzymał wartość Gmap.loadMap i ta właśnie metoda zostanie wywołana po załadowniu całej biblioteki. Przy następnych wywołaniach getMap i sprawdzeniu, że this.mapObj nie jest pusty, od razu zostanie wywołana metoda loadMap.


getMap : function(e){
	e.stop();
	this.location = e.element().innerHTML;		
	if (this.mapObj !== null) {
		this.mapDiv.show();
		this.loadMap();
	} else {
		this.mapDiv.update('ładuje ...').show();
		var body = $$('body')[0];
		var gmScript = new Element('script', {
		'src': 'http://maps.google.com/maps?file=api&v=2.x&key=' + this.apiKey + '&sensor=false&async=2&callback=Gmap.loadMap',
		'type': 'text/javascript'
		});
		body.insert(gmScript);
	}
}

Tworzenie mapy

W tej metodzie tworzony jest obiekt mapy i osadzony w this.mapDiv = $(‚map’); co zdefiniowane jest w konstruktorze.
Do mapy dodaje dwie kontrolki: GSmallMapControl do nawigacji oraz GMapTypeControl do zmiany rodzaju widoku.
7. linijka to pobranie długości i szerokości geograficznej na podstawie adresu w location i przekazaniu do metody loadPoint.


loadMap : function() {
	this.mapObj = new GMap2(this.mapDiv);
	this.mapObj.addControl(new GSmallMapControl());
	this.mapObj.addControl(new GMapTypeControl());	
	geocoder = new GClientGeocoder();
	geocoder.getLatLng(this.location, this.loadPoint);
}

Widok 3D czyli Earth jako bonus

Warto w tym momencie wspomnieć o łatwym rozszerzeniu mapy o widok 3D przy pomocy Google Earth API.
Po umieszczeniu poniższej linijki w metodzie loadMap na widoku mapy obok trzech standardowych rodzajów widoków: Map, Satellite i Hybrid pojawi się rodzaj Earth. Funkcja ta wymaga zainstalowania wtyczki systemowej dostępnej dla Windows oraz Mac OS X i działa w przęglądarkach Firefox, Chrome, IE 6&7 oraz Safari na Mac. W IE8 na razie nie działa.


	this.mapObj.addMapType(G_SATELLITE_3D_MAP);

Dodanie punktu na mapie

Po otrzymaniu z metody geocoder.getLatLng współrzędnych geograficznych punktu, tworzę marker, który nanoszę na mapę.
W ostatniej linijce dorzucam balon z adresem, który pokazujemy i gotowe.


loadPoint: function(point) {
	if (!point) {
		this.mapDiv.hide();
		alert(this.location + " not found!");
	} else {
	  this.mapObj.setCenter(point, 16);
	  var marker = new GMarker(point);
	  this.mapObj.addOverlay(marker);
	  marker.openInfoWindowHtml(this.location);	
	}
}