I'm trying to get the pixel coordinates of an image overlay on click (right click/contextmenu) using the leaflet map library. Essentially when a user clicks on the image, I need to find the x,y or width,height of where the user clicked on the image.
Currently this is what I have.
// Using leaflet.js to pan and zoom a big image.
// See also: http://kempe.net/blog/2014/06/14/leaflet-pan-zoom-image.html
// create the slippy map
var map = L.map('image-map', {
minZoom: 1,
maxZoom: 4,
center: [0, 0],
zoom: 1,
crs: L.CRS.Simple,
});
// dimensions of the image
var w = 2000,
h = 1500,
url = 'http://kempe.net/images/newspaper-big.jpg';
// calculate the edges of the image, in coordinate space
var southWest = map.unproject([0, h], map.getMaxZoom() - 1);
var northEast = map.unproject([w, 0], map.getMaxZoom() - 1);
var bounds = new L.LatLngBounds(southWest, northEast);
// add the image overlay,
// so that it covers the entire map
L.imageOverlay(url, bounds).addTo(map);
// tell leaflet that the map is exactly as big as the image
map.setMaxBounds(bounds);
function onMapClick(e) {
//returns on right click events
console.log(e);
}
//Hadnel on right click functions TODO: MOVE THIS LATER
map.on('contextmenu', onMapClick);
Currently onMapClick(e) upon inspecting the returned events on click I see no evidence of all returned coordinates any where near to the x,y or width and height of the location I clicked.
Essentially what I would like to see is the x,y or width,height of the location of the image I clicked given that the image is 20000x15000 in dimension.
Here is the fiddle http://jsfiddle.net/rayshinn/yvfwzfw4/1/
Not sure why but it's seems a bit buggy when you zoom all the way out. Just zoom all the way in for it to stop the bug on jsfiddle. This bug is not the focus as it does not happen in my local environment! seems to be something to do with fiddle.
The leaflet is giving you the x,y coordinates along the "image-map" div which resizes with the zoom in and out. The event coordinates do not scale to your image size.
In order to get x,y relative to actual picture size, you need to multiply the coordinates against the ratio of current div dimensions and full sized image dimensions.
Check my Fiddle
I calculated your x,y by taking the events coordinates, multiplying them by your var w
and var h
and dividing them by the maps height and width:
function onMapClick(e) {
var mapWidth=map._container.offsetWidth;
var mapHeight=map._container.offsetHeight;
console.log(e.containerPoint.x * w / mapWidth);
console.log(e.containerPoint.y * h / mapHeight);
console.log(e);
}
To solve this problem you need to utilize the map project to convert the latitude and longitude to coordinates in the image.
The Project method on the map is the magic
http://leafletjs.com/reference.html#map-conversion-methods
The projection will give you the X,Y in the image. These values will be zoomed based on how the image is scaled (i.e. the map zoom level).
Calculating the natural (X,Y) of the click is just a matter of calculating the scale ratio of the map bounds or overlay size and then dividing that by the projected click coordinates.
When you create the imageOverlay store that in a variable. Need to reference that to determine the scale factor of the image layer.
On click project the lat lng of the click into (x,y) coordinates
divide current width and height of the image with the natural width and height (you need to do this to handle the size change caused by map zoom)
Divide projected click coordinates by the scale factor. This will give you back the actually X,Y coordinates in the original image which is what I think you want. Code below and check out the fiddle for working example. http://jsfiddle.net/muglio/h5st7bpt/
.
// so that it covers the entire map
var overlay = L.imageOverlay(url, bounds)
overlay.addTo(map);
// tell leaflet that the map is exactly as big as the image
map.setMaxBounds(bounds);
function onMapClick(e) {
//Project the map click to x,y coordinates
//This projection is the actual XY coordinates of the image layer
//This coordinate is scaled by the amount the image is zoomed.
var clientClick = map.project(e.latlng);
//Grab the original overlay
var overlayImage = overlay._image;
//Calculate the current image ratio from the original (deals with zoom)
var yR = overlayImage.clientHeight / overlayImage.naturalHeight;
var xR = overlayImage.clientWidth / overlayImage.naturalWidth;
//scale the click coordinates to the original dimensions
//basically compensating for the scaling calculated by the map projection
var x = clientClick.x / xR;
var y = clientClick.y / yR;
console.log(x,y);
}
Hope this helps!
I don't know about leaflet but you dont need it to achieve this. With javascript you can implement a listener and use event.latLng
in a marker to manipulate the info.
google.maps.event.addListener(map, 'click', function(event) {
marker.setPosition(event.latLng);
});
Check this working fiddle
You are receiving containerPoint
, which contains x and y coordinates placement(container-wise) when you trigger the contextmenu event now.Since you know/can retrieve the dimensions of the Map container, and you know the native dimensions of the image..shouldn't that be enough to do the calculations?
e.g If you know the map container width is 1000px...and you receive a contextmenu event where the x coordinate is 500...then you know someone clicked directly in the center because 500 / 1000(map container width) = 0.5 and that means the actual position on the image would be native width(2000, as per your variable w
) * 0.5 = 1000.