2

I have written some code which creates a rectangle at the position of the user's cursor. There does not seem to be any method to do this in turf.js itself. And of course using the latlong-based coordinates of leaflet, it becomes difficult to do so since it requires mixing geographic & projected coordinates.

But I still have to do this. Ignoring effects from extreme polar distortion (the map will not allow the user to zoom out far enough, nor allow them to pan to regions where these effects will become significant), this is the method I have come up with. In broad strokes:

  1. Get the latlng of the cursor (via a mousemove event listener on the map).
  2. Use the destination method to "throw" a point in all four cardinal directions to get points which represent the left, right, upper and lower limits.
  3. Calculate a rectangle using the envelope method

Is there a simpler way of doing this? It seems like it is rather roundabout

This is the code. Obviously it could be made more compact but I have left it stretched out across multiple var declarations for the sake of readability.

var offsetX =  $("#rectangle-width-input").val()/2; // User input for rectangle width
var offsetY =  $("#rectangle-height-input").val()/2; // User input for rectable height

var topLimit = turf.destination(
    [ev.latlng.lng, ev.latlng.lat] // Mouse cursor location (in latlng),
    offsetY,
    0,
    {"units": "meters"})

var rightLimit = turf.destination(
    [ev.latlng.lng, ev.latlng.lat] // Mouse cursor location (in latlng),
    offsetX,
    90,
    {"units": "meters"})

var bottomLimit = turf.destination(
    [ev.latlng.lng, ev.latlng.lat] // Mouse cursor location (in latlng),
    offsetY,
    180,
    {"units": "meters"})

var leftLimit = turf.destination(
    [ev.latlng.lng, ev.latlng.lat] // Mouse cursor location (in latlng),
    offsetX,
    -90,
    {"units": "meters"})

mouseShape = turf.envelope(turf.featureCollection([ // Resultant rectangle
    topLimit,
    rightLimit,
    bottomLimit,
    leftLimit
]));
0

As you wrote, doing this by Leaflet requires some unprojecting and projecting.

It could be done like this:

latLng1 = L.latLng(ev.latlng.lat, ev.latlng.lng);

var point1 = L.CRS.EPSG3857.project(latLng1);
var point2 = point1.add([offsetX, offsetY]);

var latLng2 = L.CRS.EPSG3857.unproject(point2);
var bounds = L.latLngBounds(latLng1, latLng2);

var rect = L.rectangle(bounds);

var rectFeatures = rect.toGeoJSON();
var coordinates = rectFeatures.geometry.coordinates; 

var polygon = turf.polygon(coordinates);

If you CRS is not EPSG3857, just use proj4 projection definition instead of L.CRS.EPSG3857.

Offset units here are map CRS meters which do not correspond to actual meters in nature. For conversion you have to use scale factor which depends on latitude (see Calculating distance scale factor by latitude for Mercator):

factor = 1 / cos(latitude)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.