Can map.getBounds be executed for a different coordinate system? - leaflet

I execute the following code in my leaflet webmap
map.getBounds().getWest() + "&y1=" +
map.getBounds().getSouth() + "&x2=" +
map.getBounds().getEast() + "&y2=" +
map.getBounds().getNorth()
This results in a result showing me four coordinates in the WGS84 (standard) coordinate system.
Is there any way to alter this so it will output 28992 coordinates instead?

I guess that by "28992 coordinates" you're referring to the EPSG:28992 Coordinate Reference System.
The canonical way to use "non-standard" CRSs in Leaflet is to leverage proj4leaflet. This answer assumes that you're already doing so.
So the getBounds() method of L.Map always returns a L.LatLngBounds instance, which refer to unprojected WGS84 coordinates. However, we can use the map's CRS to project a L.LatLng into a L.Point with the projected coordinates, in the map's display CRS; e.g.
var map = L.map('containerId`, { crs: crsForEpsg28992 });
var foo = map.options.crs.project(L.latLng([60.3,21.1]));
var qux = map.options.crs.project(map.getCenter());
Because of how map projections work (they rotate and bend the coordinate spaces), and because of how proj4js is implemented, it's not possible to project a bounding box into a bounding box. (In most cases, the projection of a bounding box would be a curved polygon!). This image from an article by Gregor Aisch illustrates the issue:
We can, however, do an approximation: project the four corners of the bounding box, e.g.:
var mapBounds = map.getBounds();
var crs = map.options.crs;
var nw = crs.project(mapBounds.getNorthWest());
var ne = crs.project(mapBounds.getNorthEast());
var sw = crs.project(mapBounds.getSouthWest());
var se = crs.project(mapBounds.getSouthEast());
We can even create a L.Bounds (but not a L.LatLngBounds!) from those projected coordinates; that'll be a bbox in the specified CRS that contains all corners, e.g.:
var bbox = L.bounds([nw, ne, sw, se]);
It's not gonna be perfect, but that approximation should be enough for most use cases.
See also this working example (based off on one of the proj4leaflet examples), which should further illustrate the issue.

Related

Leaflet convert meters to pixels

I am creating an app using leaflet
I have the leaflet map up and running and have a Geoserver service that return points that are shown on the map.
I have one additional field that is distance between my Points on the Map and it is in meters ?
My question is how could I convert it to pixels? Is there any Leaflet function or anything ?
You can use this function with the L.GeometryUtil library.
L.GeometryUtil CDN
function disToPixeldistance(distance){
var l2 = L.GeometryUtil.destination(map.getCenter(),90,distance);
var p1 = map.latLngToContainerPoint(map.getCenter())
var p2 = map.latLngToContainerPoint(l2)
return p1.distanceTo(p2)
}
But think of that the pixel distance is changing every time you zoom

How to get the edge of a polygon drawn on map within Leaflet

I am working with Leaflet and Leaflet-Draw in Angular to draw some polygons on the Google Map. How can I implement a listener when the user clicks exactly on the edge of the drawn polygons and get the lat and lng of that edge. I know a similar situation can be implemented with Google Map API like the code below, but I can not find any source to help me implement the same thing in Leaflet.
google.maps.event.addListener(polygon, 'click', function (event) { console.log(event.edge) }
Google Map Documentation: https://developers.google.com/maps/documentation/javascript/reference/polygon#PolyMouseEvent
For those who come across this question: I found a solution myself!
I didn't find anything directly from Leaflet draw library that I could use, so I defined the problem for myself as a trigonometry problem and solve it that way.
I defined a function in which on polygon click, it converts the event.latlng and loops over polygon.getLatLngs()[0] taking a pair of A and B points. A is the first coordinates, B is the next and if it reaches to the end of array, B will be the first point. Then using Collinear Function of 3 points with x, y, I checked if the clicked x, y has a same slope as point A and B.(has to be rounded it up), if so, I would save that A and B point pair with their latLng information and further used it in my project.
Although this method works, I would appreciate if anybody would know a better solution or library built-in function that can be used instead. Thanks!
When the user clicks on the polygon you can loop through all corners and check if he clicked in the near of the corner.
poly.on('click', function(e){
var latlng = e.latlng;
var corners = poly.getLatLngs();
if(!L.LineUtil.isFlat(corners)){ //Convert to a flat array
corners = corners[0];
}
//Convert the point to pixels
var point = mymap.latLngToContainerPoint(latlng);
//Loop through each corner
corners.forEach(function(ll){
//Convert the point to pixels
var point1 = mymap.latLngToContainerPoint(ll);
var distance = Math.sqrt(Math.pow(point1.x - point.x, 2) + Math.pow(point.y - point1.y, 2));
//Check if distance between pixels is smaller then 10
if(distance < 10){
console.log('corner clicked');
}
});
});
This is plain JS you have to convert it self to angular.
A alternativ is to place on each corner a DivMarker or a CircleMarker and fire a event if the marker is clicked.
Looks like: https://geoman.io/leaflet-geoman

How to calculate location’s long/lat based on its bbox coordinates

please could anyone help?
I need to use a map.toFly() method to interpolate between 2 locations.
According to the Mapbox documentation, I need to pass in an object describing the destination I want to fly to. The object has to have a center property holding an array with centre Long/lat coordinates of the destination I need to be taken to.
https://docs.mapbox.com/mapbox-gl-js/example/flyto/
My problem with implementing the method is that I only have bounding box coordinates of the 2 locations between which I need to interpolate . I can’t do something like this:
map.flyTo(bbox)
Does anyone know how to obtain
centre Long/lat coordinates of each location based on their bbox coordinates?
Assuming you have 2 LngLatBounds objects you can call the getCenter() method.
var point1 = bounds1.getCenter();
var point2 = bounds2.getCenter();
where both bounds1 and bounds2 are objects of the type LngLatBounds.
Check:
https://docs.mapbox.com/mapbox-gl-js/api/#lnglatbounds#getcenter
Edit: for the values you gave in your comment it would be for the first bounds:
var sw1 = new mapboxgl.LngLat(110.2672863, -7.1144639);
var ne1 = new mapboxgl.LngLat(110.5088836, -6.9319917);
var bounds1 = new mapboxgl.LngLatBounds(sw1, ne1);
Note: Mapbox GL uses longitude, latitude coordinate order (as opposed to latitude, longitude).

Leaflet latLngToContainerPoint and containerPointToLatLng not reciprocal?

Anybody know why the following is not reciprocal? latLng and new
var point = dispmap.latLngToContainerPoint(latlng);
var newPoint = L.point([point.x, point.y]);
var newLatLng = dispmap.containerPointToLatLng(newPoint);
When I execute this code I send in latlng=(26.75529,-80.93581)
newLatLng, which by inspection of the code above I would expect to reciprocate gives back...
newLatLng = (26.75542,-80.93628)
I'm wanting to array some markers with identical lat-lons around the shared spot on a map, and bumping each by some screen coordinates looks like the best method based on some blog/issue reading I've done.
I'm, "close" to what I want to achieve, but as I try to validate what these leaflet calls are doing for me I hit the fundamental question above.
They can't be ...
Latitude and longitude are float values while x and y are integer values.
This means that there are an (theoretically) infinite number of latlng's and a rather small number of points on your view (width * height).
Furthermore, I'm not sure how you define identical latlng's; the best you can't to is to speak of proximity.
If I read between the lines, identical may mean that the markers overlap. Then the best way is to have a look how Leaflet.MarkerCluster are tackling with the problem.
I was able to achieve my desired result by altering zoom level to avoid pixel-point quantization effects on my translations. The screenshot below illustrates an orange and two green circle markers that represent an identical lat-lon, but I want the green arrayed around the orange in a circular fashion...in this example there are only 2 green.
I perform simple circular array math with an angular step size of PI/4 in this example. The KEY to getting the visual effect correct is the "dispmap.setZoom(dispmap._layersMaxZoom)" call BEFORE I do the math, and then I invoke "dispmap.setZoom(mats.zoom)" after the math, which will give the user the desired zoom level as specified by variable mats.zoom.
var arrayRad=20;
var dtheta=Math.PI/4;
var theta=0;
dispmap.setZoom(dispmap._layersMaxZoom)
L.geoJson(JSON.parse(mats.intendeds), {
pointToLayer: function (feature, latlng) {
var point = dispmap.latLngToContainerPoint(latlng);
dx = arrayRad*Math.cos(theta);
dy = arrayRad*Math.sin(theta);
theta += dtheta;
var newPoint = L.point([point.x + dx, point.y+ dy]);
var newLatLng = dispmap.containerPointToLatLng(newPoint);
return L.circleMarker(newLatLng, intendedDeliveryLocationMarkerOptions);
}, onEachFeature: onEachIntendedLocFeature }).addTo(dispmap);
dispmap.setZoom(mats.zoom);
Sample screen shot at max zoom level: 2 arrayed markers

Unable to display only the points within a specific range (circle) using the .getBounds() function (Leaflet)

I am trying to display a certain amount of points within a specific range, that is within a circle. But when using the .getBounds() function for comparison to see whether the point is within the bound, i get some points outside it as shown in the screenshot below:
Map Screenshot
The code currently using to check if the point is within the circle bound is below:
echo '
var mark = L.marker([' . $r->coordinates[0]->longitude . ',' . $r->coordinates[0]->latitude . ']);
if(circle.getBounds().contains(mark.getLatLng())){
mark.addTo(map);
mark.bindPopup("'.$info.'");
}
';
I am looping into an array to retrieve the latitude and longitude and from there, to see whether the coordinates fills into the bound, if so, it adds it to the map with their corresponding popup
Any solution regarding this particular issue?
Thanks for helping
You can create your own contains method and add it to the L.Circle class because it doesn't have one by default. You can use the utility method distanceTo of the L.LatLng objects to calculate distance between your marker and the circle's center and compare that to the circle's radius:
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
Now when you have a circle and a marker or latlng object you can do this:
var map = L.map(...);
var circle = L.circle(...).addTo(map),
marker = L.marker(...).addTo(map);
latLng = L.latLng(...);
// Returns true when in the circle and false when outside
circle.contains(marker.getLatLng());
circle.contains(latLng);
Working example on Plunker: http://plnkr.co/edit/OPF7DM?p=preview
L.Circle reference: http://leafletjs.com/reference.html#circle
L.Marker reference: http://leafletjs.com/reference.html#marker
L.LatLng reference: http://leafletjs.com/reference.html#latlng
The method getBounds() always returns a rectangular area. Hence it can't be used for checking whether a non-rectangular object contains a given point.
For a circle you should be able to calculate the distance (distanceTo()) of the point to the circle's center (getLatLng()) and check whether it is smaller than the circle's radius (getRadius()). Note that the distance and radius are in meters.