How to convert from (x, y) screen coordinates to LatLng (Google Maps)

Check out the easy solution(v3):

map.getProjection().fromLatLngToPoint(marker.position);

https://developers.google.com/maps/documentation/javascript/3.exp/reference#Projection


After some research and some fails I came up with a solution. Following the documentation from this link I found out that the google Points are computed in the range of x:[0-256], y:[0-256] (a tile being 256x256 pixels) and the (0,0) point being the leftmost point of the map (check the link for more information).

However, my approach is as it follows:

  • having the x and y coordinates (which are coordinates on the screen - on the map) I computed the percentage where the x and y coordinates were placed in response to the div containing the map (in my case, the hole window)

  • computed the NortEast and SouthWest LatLng bounds of the (visible) map

  • converted the bounds in google Points

  • computed the new lat and lng, in google points, with the help of the boundaries and percentage of x and y

  • converted back to lat lng

      // retrieve the lat lng for the far extremities of the (visible) map
      var latLngBounds = map.getBounds();
      var neBound = latLngBounds.getNorthEast();
      var swBound = latLngBounds.getSouthWest();
    
      // convert the bounds in pixels
      var neBoundInPx = map.getProjection().fromLatLngToPoint(neBound);
      var swBoundInPx = map.getProjection().fromLatLngToPoint(swBound);
    
      // compute the percent of x and y coordinates related to the div containing the map; in my case the screen
      var procX = x/window.innerWidth;
      var procY = y/window.innerHeight;
    
      // compute new coordinates in pixels for lat and lng;
      // for lng : subtract from the right edge of the container the left edge, 
      // multiply it by the percentage where the x coordinate was on the screen
      // related to the container in which the map is placed and add back the left boundary
      // you should now have the Lng coordinate in pixels
      // do the same for lat
      var newLngInPx = (neBoundInPx.x - swBoundInPx.x) * procX + swBoundInPx.x;
      var newLatInPx = (swBoundInPx.y - neBoundInPx.y) * procY + neBoundInPx.y;
    
      // convert from google point in lat lng and have fun :)
      var newLatLng = map.getProjection().fromPointToLatLng(new google.maps.Point(newLngInPx, newLatInPx));
    

Hope this solution will help someone out also! :)


function latLng2Point(latLng, map) {
  var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
  var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
  var scale = Math.pow(2, map.getZoom());
  var worldPoint = map.getProjection().fromLatLngToPoint(latLng);
  return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
}

function point2LatLng(point, map) {
  var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
  var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
  var scale = Math.pow(2, map.getZoom());
  var worldPoint = new google.maps.Point(point.x / scale + bottomLeft.x, point.y / scale + topRight.y);
  return map.getProjection().fromPointToLatLng(worldPoint);
}

Adding an alternate solution based on an existing SO question code, despite the original poster found a solution.

Based on this answer we can find the necessary part for Google Maps API v3 to do the conversion. It focuses on repositioning the center of the map. Modifying it to read the position from the screen requires calculating the difference of the screen coordinates from the screen center.

I renamed the function for the sake of this example to pixelOffsetToLatLng and changed it to return the position (other than that, not too different from the code in the answer above):

function pixelOffsetToLatLng(offsetx,offsety) {
  var latlng = map.getCenter();
  var scale = Math.pow(2, map.getZoom());
  var nw = new google.maps.LatLng(
      map.getBounds().getNorthEast().lat(),
      map.getBounds().getSouthWest().lng()
  );

  var worldCoordinateCenter = map.getProjection().fromLatLngToPoint(latlng);
  var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0);

  var worldCoordinateNewCenter = new google.maps.Point(
      worldCoordinateCenter.x - pixelOffset.x,
      worldCoordinateCenter.y + pixelOffset.y
  );

  var latLngPosition = map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);

  return latLngPosition;
}

To call it, you need to pass the X and Y coordinates that you have on the web page element:

  var x = mapElement.offsetWidth / 2 - screenPositionX;
  var y = screenPositionY - mapElement.offsetHeight / 2;
  pixelOffsetToLatLng(x,y);

For the leap.js side, you just need to map the leap.js coordinates to the web page, either by experimenting or by using the screen-position plugin that works like this:

var $handCursor = $('#hand-cursor'); // using jQuery here, not mandatory though

Leap.loop(function(frame) {
  if (frame.hands.length > 0) {
    var hand = frame.hands[0];
    $handCursor.css({
      left: hand.screenPosition()[0] + 'px',
      top: hand.screenPosition()[1] + 'px'
    });

    if ((hand.grabStrength >= 0.6 && lastGrabStrength < 0.6)) {
      var x = mapElement.offsetWidth / 2 - hand.screenPosition()[0];
      var y = hand.screenPosition()[1] - mapElement.offsetHeight / 2;
      map.setCenter(pixelOffsetToLatLng(x, y));
    }
  }
}).use('screenPosition', {
  scale: 0.5
});

Here's a Codepen example on how to read the coordinates using Leap.js in 2D environment: http://codepen.io/raimo/pen/pKIko

You can center the Google Maps view using your mouse or by grabbing your hand over the Leap Motion Controller (see the red "cursor" for visual cue).