Nowadays many sites uses embedded map from Google for purposes like showing object location, drive-in way or more complex stuff. Recent Google Maps Version3 (V3) API becomes very powerful, but remained very clear and easy to use.
While developing site for real estate company I faced with necessity to display fancy, complex overlays on top of the map when user clicks on the marker.
There are some standard ways of showing so called info-windows. The problem is that it is not possible put complex formatting there or catch mouse clicks events.
To solve it I have to to dig into API internals and recent version V3 has some surprises here.
The easiest way to show custom overlay is to determine coordinates of clicked marker and position DIV over the map to right position. Sounds easy.
I found some code that should do the trick, but it does not work. It was designed for V2 API.
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
var proj = overlay.getProjection();
var pos = marker.getPosition();
var p = proj.fromLatLngToContainerPixel(pos);
After some API digging and googling, I found out that there are no documented ways of determiniting pixel position of GoogleMap point. Thats sad.
Here is the semi-hacked code that actually does the trick
var topRight=gmap.getProjection().fromLatLngToPoint(gmap.getBounds().getNorthEast ());
var bottomLeft=gmap.getProjection().fromLatLngToPoint(gmap.getBounds().getSouthWest());
var scale=Math.pow(2,gmap.getZoom());
var worldPoint=gmap.getProjection().fromLatLngToPoint(marker.getPosition());
var point = new google.maps.Point((worldPoint.x-bottomLeft.x)*scale,(worldPoint.y-topRight.y)*scale);
Where
Below you can find working example, I made overlay window simple, but since it is DIV there is no limits of pushing it.
document.write('<div id="overlay" style="z-index: 1000; position: absolute;display:none;width:200px;height:100px;background-color:white;border:1px solid grey;padding:10px;">ANY CUSTOM FANCY OVERLAY HERE<br/><br/><br/><br/><br/><br/><a href="#" id="close">close</a></div>');
document.write('<div id="map" style="width:500px; height:500px;"></div>');
// Get center
var map_center = new google.maps.LatLng(50.1700235000, 4.7319823000);
// Load google map
var map = new google.maps.Map( document.getElementById("map"), {
zoom: 3,
center: map_center,
mapTypeId: google.maps.MapTypeId.HYBRID,
panControl: false,
streetViewControl: false,
mapTypeControl: false
});
var pos;
var marker_list = [];
for(var i = 0 ; i < 10 ; i++) {
pos = new google.maps.LatLng(Math.floor(Math.random()*100), Math.floor(Math.random()*50));
marker_list.push( new google.maps.Marker({
position: pos,
map: map,
title: 'Title',
icon: '/other/gmap/marker.gif'
}));
var storyClick = new Function("event", "markerClick("+i+");");
google.maps.event.addListener(marker_list[i], 'click', storyClick);
}
function markerClick(num) {
var topRight=map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
var bottomLeft=map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
var scale=Math.pow(2,map.getZoom());
var worldPoint=map.getProjection().fromLatLngToPoint(marker_list[num].getPosition());
var point = new google.maps.Point((worldPoint.x-bottomLeft.x)*scale,(worldPoint.y-topRight.y)*scale);
jQuery("#overlay").css({
left:(jQuery("#map").position().left + point.x - jQuery("#overlay").width()/2),
top:(jQuery("#map").position().top + point.y - jQuery("#overlay").height() - 50)
});
jQuery("#overlay").show();
}
jQuery('#close').click(function(e) {
e.preventDefault();
jQuery("#overlay").hide();
});
google.maps.event.addListener(map, 'center_changed', function() {
jQuery("#overlay").hide();
});
google.maps.event.addListener(map, 'zoom_changed', function() {
jQuery("#overlay").hide();
});