Multiple InfoWindow

15 Август 2010

Давненько я не писал о гуглокартах. Но это скорее потому что мой проект для BetterPlace закончился фэйлом, сайт в продакшн не пошел, хотя он и был для внутреннего пользования. Единственное что стоящее осталось от этого проекта это Google Map API v3 Marker Manager, который я сегодня по случаю обновил.

Но поговорить я хотел не о картах, и не о маркерах а о InfoWindow. Забавно то что на всех картах и во всех примерах InfoWindow всегда один, при нажатии на маркер он просто меняет якорь (маркер) и текст. Никто и никогда не подозревал, что люди хотят сравнить два или больше маркера (я говорю маркера потому что без дополнительного кода google.maps.InfoWindow цепляется только к google.maps.Marker) по параметрам открыв их InfoWindow.

Итак задача: открывать для каждого маркера свой InfoWindow. На самом деле может показаться что все очень просто:


var map = new google.maps.Map(document.getElementById("map1"), {
	zoom: 5,
	center: new google.maps.LatLng(50.440951, 30.527181),
	mapTypeId: google.maps.MapTypeId.HYBRID
});
var marker = new google.maps.Marker({
	map: map,
	position : new google.maps.LatLng(50.440951, 30.527181),
	draggable : false
});
google.maps.event.addListener(marker, "click", function(e){
	map.setCenter(this.getPosition());
	new google.maps.InfoWindow({
		content: this.getPosition().toString()
	}).open(map, this);
});

Но нет, таким способом при каждом клике на маркер будет открываться новое InfoWindow и они будут наслаиваться. Значит надо иметь ссылки на все объекты InfoWindow.

В этом примере я уже использую MarkerManager, с ним как-то удобнее ;)


var myMarkerManager = new MarkerManager(
	new google.maps.Map(document.getElementById("map2"), {
		zoom: 5,
		center: new google.maps.LatLng(50, 27),
		mapTypeId: google.maps.MapTypeId.HYBRID
	})
);
myMarkerManager.createMarker(new google.maps.LatLng(50.440951, 30.527181));
myMarkerManager.createMarker(new google.maps.LatLng(49.836944, 24.005000));

var windows = [];
function createInfoWindow(marker){
	var window = new google.maps.InfoWindow({
		content: marker.getPosition().toString()
	})
	google.maps.event.addListener(window, "closeclick", function(e){
		windows.splice(MarkerManager.prototype.inArray(marker, windows), 1);
	});
	window.open(myMarkerManager.map, marker);
	windows.push(window);
}
	
for (var i in myMarkerManager.markers){
	google.maps.event.addListener(myMarkerManager.markers[i], "click", function(e){
		myMarkerManager.map.setCenter(this.getPosition());
		
		for (var i=0, length=windows.length; i<length; i++){
			if (windows[i].getContent()==this.getPosition().toString()) {
				return;
			}
		}
		createInfoWindow(this);
	})
}

Но и этот способ не айс. Смотрите что происходит: нужно иметь список всех InfoWindow, но никакого метода для их получения не существует. Я очень надеялся найти что-то вроде


// fake code!
var overlays = google.maps.Map.getOverlays();
for (var i in overlays ){
	if (overlays[i] instanceof google.maps.InfoWindow){
		// do staff
	}
}

Но ничего подобного не существует. Более того если InfoWindow был прицеплен к маркеру то у него нет позиции


google.maps.event.addListener(marker, "click", function(e){
	var window = new google.maps.InfoWindow({
		content: this.getPosition().toString()
	}).open(map, this);
	console.log(window.getPosition()) // undefined
});

google.maps.event.addListener(marker, "click", function(e){
	var window = new google.maps.InfoWindow({
		content: this.getPosition().toString(),
		position : this.getPosition()
	}).open(map, this);
	console.log(window.getPosition()) // position
});

Но во втором варианте проблема в том что InfoWindow будет относиться не к маркеру (стрелочка указывает на центр верха маркера), а к точке к которой относиться маркер.

Поскольку InfoWindow не имеет позиции, то сравнивать приходиться не позиции а содержимое, это мало того что не удобно так еще и черевато всякими косяками. в общем этот вариант тоже не вариант.

Если все методы перепробованы а результата нет - прочтите инструкцию. Вооружившись этой самой инструкцией мы начинаем хачить класс google.maps.Marker


google.maps.Marker.prototype.openInfoWindow = function(content){
	if (!(this.InfoWindow && this.InfoWindow.getContent() == content)){ 
		this.InfoWindow = new google.maps.InfoWindow({
			content: content
		});
	}
	this.InfoWindow.open(this.map, this);
}
	
var myMarkerManager = new MarkerManager(
	new google.maps.Map(document.getElementById("map3"), {
		zoom: 5,
		center: new google.maps.LatLng(50, 27),
		mapTypeId: google.maps.MapTypeId.HYBRID
	})
);

myMarkerManager.createMarker(new google.maps.LatLng(50.440951, 30.527181));
myMarkerManager.createMarker(new google.maps.LatLng(49.836944, 24.005000));
	
for (var i in myMarkerManager.markers){
	google.maps.event.addListener(myMarkerManager.markers[i], "click", function(e){
		myMarkerManager.map.setCenter(this.getPosition());
		this.openInfoWindow(this.getPosition().toString());
	});
}

Вот так все легко и просто :)

Комментирование отключено.