10cze Ł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.
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);
}
}




Czerwiec 13th, 2009 at 17:38
Hej. Ciekawy pomysł. Też coraz częściej zastanawiam się w swoich aplikacjach nad ładowaniem dodatkowych modułów JS później niż podczas ładowania strony. Zwłaszcza przydałoby się to w aplikacjach nieco bardziej złożonych, gdzie ładowanych elementów jest sporo. W tej chwili jeszcze zastanawiam się nad tym jak ładować zależne od siebie elementy, tak, by zachować kolejność wynikającą z zależności.
Dziwny ten Twój kod JavaScript. Nie wiem po co najpierw tworzysz metody _loadMap() i _loadPoint(), a potem kopiujesz je do loadMap i loadPoint. Zupełnie to niepotrzebne. Jeśli chcesz by były za-bind()’owane, to wystarczy this._loadMap = this._loadMap.bind(this); po co tworzyć nowy identyfikator
Czerwiec 15th, 2009 at 13:33
W sumie masz rację, ale jak wiesz w obu zmiennych this.loadMap i this._loadMap będzie dokladnie ta sama funkcja, a nie jej kopia.
Robilem tak dlatego, zeby odroznic metody zbindowane od reszty, ale moze nie wplywa to na czytelność, a wręcz odwrotnie.
Czerwiec 15th, 2009 at 13:55
Mniej chodzi mi o użycie pamięci, a bardziej o czytelność i porządek. Na przykład przeglądając strukturę takiego obiektu w Firebugu, znajdę dwie metody o łudząco podobnych nazwach. Przeglądając Twój kod, z początku chciałem napisać komentarz: “Przecież to nie może działać, masz błąd”
Pozdrawiam
Lipiec 13th, 2009 at 14:51
szacunek dla tych ktorzy cos pisza, a nie pisza tylko negatywne komentarze