13 Aug 2005

how to make google maps fixed on a page (and working in safari)

[update: changed to include better workaround for safari google map redraw bug. ]

i've spent the whole morning (ok, i woke up at 12pm) trying to do something that is relatively simple. i've got an embedded google map which i want to embed in a page in a fixed position. that means when you scroll around the map stays in the same place. in CSS terms, this is called position:fixed. it turns out it isn't so simple. so maybe this page will help some people figure out what is going on (plus get around a safari redrawing bug):

so originally, our page is like this. you are able to scroll the map off the visible window. look at the source, even though the object is set to position:fixed, it doesn't stick. so something inside google's voodoo is changing the property.

1. let's change the visible property manually via javascript

after looking at the obfuscated google maps javascript, you'll find that the property you want is easily accessible as:

/* instantiate the google map */
var map = new GMap(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.centerAndZoom(new GPoint(-122.1419, 37.4419), 4);
/* change that to fixed */
map.div.style.position = 'fixed';

ah, that sort of works. the google map stays put when you scroll, but all the overlays on the map still scroll off, and the map is huge. this is actually a quite in interesting artifact. because you can see how google maps determines when to load in a new jpeg and how much extra images you are downloading when you set up a small window to view the map.

Gmaps Attempt1

to prevent all the extra stuff, you could add:

map.div.style.overflow = 'hidden';

2. so lets just put it in another container

so we just put the map into another container, easy!

<div id="mapholder">
<div id="map"></div>

so this is the solution, but if you try it under safari, you'll find a weird artifact when you scroll, the box itself stays put, but the images themselves seem to get scrolled off. after puzzling over this effect and trying all sorts of hacks, i figured out that it was a safari rendering bug.

Gmaps Attempt2

it seems that it is forgetting to redraw the contents of the map object. so we have to employ another hack. note that this works fine in firefox. not so good in opera, but i have no clue about how broken the opera css model is.

3. enter safari hack

the hack that we employ is the forced property update on scrolling to force safari to redraw everytime something is scrolled. so here is the javascript to do it:

window.onscroll = function() {
var fake = document.createElement("div");

i learnt this trick from looking at the ruby on rails source after googling for an mention of this bug. the ruby on rails code has a way to workaround the refresh problem, but it turns out you have to force a change to the dom to make safari reload everything inside the dom. so once that is done, you can be sure to have a google map in a fixed position for firefox and safari.

now we have to get it working under internet explorer .. grr ..

You can reply to me about this on Twitter: