I have a problem, getting pixel coordinates in Leaflet. Any help would be greatly appreciated!
I want to display an image using leaflet (no tiles - just a image, non-geographical map) and the user should have the option to click on the image, set a marker and I need the pixel position of that marker. For testing purposes, I've created a JSFiddle, that uses this image.
Displaying the image and setting the marker is not a problem. There are plenty of tutorials out there for that.
But getting that pixel position is - at least for me - somehow impossible. I've read every post / article / ... about the different methods provided by Leaflet, but still no success.
In an image editing program I can see, that the top of this tower on the image has roughly these pixel coordinates: x=1350, y=625.
Image showing the pixel position of the top of the tower:
So when the user clicks on the top of the tower, I get the LatLng of this point and I can set the marker. When the user does not change the zoom level, my code is actually working. Clicking on the top of the tower, I get pixel coordinates, that are correct (see the blue marker on the image, showing where i clicked, and the pixels calculated displayed on the console):
Image showing the correct calculated position, if the user didn't zoom:
But when the user starts zooming, the calculated pixel coordinates are definitely wrong:
Image showing the wrong calculated position, after the user zoomed:
I've created this JSFiddle to share my code: https://jsfiddle.net/q36f1ytu/73/
The code that handles the click event is basically this (see my JSFiddle for the whole code):
map.on("click", function (e) {
const marker = new L.Marker(e.latlng).addTo(map)
// Here I want to get the pixel coordinate of the image
var imagePixelCoords = map.project(e.latlng, map.getZoom())
console.log("imagePixelCoords: " + imagePixelCoords)
})
I am quite lost, how to calculate the pixel coordinates correctly, when the user zooms.
Thank you very much in advance!
Since you are using a custom CRS, use the image height and width for the bounds, set minZoom
to a negative value such as -5
(here is why), and then simply use e.latlng
to retrieve the image coordinates.
But there is another caveat, x
and y
of an image usually starts in the top-left corner of the image, however, the coordinates in a leaflet map starts on the bottom-left. Therefore, you'll need to calculate imgHeight-lat
to retrieve the correct y
pixel.
const imageUrl =
'https://upload.wikimedia.org/wikipedia/commons/7/7c/Kaohsiung_Skyline_2020.jpg';
const imgWidth = 3236;
const imgHeight = 2157;
const map = L.map('map', {
minZoom: -5,
crs: L.CRS.Simple,
zoomControl: false,
});
const bounds = [[0, 0], [imgHeight, imgWidth]];
L.imageOverlay(imageUrl, bounds).addTo(map);
map.fitBounds(bounds);
map.on('click', (e) => {
let {lat: y, lng: x} = e.latlng;
// starting top-left instead bottom-left
y = imgHeight - y;
if (y < 0 || y > imgHeight || x < 0 || x > imgWidth) {
console.log('outside of image');
return;
}
console.log(x, y);
new L.Marker(e.latlng).addTo(map)
});
Here is a JSFiddle.
Addendum: This StackOverflow question is using a custom class CRSPixel
to move the origin from the bottom left corner to the top left corner:
// ...
const CRSPixel = L.extend({}, L.CRS.Simple, {
transformation: new L.Transformation(1, 0, 1, 0),
});
const map = L.map('map', {
minZoom: -5,
crs: CRSPixel,
zoomControl: false,
});
// ...
map.on('click', (e) => {
const {lat: y, lng: x} = e.latlng;
if (y < 0 || y > imgHeight || x < 0 || x > imgWidth) {
console.log('outside of image');
return;
}
console.log(x, y);
new L.Marker(e.latlng).addTo(map)
});
Here is a JSFiddle with CRSPixel
.