0

I'm following the Google Maps API v3 ImageMapType example here: https://developers.google.com/maps/documentation/javascript/examples/maptype-image

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 http://jsfiddle.net/2N2sy/1/ (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);
    });
}
s15199d
  • 7,261
  • 11
  • 43
  • 70
  • @geocodezip thanks for fixing my jsfiddle! You only see 3x of the console.log due to the width of the jsfiddle output window. If you expand the window wider you'll see more iterations of the console.log – s15199d Aug 04 '14 at 14:34
  • Fiddle link is not correct. – MrUpsidown Aug 06 '14 at 11:20
  • Just by hit and trial. this fiddle link works: http://jsfiddle.net/2N2sy/1/ – SSA Aug 06 '14 at 12:41

2 Answers2

1

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:

  1. Set x to 1 % 1 (that's 0)
  2. Set x to 0 + 1 (that's 1)
  3. Set x to 1 % 1 (that's 0 again)

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.


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.


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)

gpgekko
  • 3,506
  • 3
  • 32
  • 35
  • 1
    @SSA The main problem is that nobody can really 'fix' the zooming, since we have no idea which images are available. Right now, it's just skipping parts of the overall image on different zoom levels. Since he chopped it up in 8x8, the normalization function would suggest that zoomlevel 3 is the one showing the full picture. However, because the images provided have their Y axis the wrong way around, it looks all funky. – gpgekko Aug 06 '14 at 13:22
  • @gpgekko thanks for that explanation. Increasing the default zoom and the min/max zoom does in fact load more of my tiles, but they're not in the correct order. I labeled my 64 titles from 0-0.png to 7-7.png where 0-0 is the top left corner and 7-7 is the bottom right corner. What am I missing to make my map work? – s15199d Aug 06 '14 at 13:24
  • @gpgekko are you saying my x/y are flipped in my title naming? – s15199d Aug 06 '14 at 13:25
  • @s15199d Actually, (0,0) is in the top left corner and (7,7) in the bottom right. However, the images do appear to be in upside down order. – gpgekko Aug 06 '14 at 13:28
  • @s15199d It's actually the example code that flips things around. Change the line with `(bound - normalizedCoord.y - 1)` to `(normalizedCoord.y - 1)` (also fix zoom at 3), it will look much better already (I'd post a fiddle, but it seems jsfiddle is down). – gpgekko Aug 06 '14 at 13:37
  • @s15199d With the tiles fixed, the only thing left is zoom. The thing I'm not sure about is what you want to show on the other zoom levels. You only have images for one level of detail, so what is there to zoom to? – gpgekko Aug 06 '14 at 13:40
  • Thanks @gpgekko! What should the tile second from the left row 0 be named? 0-1.png or 1-0.png ? As far as what I want the zoom to do...I want to start out at zoom-level 1 and give the user the ability to zoom in/out from there. I know I'll need 0, 1, 2, 3 folders for the zoom. With 64 slices in folder-3. How many slices should be folders 0, 1 and 2? – s15199d Aug 06 '14 at 13:57
  • @s15199d Google provides a labeled example grid in the [docs](https://developers.google.com/maps/documentation/javascript/maptypes#TileCoordinates). According to that it would be 1-0 (so X-Y). As far as the slices go, if you keep using the normalization function there is a comment describing the number of tiles in a row for each zoom level: `// 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc`. So it would be 1, 4, 16, 64 for zoom levels 0, 1, 2, 3. – gpgekko Aug 06 '14 at 14:02
  • I had the naming correct. You nailed it by removing the `bound -` @gpgekko you're so helpful thank you! I've almost go it. Hopefully this is my last question. If my image is 2000px X 2000px at zoom level 3. What should the dimensions of my image be at zoom levels 0, 1, 2? – s15199d Aug 06 '14 at 14:23
  • @s15199d It depends on the quality of the image, but it would already "work" by just keeping the current dimensions and cutting it in smaller pieces. It will allow people to take a closer look without artifacts from resizing. – gpgekko Aug 06 '14 at 14:45
  • @s15199d Eh, brain fart, that would of course not work because you wouldn't get the 250x250 tiles. Meaning that you have to do the math the other way around, so for zoom level zero you'd get 250x250, one would be (250x2) 500x500, two would be (250x4) 1000x1000. – gpgekko Aug 06 '14 at 14:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58810/discussion-between-s15199d-and-gpgekko). – s15199d Aug 06 '14 at 16:55
  • I may be pushing my luck here @gpgekko but do you know how to set it up to prevent my map from repeating horizontally? – s15199d Aug 06 '14 at 18:08
  • Never been sure if you get notifications of chat when offline, so here is a comment to point out I answered there and added a snippet to my answer here. Hope this will help you move forward. – gpgekko Aug 06 '14 at 19:58
0

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:

http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/0/0/0.jpg

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:

http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/1/0/1.jpg
http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/1/0/0.jpg

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.

Xion Dark
  • 3,374
  • 2
  • 15
  • 23