DexterTechWith

Monday, May 22, 2006

Prototype Number Extension doesn't mix well with GMap2!

Ok so here's my starter for 10...


It's no doubt about it, prototype javascript library makes coding javascript applications much much easier. However, I've notice a few people grumbling about how it extends base Javascript types (like Object, Number, Array etc.). It's not been a problem for me until now. I've recently been updating the Google mapping code for a project I'm working on so it works with the v2 release of the Google Maps API. There's some pretty major changes (like proper Lat/Long points with the ordinals the right way round!) One thing I hadn't spotted though was the fact that the new .setCenter() method on the GMap2 class is "type safe" - or should I say "type fussy"(?). So my code, that reads a set of query string values (lattude, longitude, zoom level and a few others). It looks a bit like this:

http://www.mymappingsite.co.uk/map.aspx?lat=52.921&lng=-1.473&z=11

So this should send the map to: Latitude of 52.921, Longitude of -1.473 and Zoom level 11 (on the new scale).

That worked fine before, but now send the map off to zoom level 0 (now the furthest away).

To get the querystring parameters I'm using some code a bit like this:



// Create an object to hold the parameters
var params = new Object();
...
// Use the prototype library method toQueryParams() to extract the values
// into the holder object
params = location.search.toQueryParams();
...
// Read in intial parameters
if (params.lat && params.lng) {
initialCentre = new GLatLng(params.lat.valueOf(), params.lng.valueOf());
}
if (params.z != null) initialZoomLevel = params.z.valueOf();
...
// Create the map (GMap2 object) and set it's centre and zoom level
myMap = new GMap2("myMapDiv");
myMap.setCenter(initialCentre, initialZoomLevel);


What was happening (as I eventually worked out grrrrr...) was that the setCenter() method checks the type of the zoom level to make sure it's a primitive number type. In our case, because prototype uses it's Object.extend() method to extend the Javascript Number base class, when the typeof check is done, it returns "object" and not "number" as required - therefore it rejects my value and goes for 0 instead.

Now, how to fix it? Well you can't "cast" objects at all in JavaScript, let alone cast this one back to a primitive number - as I dicovered. However you can use the valueOf() method to extract out the original primitive value of the object - i.e. in this case a "number".

So I changed the last bit to something more like this:


initialZoomLevel = new Number(zoomLevel);
myMap = new GMap2("myMapDiv");
myMap.setCenter(initialCentre, initial.valueOf());

Easy - but not obvious, I thought.

I wonder if this a new strategy by those clever people at Google maps - type safe paramaters anyone?