Tuesday 22 December 2009

Updating Google Map Marker's z-index

Lately I've been working on a web application that uses Google's Maps API. It's been an interesting and engaging project.

One of the limitations of the current Maps API is that the z-index of a marker cannot be changed after it has been created. The client requested that the selected marker "popped to the front" as some markers obscured others in certain map areas depending on zoom and closeness of coordinates. This was a reasonable request and would enhance the UI, but was not so easy to implement.


Mike Williams gives a good introduction to this issue and details of how to set the z-index of the marker when it is created with addOverlay() in his Google Maps API Tutorial. Having read this, I attempted to re-create each marker when it was clicked and keep track of the top most z-index. I had some success but had unpredictable z-index results and it was definitely an inefficient way to produce the desired effect.

I decided to browse the DOM and see if I could find a better way to do this. I found a guide to Undocumented Google API features which seems to be mostly out of date, but contained the very important details of how to calculate a Marker's default z-index:

Use marker.setZIndex(Math.round(marker.getLatitude()*-100000)) to get a moved marker to overlap correctly.

Even though setZIndex() and getLatitude() are not valid methods in the current API, it's easy to understand the calculation.

In my application I was already using a unique icon for each marker so that they displayed sequential letters (A,B,C...) and had added an index property to the marker object. I was able to leverage this with a bit of jQuery magic to find each icon in the DOM and alter the CSS z-index value. Since the default z-index is something like -108619296, I created a function to toggle the z-index between normal and front positions by multiplying it by -1.

icon = $("#mapbox div div div img[src='/images/markers/"+marker.index+".png']");
zidx = icon.css('z-index');
icon.css('z-index',zidx*-1);


Just to make sure that no other marker was still in the top position, I looped through my array of markers and reset the z-index with this function.

function reset_zorder(marker) {
$("#mapbox div div div img[src='/images/markers/"+marker.index+".png']").css('z-index',Math.round(marker.getPoint().lat()*-100000));
}


Obviously none of this is a copy+paste solution. but it should give anybody needing to manipulate Google Maps MAP Marker z-index a good example to work from.

Thursday 17 December 2009

"X-Moz: prefetch" and skewed page-hits

Earlier today I installed a WordPress plugin recommend for tracking the popularity of posts. The plugin is unsurprisingly named "Recently Popular". After installing the plugin I ran some quick tests and found that I was getting extra hits recorded. I spent a bit of time back-tracking to find the source and after systematically disabling all other plugins and page elements found that it was firing in wp_head() in the page header.

After some more digging, I noticed that the extra hit was for the chronologically next published post and that the problem occurred in both WordPress and WordPressMU. This wasn't making a lot of sense so I decided to try a different browser - more of a sanity test than anything. That's when I found it didn't occur in Chrome, or Opera - just Firefox 3.5.6 that I'd upgraded to a few hours earlier.

I fired up the Live HTTP Headers add-on and checked out the requests Firefox was making. It was definitely making both post requests. I took a closer look at the second request and noticed the extra header "X-Moz: prefetch".

A quick search for X-Moz: prefetch turns up Mozilla's Link prefetching FAQ which gives a good description of what is happening and why. WordPress creates a tag similar to the following when wp_head() is executed:

<link rel='next' title='The Next Post' href='http://your_domain/year/month/day/the_next_post/' />

I am unaware of anyway to disable the prefetch hints. You could edit your header.php and remove the wp_head() statement, but many plugins rely on the execution of this function so results could be unexpected and undesirable. The issue for me was not that the hint was published but that the prefetch hits were being counted as real post requests, as well as the actual request when I clicked through a second or two later. This would seriously skew the perceived popularity of posts.

My solution was to ensure that the Recently Popular plugin ignored post requests that passed the "X-Moz: prefetch" header. Depending on your server configuration, the method of checking the header exists may differ - apache_request_headers() (alias getallheaders()) is only supported when PHP is installed as an Apache module. Most servers should support checking for $_SERVER['HTTP_X_MOZ'].

I wonder how many other people will wonder why their page hit stats have mysteriously increased without any increase in ad impressions, etc.

I will contact the plugin author to suggest an update once I've published this post.