www.gmapsapi.com

Kompleksowy kurs podstaw API, po którym mapowianie nie będzie miało przed Tobą żadnych tajemnic!

Setki przykładów, kursów i poradników z kodem gotowym do skopiowania i korzystania.

Największa strona o Google Maps API w Polsce, największe źródło informacji w języku polskim.

Zaznaczanie obszaru przez użytkownika

Ten artykuł dotyczy API w wersji 2

« powrót do listy poradników

W Twojej aplikacji możesz niejednokrotnie wymagać od użytkownika zaznaczenia pewnego obszaru mapy za pomocą myszy. Dzięki temu możesz wyświetlić jedynie markery z określonego przedziału lub wykonać inne akcje. W tej części kursu poznasz sposób realizacji zaznaczania prostokątnego obszaru za pomocą myszy, wraz z przykładowym zastosowaniem.

Założenia

Zaznaczanie obszaru prostokątnego można stworzyć przy użyciu polilinii, ale rozwiązanie to jest wolne, szczególnie w przeglądarce Internet Explorer. W tym tutorialu zostanie to rozwiązane w prostszy i szybszy sposób. Sterowanie obszarem zaznaczania polegać będzie na kliknięciu w pierwszym punkcie w celu otwarcia zaznaczenia, i w punkcie drugim w celu jego zakończenia. W trakcie przesuwania myszy użytkownik będzie widział dynamicznie odświeżany prostokąt, pokazujący graficznie zaznaczony obszar.

Najprostsza w użyciu będzie klasa GOverlay(), której działanie przedstawiłem w tym poradniku. Dzięki niej wstawimy na mapę element blokowy div, odpowiednio go przestylujemy, a dzięki wewnętrzym funkcjon API zmiana jego rozmiaru i odświeżanie będzie banalnie proste. Założenia i sposób osiągnięcia celu będzie identyczny jak w tutorialu 19, diabeł jednak tkwi w szczegółach.

Inicjalizacja

Najpierw stworzymy nową klasę o nazwie ZaznaczObszar:

function ZaznaczObszar(punkt1,punkt2)  
{  
    this.punkt1 = punkt1;   
	this.punkt2 = punkt2 || punkt1;
}; 

Konstruktor posiada dwa argumenty - punkty typu GLatLng, które zapisujemy jako własności obiektu tej klasy. Jeśli punkt2 nie został podany, to wartość this.punkt2 ustawiamy na argument punkt1. Te dwa punkty będą określać dwa naprzeciwległe narożniki zaznaczanego prostokątnego obszaru.

Klasa ZaznaczObszar ma dziedziczyć po GOverlay, co też czynimy:

ZaznaczObszar.prototype = new GOverlay();  

ZaznaczObszar.prototype.pobierz = function()
{
	var granica = new GLatLngBounds();
	granica.extend(this.punkt1);
	granica.extend(this.punkt2);
	return granica;
};

Metoda pobierz() będzie zwracać prostokątny obszar GLatLngBounds, określony przez narożniki punkt1 i punkt2. W celu zagwarantowania poprawności obszaru, stopniowo rozszerzamy go (metoda extend() o dwa punkty), a następnie zwracamy.

Teraz należy napisać metodę, dzięki której współrzędne drugiego punktu obszaru będą odświeżane wraz z ruchami myszy:

ZaznaczObszar.prototype.ustawPunktKoncowy = function(punkt)
{
	this.punkt2 = punkt;
	this.redraw(true);
};

Metoda ustawPunktKoncowy() zmieni własność punkt2 na punkt, określony w jedynym przekazywanym argumencie. Następnie wymusi ona przerysowanie zaznaczenia tak, by współrzędne prostokąta na ekranie odpowiadały własnościom zaznaczenia.

Metody initialize, copy, remove

Kolejne kroki są bardzo podobne do tego, co zostało przedstawione w tym poradniku, w związku z czym nie będę ich komentował:

