Getting pixel coordinates of an image overlay using leaflet map library on click (right click)

12,686

Solution 1

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);


}

Solution 2

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.

  1. When you create the imageOverlay store that in a variable. Need to reference that to determine the scale factor of the image layer.

  2. On click project the lat lng of the click into (x,y) coordinates

  3. 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)

  4. 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!

Share:
12,686
BaconJuice
Author by

BaconJuice

Part-Time BaconJuicer

Updated on June 10, 2022

Comments

  • BaconJuice
    BaconJuice almost 2 years

    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.

  • BaconJuice
    BaconJuice about 9 years
    Hi @Jordi I'm not trying to find the lat,lang of the map. I'm trying to find the x,y of the image.
  • Jordi Castilla
    Jordi Castilla about 9 years
    I understand.... can you post a fiddle or some example where we can see the issue?
  • muglio
    muglio about 9 years
    This solution works even if map is resized. It appears not to work on JSFiddle when the map is zoomed out and not 100% width and height of the fiddle container but I believe that is an artifact of JSFiddle. Was curios and compared it to my solution and will verify this solution works even when map is resized.
  • Dave Alperovich
    Dave Alperovich about 9 years
    @muglio, I tried testing at different sizes and was always able to get success. I probably dont understand the use case you're describing bc it sounds like a scenario that works for me...
  • muglio
    muglio about 9 years
    I agree with your answer. It is good and I upvoted. I stated in my answer which was different that you deserve the bounty.
  • muglio
    muglio about 9 years
    To clarify I was trying to point out an issue with JSFiddle. I tested your solution outside of jsfiddle and it works.
  • Dave Alperovich
    Dave Alperovich about 9 years
    @muglio, I figured that. You stated very carefully. But I couldn't figure out how to reproduce it.
  • Dave Alperovich
    Dave Alperovich about 9 years
    Thank you. Let's see which solution works best for OP.
  • muglio
    muglio about 9 years
    If you fullscreen JSFiddle you can zoom in all the way on the map. Then zoom all the way out... The map starts bouncing (jsfiddle issue) then you resize the window until map stops bouncing. Zoom in a couple times then all the way back out. This cause X coordinates to go - on the far left side of map. It looks like fiddle is introducing a negative margin issue in the map.
  • Dave Alperovich
    Dave Alperovich about 9 years
    @muglio aaahhh, I see now. Yes, something odd about this Fiddle
  • BaconJuice
    BaconJuice about 9 years
    Hi muglio, thank you very much for your time and effort in to helping me with this! Appreciate it very much.
  • muglio
    muglio about 9 years
    @BaconJuice No problem.
  • Dine
    Dine over 8 years
    So I'm just having the same issue I think. I've tried this solution and it's logging entirely different values on different zoom levels. I'd like to get the same x and y values related to the original size of the image. Do you guys know how to do that?
  • Dave Alperovich
    Dave Alperovich over 8 years
    @Dine, what browser are you using? Can you create a plunker?
  • Dine
    Dine over 8 years
    I'm using Chrome, I get different values for my local app, but when I look at the jsfiddle mentioned in this answer: jsfiddle.net/dalper01/yvfwzfw4/6 then I also get different values. I.e. when I click the bottom left on the image at zoom level 4 the values are 760.5633802816901 966.403162055336, at zoom level 3 the values are 522.6917057902973 1126.4822134387352
  • Dine
    Dine over 8 years
    @DaveAlperovich is there a way to work out how far the image has been panned out of the screen