I am implementing an application using Google Maps and Leap Motion and what I want right now, and I am a bit stuck, is a way to convert (x, y) screen coordinates into a Goog
You need to know (x0,y0)
of the center of your map element, (lat0,lng0)
of the map center, and the ratio r
of degrees per pixel, corresponding to the Map's Zoom level. Then
lat(y) = lat0 + r(y-y0)
lng(x) = lng0 + r(x-x0)
Note that this is a simplified linearized model, working for maps showing small areas.
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).
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! :)
Check out the easy solution(v3):
map.getProjection().fromLatLngToPoint(marker.position);
https://developers.google.com/maps/documentation/javascript/3.exp/reference#Projection
Apparently, Google has decided to make life easier.
Here is the built-in solution:
Point point = googleMap.getProjection.toScreenLocation(latLng)
LatLng latlng = googleMap.getProjection.fromScreenLocation(point)
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);
}