Google Maps API V3 - Prevent ImageMapType from wrapping
Asked Answered
P

2

9

Please note:

This question is very similar to this one I found on stackoverflow.

Google Maps v3 ImageMapType Prevent Wrapping

However, the above question and answer did not work for my example / issue as I need to be able to view all of my image at any zoom level and more importantly i need the drawing tools to work correctly.


My Scenario:

I have a custom google map using ImageMapType, it also has the DrawingManager library and tools.

My issue:

At first glance all works nicely, however if you are to draw any markers or polygons and then pan the map the markers / polygons repeat or move across the area of map in view.

The same issue occurs when drawing large polygons on the map, as you are drawing the polygon, you will notice the line you are drawing will suddenly snap to the wrong side of your polygon.

My question:

How do I go about preventing the wrapping issues so that all of the markers do not move, or duplicate, and so that the drawing tools work without snapping to the other side of your polygon?


Online example:

http://jsbin.com/ecujug/5/edit#javascript,live

Video of the issues:

https://dl.dropbox.com/u/14037764/Development/stackoverflow/map-drawing/issue.html

Desired Effect:

http://www.maplib.net/map.php?id=1236

Pastelki answered 10/7, 2012 at 10:20 Comment(0)
T
13

Instead of 1-3 zoom levels, you should work in higher levels and choose another origin than (0,0) tile for images. What you need, is just simple Maths.As by default your map will be centered to LatLng(0,0) point(as you have mentioned in your MapOptions), the calculations will be performed around that point.

Theory

At any zoom, there are totally 2^zoom x 2^zoom tiles:

                           zoom
  _______________________ 2
  |_|_|_|_|_|_|_|_|_|_|_|
  |_|_|_|_|_|_|_|_|_|_|_|
  |_|_|_|_|_|_|_|_|_|_|_|          
  |_|_|_|_|_|_|_|_|_|_|_|          
  |_|_|_|_|_|_|_|_|_|_|_|
  |_|_|_|_|_|_|_|_|_|_|_|          
  |_|_|_|_|_|_|_|_|_|_|_|
  |_|_|_|_|_|_|_|_|_|_|_|
  |_|_|_|_|_|_|_|_|_|_|_|
  |_|_|_|_|_|_|_|_|_|_|_| 
  zoom
 2

As LatLng(0,0) is the central GPS point, the tile,which contains that point, should be the central tile of the tile-sheet:

                           zoom
  _______________________ 2
  |                     |
  |                     |
  |                     |           zoom
  |                     |          2         zoom-1
  |          o----------|-------*  ------ = 2
  |          |_|        |            2
  |          |          |
  |          |          |
  |          |          |
  |__________|__________| 
  zoom       |
 2           |  zoom-1
             * 2

So at any zoom level, the central tile has (2^(zoom-1), 2^(zoom-1)) coordinates. That tile will be the origin of the mappings.By subtracting origin coordinates from the current tile's coordinates, we will have such a coordinate-space as when we were working in 1-3 zoom levels and when the origin was the (0,0) tile.

Implementation

First of all, choose higher zoom levels,for example:

var MIN_ZOOM = 11,
    MAX_ZOOM = 13;

Mapping will be done by getNormalizedCoord function:

function getNormalizedCoord(coord, zoom) {
    //Amount of total tiles:
    // MIN_ZOOM    ->     1 tile
    // MIN_ZOOM+1  ->     2 tiles
    // MIN_ZOOM+2  ->     4 tiles
    var totalTiles = 1 << (zoom - MIN_ZOOM),
        y = coord.y,
        x = coord.x;
    var originx = 1 << (zoom-1),
        originy = 1 << (zoom-1);

    if(y < originx || y >= originx + totalTiles ||
        x < originx || x >= originx + totalTiles){
        return null;
    }

    x -= originx;
    y -= originy;

    return { x:x, y:y };
 }

And finally, the ImageMapOptions should be:

var siteMapOptions = {
    getTileUrl: function (coord, zoom) {
         var normalizedCoord = getNormalizedCoord(coord, zoom);
         if (normalizedCoord) {
             return 'https://edocstorage.blob.core.windows.net/siteimages/2fa9fc72-23a7-41ed-86a1-b83a3ba04790/_siteTiles/tile_' + 
                    (zoom-MIN_ZOOM) + '_' + 
                    normalizedCoord.x + '-' + 
                    normalizedCoord.y + '.png';
         } else {
             return 'content/tilecutter/empty.jpg';
         }
    },
    tileSize: new google.maps.Size(256, 256),
    maxZoom: MAX_ZOOM,
    minZoom: MIN_ZOOM,
    radius: 1738000,
    name: "Site Plan"
}; 

Live demo

Ticker answered 22/7, 2012 at 10:3 Comment(1)
excellent answer thank you very much! I'm sure this will be useful to many others.Pastelki
R
3

Seems quite obvious - google maps thinks this is a whole Earth, so that it's rounded. Why do you work on the minimal (Earth-wide) zoom level? Make google maps think this is just a small piece of land which doesn't take more than 1° and you are done.

Repay answered 10/7, 2012 at 17:39 Comment(13)
Thanks for the answer, however.. The whole idea is that the user can upload an image, and the view it in its entirety then zoom in if need bePastelki
@Blowsie, well, the "entirety" is up to you... you can zoom in as needed. You don't need to start at zoom 1. Just start at 13 for example :)Repay
this approach really wont work for my case and would generally be a bad UX overall thanks for the thought tho, +1Pastelki
@Blowsie, I don't get it, why it won't work? Smaller scale will work exactly the same way as larger scale, except for the wrapping problem. Exactly what you need.Repay
People will need to see the whole map at once. That's the criteria as per my question.Pastelki
@Blowsie, and how does my solution violate that?Repay
because you need to be able to add polygons to the entire image and view it in its entirety without the issues mentioned in my questionPastelki
@Blowsie, I don't see how my solution disables that. The only thing that changes is that you map the image to different geographical coordinates, so that google thinks it is just a small city instead of whole Earth. From users point of view, it looks exactly the same! Exactly the same picture all over the window.Repay
maybe I misunderstand your answer, please provide a sample.Pastelki
@Blowsie, providing a sample would be the same as making it all, quite laborious. I'll try be as clear as possible: place your photo over San Francisco, then zoom to San Francisco and that's it. Do you understand me now?Repay
I cant see in the documentation for ImapeMapType how you can specify a location to put the image. developers.google.com/maps/documentation/javascript/…Pastelki
maybe you got confused with ImapeMapType and overlay?Pastelki
@Blowsie, in the getTileUrl() callback you get coordinates and return image - so the logic of locating the image somewhere is hidden there.Repay

© 2022 - 2024 — McMap. All rights reserved.