Leaflet: Get scaled bounding box by zoom level

Viewed 245

I am trying to make a projection on how the next bounds will look like. Here is a plunkr: https://plnkr.co/edit/sk6NRh51WZA2vpWP

This is how I got it working, but it is not very efficient:

const originalMapElement = document.getElementById('map');
const lMap: any = L.map(originalMapElement);


// working but very inefficient
// ----------------------------
function getScaledBounds(center, zoom) {
  const fakeDiv = document.createElement("div");
  fakeDiv.style.display = "block";
  fakeDiv.style.visibility = "hidden";
  fakeDiv.style.width = originalMapElement.offsetWidth + "px";
  fakeDiv.style.height = originalMapElement.offsetHeight + "px";
  document.body.appendChild(fakeDiv);
  const fakeMap = L.map(fakeDiv);
  fakeMap.setView(center, zoom, { animate: false });
  return fakeMap.getBounds();
}

My two other programmatic approaches are very close and yield almost but not quite the same results as the first function above:

function getScaledBounds(center, zoom) {
  const centerPoint = lMap.project(center, zoom);
  const viewHalf = lMap.getSize().divideBy(2);
  const projectedBox = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf));
  return L.latLngBounds(
    lMap.unproject(projectedBox.getBottomLeft(), zoom),
    lMap.unproject(projectedBox.getTopRight(), zoom),
  );
}
function getScaledBounds(center, zoom) {
  const zoomFactor = Math.pow(2, zoom) * 2;
  const dw = originalMapElement.offsetWidth / zoomFactor;
  const dh = originalMapElement.offsetHeight / zoomFactor;
  const centerPoint = lMap.project(center, zoom);
  return L.latLngBounds(
    lMap.unproject(new Point(centerPoint.x - dw, centerPoint.y + dh, false), zoom),
    lMap.unproject(new Point(centerPoint.x + dw, centerPoint.y - dh, false), zoom),
  );
}

Does anybody have a solution for this problem? Or can someone explain why all of these yield different results, while they should return the same value in my understanding?

2 Answers

This was painful :D I didn't find a answer to my question, but I was able to get the code working at least:

function getScaledBoundsWorking(center, zoom) {
  const bounds = lMap.getPixelBounds(center, zoom);
  const sw = lMap.unproject(bounds.getBottomLeft(), zoom);
  const ne = lMap.unproject(bounds.getTopRight(), zoom);
  return L.latLngBounds(sw, ne);
}

https://plnkr.co/edit/ei6qg001clSoe0CI

I am still curious about what exactly is wrong with the other approaches.

lMap.unproject() and lMap.project() are not a linear functions. You have treated them as linear in your previous approaches.

const viewHalf = lMap.getSize().divideBy(2); Gets half of the displayed size, but does not necessarily match the projection to provide the middle of the map.

In your answer, by calling lMap.unproject() passing non-modified values, works perfectly.

When working with non-linear relationships, the standard arithmetic operations do not work correctly without including the non-linear factors.

Related