RedCrusador
RedCrusador

Reputation: 705

Mapbox GL approximate distance from bbox

I am using Mapbox GL JS to find out the nearest features to a clicked spot the user has clicked on the map. Its working great. But I'd like to output a approximate distance. The code Im using is below...

function nearestFeature(y,x) { 
    var bbox = [[y, x], [y, x]];
    var featuresBuilding = map.queryRenderedFeatures(bbox, { layers: ['MyBuildingLayer'] });
    if (featuresBuilding[0]) {
        //found
    }else{
        //widen the area
        for (i = 1;i<100;i++) {
            bbox = [[y-i, x-i], [y+i, x+i]];
            featuresBuilding = map.queryRenderedFeatures(bbox, { layers: ['MyBuildingLayer'] });
            if (featuresBuilding[0]) { 
                //calculate distance
                var distance = 100*i; 
                break;
            }
        }
    }
}

I might be complicating this issue but essentially I need to work out the distance a point difference is for the X / Y and multiply the meter distance to get a rough estimation. I used var distance = 100*i to illustrate this, I need to work out how to acertain the dummy 100 figure...

Upvotes: 1

Views: 1809

Answers (1)

Andi-lo
Andi-lo

Reputation: 2312

I once had a project where I also needed the value of 1px as a distance value to build something like a scale control (https://www.mapbox.com/mapbox-gl-js/api/#scalecontrol)

The solution is using the bounding box of the current viewport to calculate the distance between 2 points. Dividing this by the users viewport width will give you the distance for 1 pixel. I Used the mapbox scale control to check my values against theirs and the result seems to be reasonable.

I came up with this solution (requires turf.js). You can see the full working example on a quick jsfiddle I created: https://jsfiddle.net/andi_lo/38h7m5wx/

function getDistance() {
  const bounds = map.getBounds();
  const topLeft = turf.point([bounds._ne.lng, bounds._ne.lat]);
  const topRight = turf.point([bounds._sw.lng, bounds._ne.lat]);
  const bottomLeft = turf.point([bounds._ne.lng, bounds._sw.lat]);
  const bottomRight = turf.point([bounds._sw.lng, bounds._sw.lat]);
  
  const middleLeft = turf.midpoint(topLeft, bottomLeft);
  const middleRight = turf.midpoint(topRight, bottomRight);
  const distance = turf.distance(middleLeft, middleRight, 'kilometers');
  return distance;
}

const clientWidth = window.innerWidth;
const distance = getDistance();
const onePixel = distance / clientWidth;
console.log(`1px is ~${onePixel.toFixed(3)} km or ${Math.ceil((onePixel) * 1000)} meters`);

Upvotes: 2

Related Questions