ZaznaczObszar.prototype.initialize = function(mapa)
{
	this.mapa = mapa;
	var kontener = document.createElement('div');
	kontener.style.border = '2px solid red';			
	kontener.style.position = 'absolute';
	this.mapa.getPane(G_MAP_MAP_PANE).appendChild(kontener);
	this.kontener = kontener;
};

ZaznaczObszar.prototype.remove = function()
{
	this.kontener.parentNode.removeChild(this.kontener);
};

ZaznaczObszar.prototype.copy = function()
{
	return new ZaznaczObszar(this.punkt1,this.punkt2);
};

Rysowanie prostokąta

Czas na narysowanie prostokąta - wpierw konwertujemy współrzędne geograficzne na pozycję XY względem górnego, lewego narożnika mapy, używając metody mapa.fromLatLngToDivPixel(). Wyciągamy z każdego z punktów współrzędne x i y, a następnie porównujemy odpowiadające sobie współrzędne i razie potrzeby je zamieniamy. Po tej operacji położenie prostokąta określone będzie współrzędnymi pierwszego punktu, a długość i szerokość prostokąta będzie różnicą odpowiadających sobie wartości. Oto kod:

ZaznaczObszar.prototype.redraw = function(wymus)
{
	if (!wymus || !this.punkt2 || !this.punkt1)
		return;
		
	var x1 = this.mapa.fromLatLngToDivPixel(this.punkt1).x;
	var y1 = this.mapa.fromLatLngToDivPixel(this.punkt1).y;
	var x2 = this.mapa.fromLatLngToDivPixel(this.punkt2).x;
	var y2 = this.mapa.fromLatLngToDivPixel(this.punkt2).y;
	
	if(x1>x2)
	{
		var x_temp = x1;
		x1 = x2;
		x2 = x_temp;
	}
	
	if(y1>y2)
	{
		var y_temp = y1;
		y1 = y2;
		y2 = y_temp;
	}
	
	this.kontener.style.left 	= x1+'px';
	this.kontener.style.top 	= y1+'px';
	this.kontener.style.width	= x2-x1+'px';
	this.kontener.style.height	= y2-y1+'px';
};

Ostatnie szlify

Ostatnie co pozostało to zaprogramowanie odpowiednich zdarzeń przy kliknięciu i przesuwaniu myszy. Oto moja propozycja:

GEvent.addListener(mapa,'mousemove',function(p)
{
	if(!obszar || !obszar.punkt1)
		return;
	obszar.ustawPunktKoncowy(p);
});

Ogólnie mówiąc, gdy pozycja kursora myszy zmieni się to sprawdzamy, czy istnieje obiekt obszar oraz czy posiada odpowiednią właściwość punkt1. Jeśli tak jest, to ustawiamy wartość drugiego punktu za pomocą metody ustawPunktKoncowy().

GEvent.addListener(mapa,'click',function(o,p)
{
	if(!p)
		return;
	if(!obszar)
	{
		obszar = new ZaznaczObszar(p);
		mapa.addOverlay(obszar);
	}
	else
	{
		GLog.write('Obszar: '+obszar.pobierz());
		obszar.remove(); 
		obszar = null;
	}
});

Gdy zostanie kliknięty lewy przycisk myszy sprawdzamy, czy istnieje obiekt obszar. Jeśli nie, to tworzymy go, przekazując jako argument kliknięty punkt (jest on klasy GLatLng), a następnie dodajemy stworzony obiekt na mapę. Jeśli obiekt już istnieje, to wyświetlamy współrzędne zaznaczonego obszaru (GLog.write() zasadniczo służy do debugowania aplikacji, ale jest mniej uciążliwe niż alert(), stąd pozwoliłem sobie użyć tej funkcji w celu zaprezentowania, że zaznaczony obszar jest znany). Następnie usuwamy zaznaczenie i ustawiamy wartość obiekt na null.

Tak napisany przykład da następujący efekt: