Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Maps API V3 fromDivPixelToLatLng not consistent

I need to place a marker at a fixed pixel location within the map's div. To instantiate a marker, you need a LatLng. I understand that fromDivPixelToLatLng() is the way to convert from pixel co-ordinates to a LatLng, but I can't get it to behave consistently.

I have posted a simple example of my problem at http://www.pinksy.co.uk/newsquare/overlaytest.html. Click on the map to place a marker at 200px/200px. Drag the map around and click again. I was expecting a marker to be placed at 200px/200px every time, but this is not the case.

First I set up the map as usual, in a 600px by 300px div:

var london = new google.maps.LatLng(51.501904,-0.130463);
var mapOptions = {
    zoom: 15,
    center: london,
    mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

Then I create an overlay:

var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);

To test fromDivPixelToLatLng(), I create a click event on the map, which attempts to place a marker at pixel location 200px/200px. Regardless of where you drag the map, I was expecting the marker to always be placed at 200px/200px:

google.maps.event.addListener(map, 'click', function(event) {

    var pixelLatLng = overlay.getProjection().fromDivPixelToLatLng(new google.maps.Point(200,200));

    var marker = new google.maps.Marker({
        position: pixelLatLng,
        map: map
    });
});

However, drag the map around, and you will see that the marker is not always placed at 200px/200px. Any ideas?

Thanks!

like image 370
pinksy Avatar asked Oct 29 '11 09:10

pinksy


2 Answers

After experimentation, I have found that fromContainerPixelToLatLng() is what I'm looking for. For the benefit of others, I have posted an example at http://www.pinksy.co.uk/newsquare/overlaytest2.html.

(For the record, I'm still unsure why fromDivPixelToLatLng behaves the way it does, but never mind!)

like image 127
pinksy Avatar answered Nov 01 '22 02:11

pinksy


Check the demo under: http://jsbin.com/otidih/51 for some more experiments on this. To get the logging start the console - most things are logged there.

Detailed explanation from this groups post. A shorter version below:

The ContainerPixel is calculated relative to your map container. If you pan the map, then the ContainerPixel of LatLngs changes. The ContainerPixel of things that don't move with the map (float) doesn't change. For example, the ContainerPixel of the mapCenter stays the same if you don't resize the map:

overlay.getProjection().fromLatLngToContainerPixel(map.getCenter())

The DivPixel is calculated relative to a huge Div that holds the entire tilespace for the world at the current zoom level.

overlay.getProjection().fromLatLngToDivPixel(point)

If you do not change the zoom level and move (pan) the map, then the DivPixel of anything that moves with the map will stay the same. For example the DivPixel of a given city on a map will stay the same, even if you move the map. It will only change when you change the zoom level or cross the international dateline.

Please note that the actual reference point used for calculating the DivPixel gets reset whenever the map zooms, so the same LatLng can have different DivPixel values even when you come back to the same zoom level.

Also to be considered is the Point value returned from

map.getProjection().fromLatLngToPoint()

which is well explained in the API Reference It translates from the LatLng cylinder to the big point plane which always stays the same (no matter which zoom level). Given LatLngs will always map to the same Point.

The (0,0) point is the (85.0511287798066,-180) LatLng - where to Google Map cuts of (if you want to know why , read about the Mercator projection)

like image 40
kaskader Avatar answered Nov 01 '22 01:11

kaskader