Recently Yahoo!! released new map tiles … ah heck, actually it was a couple of months ago, I just suck at writing blog posts … anyway, here’s their post from last December: Yahoo! Maps – New International Coverage which goes on to say …
“We’ve added detailed coverage to 45 new countries, with new data in a further 30 countries, to make it easier for you to navigate to exotic locales as you plan for your winter travel.”
I’m as keen as the next person to have 45 new countries, so I bumped our version of the maps API used over here at Flickr to make use of the new tiles.
Which gives us more to work with for many bits of Albania, Andorra, Argentina, Australia, Austria, Bahrain, Belarus, Belgium, Bosnia & Herzegovina, Botswana, Brazil, Bulgaria, Canada, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Gibraltar, Greece, Hong Kong, Hungary, Iceland, India, Indonesia, Ireland, Italy, Kuwait, Latvia, Lesotho, Liechtenstein, Lithuania, Luxembourg, Macau-China, Macedonia, Malaysia, Malta, Mexico, Moldova, Monaco, Montenegro, Namibia, Netherlands, New Zealand, Norway, Oman, Philippines, Poland, Portugal, Qatar, Romania, Russia, San Marino, Saudi Arabia, Serbia, Singapore, Slovakia, Slovenia, South Africa, South Korea, Spain, Swaziland, Sweden, Switzerland, Taiwan, Thailand, Turkey, US, United Arab Emirates, United Kingdom and [catch breath], Vietnam.
Often we’ll try to improve our coverage with the help of (the frankly awesome) OpenStreetMap (OSM) peeps, as previously mentioned in; Around the World and Back Again, Flickr [heart] Burning Man [heart] OpenStreetMap and More new map tiles.
With this roll out we’ve actually removed some OSM tiles. Mexico City, Rio de Janeiro, Sao Paulo are now covered in more detail by Yahoo! … here’s the tiles for Mexico City …
… which as you can see are pretty good.
But from OpenStreetMap we’ve added Accra, Algiers, Cairo, Harare, Kinshasa, Mogadishu and Nairobi, you can see the before and after for Nairobi below …
Before
After, with OSM Tiles
… which as you can see are also pretty good :)
Clearly we can’t spend forever swapping tiles in and out, well maybe we can, but at some point there’ll probably be a better way of managing this kind of thing.
In the meantime though, this being the code blog, and just for fun, here’s a little bit of what happens in the world of JavaScript.
Warning, some code ahead!
This check_map function is called each time you move, zoom or switch map views …
check_map: function(map_obj, parent_node) {
// Grab the focus, zoomlevel and maptype of the current view
var lat_lon = map_obj.getCenterLatLon();
var zl = map_obj.getZoomLevel();
var map_type = map_obj.getCurrentMapType();
Then we check the location against a list of places we want to load OSM tiles for, we could do this any number of ways, but pragmatically this just works (scroll the below code all the way to the right for the interesting bits, if you’re not reading this in an RSS feed) …
// Now see if we match any of these following tests to work out if we need to switch to osm or not.
// The meta-test is if we are in MAP mode.
var in_the_zone = false;
if (map_type == 'YAHOO_MAP') {
if (zl < 8 && lat_lon.Lat >= 39.8558502197 && lat_lon.Lat <= 40.0156097412 && lat_lon.Lon >= 116.2662734985 && lat_lon.Lon <= 116.4829177856) in_the_zone = true; // Beijing
if (zl < 7 && lat_lon.Lat >= 40.735551 && lat_lon.Lat <= 40.807533 && lat_lon.Lon >= -119.272041 && lat_lon.Lon <= -119.163379) in_the_zone = true; // Black Rock City, 2008
if (zl < 9 && lat_lon.Lat >= 35.46290704974905 && lat_lon.Lat <= 36.02799998329552 && lat_lon.Lon >= 139.21875 && lat_lon.Lon <= 140.27069091796875) in_the_zone = true; // Tokyo
if (zl < 8 && lat_lon.Lat >= -34.6944313049 && lat_lon.Lat <= -34.4146499634 && lat_lon.Lon >= -58.6389389038 && lat_lon.Lon <= -58.2992210388) in_the_zone = true; // Buenos Aires
// Yahoo Better if (zl < 8 && lat_lon.Lat >= 18.9466495514 && lat_lon.Lat <= 19.6985702515 && lat_lon.Lon >= -99.5071487427 && lat_lon.Lon <= -98.7429122925) in_the_zone = true; // Mexico City
// Yahoo Better if (zl < 8 && lat_lon.Lat >= -23.0837802887 && lat_lon.Lat <= -22.7662200928 && lat_lon.Lon >= -43.7946395874 && lat_lon.Lon <= -43.1328392029) in_the_zone = true; // Rio de Janeiro
// Yahoo Better if (zl < 8 && lat_lon.Lat >= -24.0083808899 && lat_lon.Lat <= -23.3576107025 && lat_lon.Lon >= -46.8253898621 && lat_lon.Lon <= -46.3648300171) in_the_zone = true; // Sao Paulo
if (zl < 8 && lat_lon.Lat >= -35.2210502625 && lat_lon.Lat <= -34.6507987976 && lat_lon.Lon >= 138.4653778076 && lat_lon.Lon <= 138.7634735107) in_the_zone = true; // Adelaide
if (zl < 8 && lat_lon.Lat >= -34.1896095276 && lat_lon.Lat <= -33.5781402588 && lat_lon.Lon >= 150.5171661377 && lat_lon.Lon <= 151.3425750732) in_the_zone = true; // Sydney
if (zl < 8 && lat_lon.Lat >= -27.8130893707 && lat_lon.Lat <= -27.0251598358 && lat_lon.Lon >= 152.6393127441 && lat_lon.Lon <= 153.3230438232) in_the_zone = true; // Brisbane
if (zl < 8 && lat_lon.Lat >= -35.4803314209 && lat_lon.Lat <= -35.1245193481 && lat_lon.Lon >= 148.9959259033 && lat_lon.Lon <= 149.2332458496) in_the_zone = true; // Canberra
if (zl < 8 && lat_lon.Lat >= -38.4112510681 && lat_lon.Lat <= -37.5401115417 && lat_lon.Lon >= 144.5532073975 && lat_lon.Lon <= 145.5077362061) in_the_zone = true; // Melbourne
if (zl < 8 && lat_lon.Lat >= 33.2156982422 && lat_lon.Lat <= 33.4300994873 && lat_lon.Lon >= 44.2592010498 && lat_lon.Lon <= 44.5364112854) in_the_zone = true; // baghdad
if (zl < 8 && lat_lon.Lat >= 34.4611015320 && lat_lon.Lat <= 34.5925598145 && lat_lon.Lon >= 69.0997009277 && lat_lon.Lon <= 69.2699813843) in_the_zone = true; // kabul
if (zl < 10 && lat_lon.Lat >= -4.3634901047 && lat_lon.Lat <= -4.3009300232 && lat_lon.Lon >= 15.2374696732 && lat_lon.Lon <= 15.3460502625) in_the_zone = true; // kinshasa
if (zl < 10 && lat_lon.Lat >= 2.0093801022 && lat_lon.Lat <= 2.0614199638 && lat_lon.Lon >= 45.3139114380 && lat_lon.Lon <= 45.3669013977) in_the_zone = true; // mogadishu
if (zl < 10 && lat_lon.Lat >= -17.8511505127 && lat_lon.Lat <= -17.7955493927 && lat_lon.Lon >= 31.0210304260 && lat_lon.Lon <= 31.0794296265) in_the_zone = true; // harare
if (zl < 10 && lat_lon.Lat >= -1.3165600300 && lat_lon.Lat <= -1.2379800081 && lat_lon.Lon >= 36.7483406067 && lat_lon.Lon <= 36.8735618591) in_the_zone = true; // nairobi
if (zl < 10 && lat_lon.Lat >= 5.5237197876 && lat_lon.Lat <= 5.5998301506 && lat_lon.Lon >= -0.2535800040 && lat_lon.Lon <= -0.1586299986) in_the_zone = true; // accra
if (zl < 10 && lat_lon.Lat >= 30.0068798065 && lat_lon.Lat <= 30.1119003296 && lat_lon.Lon >= 31.2149791718 && lat_lon.Lon <= 31.3111705780) in_the_zone = true; // cairo
if (zl < 10 && lat_lon.Lat >= 36.6997604370 && lat_lon.Lat <= 36.8181610107 && lat_lon.Lon >= 2.9909501076 && lat_lon.Lon <= 3.1476099491) in_the_zone = true; // algiers
}
If we found a match up there, then "in_the_zone" would have been set, in which case we'll check to see if were already showing osm tiles, if not we'll tell the YAHOO API to use our OSM tiles rather than the YAHOO ones ...
// ok, if we've match one of the above tests then we are in osm land ...
if (in_the_zone) {
// if we aren't already osming, then we need to switch the map tiles.
if (!this.osming) {
// Say that we are now osming
this.osming = true;
// Put the new tiles in
YMapConfig.tileReg=['/our_openstreetmap_tile_broker.xxx?t=m&','/our_openstreetmap_tile_broker.xxx?t=m&'];
// Tell the maps to clear out the tile cache and load in the new tiles.
map_obj._cleanTileCache();
map_obj._callTiles();
}
} else {
"YMapConfig.tileReg=" tells the map API to load tiles from us rather than the default ones, hint, you should set this to your own tile server ;)
"_cleanTileCache()" and "_callTiles()" are two undocumented functions (and therefor may break at some point) that allows you to force the map to load in new tiles. Otherwise the current view of the map will still show the Yahoo tiles and not use the new ones until you next pan the map around. Again there's probably a better way of doing this, but there's still a lot to be said for it-just-works!
The next bit runs if we're not "in the zone" to see if we need to turn the OSM tiles back off.
// otherwise we are not looking at an osm spot, in which case check to see if
// we *were* looking at one, and if so, turn it all off again
if (this.osming == true) {
// say that we are no longer osming
this.osming = false;
// turn the tiles back
YMapConfig.tileReg=this.oldTileReg;
// Tell the maps to clear out the tile cache and load in the new tiles.
map_obj._cleanTileCache();
map_obj._callTiles();
}
}
Which is roughly the opposite of turning them on. The only thing to note is that is the line ...
YMapConfig.tileReg=this.oldTileReg
... when we created the map I used this ...
// record what the old tiles were
this.oldTileReg=YMapConfig.tileReg;
... to record where YMapConfig thinks it aught to be loading tiles from when in map view (as opposed to hybrid or satellite view) so it can be reset when you need it.
And that's pretty much it. I've chopped out some distracting bits here or there to make it clearer and no-one else is likely to do it like this, but I find sharing to be cathartic (adjective not noun) :)
For a smidge of further reading this is a handy article from A List Apart: Take Control of Your Maps by Paul Smith.