Google Maps API v3 ImageMapType


I'm following the Google Maps API v3 ImageMapType example here: <a href="https://developers.google.com/maps/documentation/javascript/examples/maptype-image" rel="nofollow">https://developers.google.com/maps/documentation/javascript/examples/maptype-image</a>

But, I don't have a clear understanding from the documentation how the tiles/zoom work. For now, I'm just trying to get it to work with 0 zoom. Once I tackle that, then I can figure out the zoom piece.

My image is 2000px X 2000px. I've sliced it up into 8 tiles by 8 tiles at 250px X 250px per tile.

I am doing console.log on getTileUrl. I was expecting to see all 64 of my tiles loaded from 0-0.png to 7-7.png But, I'm seeing 0-0.png attempt to load nine times.

I've created this <a href="http://jsfiddle.net/2N2sy/1/" rel="nofollow">http://jsfiddle.net/2N2sy/1/</a> (code below) to simulate my code.

Help unraveling the tiles/zoom would be greatly appreciated!

function getNormalizedCoord(coord, zoom) { var y = coord.y; var x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc var tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = (x % tileRange + tileRange) % tileRange; } return { x: x, y: y }; } var map; function initMaps() { $.getScript("http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox.js").done(function (script, textStatus) { var customMapTypeOptions = { getTileUrl: function (coord, zoom) { var normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return null; } var bound = Math.pow(2, zoom); console.log('http://img.photobucket.com/albums/v229/s15199d/ + normalizedCoord.x + '-' + (bound - normalizedCoord.y - 1) + '.png'); return 'http://img.photobucket.com/albums/v229/s15199d/ + normalizedCoord.x + '-' + (bound - normalizedCoord.y - 1) + '.png'; }, tileSize: new google.maps.Size(250, 250), maxZoom: 0, minZoom: 0, radius: 1738000, name: 'custom map' }; var customMapType = new google.maps.ImageMapType(customMapTypeOptions); var latlng = new google.maps.LatLng(0, 0), // center point mapOptions = { zoom: 0, center: latlng, draggable: true, scrollwheel: false, mapTypeControl: false, panControl: false, scaleControl: false, zoomControl: true, zoomControlOptions: { style: google.maps.ZoomControlStyle.LARGE, position: google.maps.ControlPosition.RIGHT_TOP }, streetViewControl: false, streetViewControlOptions: { position: google.maps.ControlPosition.RIGHT_TOP }, mapTypeControlOptions: { mapTypeIds: ['custom map'] } }; map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions); map.mapTypes.set('custom map', customMapType); map.setMapTypeId('custom map'); }); } $(function () { if (window.google && google.maps) { //alert("Map script is already loaded. Initializing"); initMaps(); } else { //alert("Lazy loading Google map..."); lazyLoadGoogleMap(); } }); function lazyLoadGoogleMap() { $.getScript("http://maps.google.com/maps/api/js?sensor=true&callback=initMaps") .done(function (script, textStatus) { //alert("Google map script loaded successfully"); }) .fail(function (jqxhr, settings, ex) { //alert("Could not load Google Map script: " + jqxhr); }); }


You're telling it to do so. If you look at your getNormalizedCoord function, you'll see that you're expecting a tileRange of 1. Then you check the x coordinate against the tileRange. Since that is 1, all values above or equal to 1 will be normalized down (only one option below 1, and that's zero).

If you follow the logic it does this:

<ol><li>Set x to 1 % 1 (that's 0)</li> <li>Set x to 0 + 1 (that's 1)</li> <li>Set x to 1 % 1 (that's 0 again)</li> </ol>

So at the zoom level you chose, the function is rightfully always returning 0. If you try a bigger zoom level, you will notice it does load your other tiles.

One of the mistakes you're making (I think), is that you got the zoom levels backwards: 0 is fully zoomed out and 9 is fully zoomed in. The example you used is based around a single overview image for zoom level 0 and smaller chunks on every step further zoomed in. Therefor you should be expecting one tile (0, 0) being loaded at zoom level 0. To load all of the 64 tiles, you will need a higher zoom level. The multiple calls to the same url is simply the API using its cache to fill in the tiles. If you look at the example, it is just repeating the same image along the X axis there as well.

<hr />

To recap what is discussed in the comments, the zoom level at which the normalization function used will load all tiles is 3. Right now, the tiles are being loaded with the y axis flipped. To fix this, you will have to change the following line in getTileUrl from (bound - normalizedCoord.y - 1) to (normalizedCoord.y - 1).

The whole idea of zooming in Google Maps is based on loading images with a higher level of detail for the same tile grid, giving the idea of being zoomed in further. To achieve this, you will therefor need to produce extra images.

If you don't have / don't need images with extra detail, you can either opt to fix the zoom level at 3 (nobody will ever notice anyway) and deploy like that or clean up (perhaps even remove) the normalization code to your needs. Currently the function is in charge of repeating the same images across the X axis, while not repeating at all on the Y axis. For the repetition on the X axis it looks at the zoom level to determine how many tiles should be loaded before wrapping around to 0 again.

From the question, I can't deduce if you need the wrapping or just picked that up from the example. Nor can I tell if you have more images or not. Therefor I can't hand you any ready-to-use code, because I don't have any specifications to work with.

<hr />

If you don't need the wrapping, make it handle the X coordinates like it does the Y coordinates:

function getNormalizedCoord(coord, zoom) { var y = coord.y; var x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc var tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // don't repeat across x-axis (horizontally) if (x < 0 || x >= tileRange) { return null; } return { x: x, y: y }; }

(Note that those two if statements can be collapsed into one, I just wanted to keep it easy to notice what changes influence this behavior)


You seem to be having a zoom level issue. By changing the minZoom and maxZoom in the customMapTypeOptions object to '0'and '2' respectively and setting the starting zoom to '1' in the mapOptions object, the application called images '0-1', '0-0','1-1', and '1-0' on load.

After I investigated the Google example you listed, I noticed that when you url for their map tile include the zoom level in the url. Here is an example of the one tile called at a zoom level of 0:

<a href="http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/0/0/0.jpg" rel="nofollow">http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/0/0/0.jpg</a>

Note the last three numbers, ".../0/0/0.jpg". After I zoomed in to zoom level 1, the first two map tiles called was have the urls:

<a href="http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/1/0/1.jpg" rel="nofollow">http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/1/0/1.jpg</a><br /><a href="http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/1/0/0.jpg" rel="nofollow">http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/1/0/0.jpg</a>

Notice how the last three number have changed. I believe the first number is the zoom level the image should be displayed at followed by the x & y of the images position in the map tile grid.

According to a comment in the example code:

// tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc var tileRange = 1 << zoom;

you will use a single image file for zoom level 0 (which is why 0-0 is your only image loaded), 2 images for zoom level 1, 4 images for zoom level 2, and so on.


  • Stop windows from showing up as 'tasks' from task manager WPF c#
  • Xcode 5.1 compiler errors after adding a framework
  • Getting Uncaught TypeError: Cannot read property 'length' of undefined on leafletjs
  • Internet Explorer 11 renders page strangely until reszing?
  • Tiles generated from mbutil does not render using leafletjs
  • Links not displaying links
  • MySQL ORDER BY x-y/x ASC
  • no such table: tablename in sqlite even after initialization
  • How do I restrict a Google Geocode query to multiple countries?
  • Where can I find a sample for Pcap for Diameter protocol (WireShark)? [closed]
  • Regex to capture float from string (and replace with the captured float)
  • Union of circles and polygon in leaflet
  • Can HoughCircles function in opencv detect circles within a circle?
  • Adding Conditionals & Functions to a Math Parser
  • How do I get narrow width and a large height on a RadioButtons widget, and still have round radio bu
  • “tkinter.TclError: invalid command name” error after calling root.destroy()
  • Get photos from a Google+ album, in JSON format
  • Round number to nearest “nth” based on first non zero
  • NSTextField margin and padding? (Swift)
  • stacked chart with ZingChart
  • Javascript - Infinite scroll JSON array?
  • What causes erratic GPS estimates during certain time intervals?
  • Android: Button background XML sometimes loses alpha when setting color filter
  • Facebook Graph API: Permissions to Friends Photos
  • Chart js - Draw center of each bubbles of a bubble chart
  • Can I override some attribute of drawable shape?
  • Setting inner div opacity to 1, but not effected
  • Dropdown menu items hides behind main menu in bootstrap customized navigation bar
  • How to show a badges count of ToolBarItem Icon in Xamarin Forms
  • Cryptic error when trying to run POW
  • Calling C function from lua
  • Python PIL to extract number from image
  • Outputting SharePoint Hyperlink Column as URL
  • C# fibonacci function returning errors
  • Disable Kendo Autocomplete
  • TextToSpeech.setEngineByPackageName() triggers NullPointerException
  • How to view images from protected folder with php?
  • D3 get axis values on zoom event
  • Time complexity of a program which involves multiple variables
  • Buffer size for converting unsigned long to string