I'm in the process of converting a map from using mapbox.js to mapbox-gl.js, and am having trouble drawing a circle that uses miles or meters for its radius instead of pixels. This particular circle is used to show the area for distance in any direction from a central point.
Previously I was able to use the following, which was then added to a layer group:
// 500 miles = 804672 meters
L.circle(L.latLng(41.0804, -85.1392), 804672, {
stroke: false,
fill: true,
fillOpacity: 0.6,
fillColor: "#5b94c6",
className: "circle_500"
});
The only documentation I've found to do this in Mapbox GL is the following:
map.addSource("source_circle_500", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-85.1392, 41.0804]
}
}]
}
});
map.addLayer({
"id": "circle500",
"type": "circle",
"source": "source_circle_500",
"layout": {
"visibility": "none"
},
"paint": {
"circle-radius": 804672,
"circle-color": "#5b94c6",
"circle-opacity": 0.6
}
});
But this renders the circle in pixels, which does not scale with zoom. Is there currently a way with Mapbox GL to render a layer with a circle (or multiple) that's based on distance and scales with zoom?
I am currently using v0.19.0 of Mapbox GL.
I've solved this problem for my use cases by using a GeoJSON polygon. It's not strictly a circle but by increasing the number of sides on the polygon you can get pretty close.
The added benefit to this method is that it will correctly change its pitch, size, bearing, etc with the map automatically.
Here is the function to generate the GeoJSON Polygon
var createGeoJSONCircle = function(center, radiusInKm, points) {
if(!points) points = 64;
var coords = {
latitude: center[1],
longitude: center[0]
};
var km = radiusInKm;
var ret = [];
var distanceX = km/(111.320*Math.cos(coords.latitude*Math.PI/180));
var distanceY = km/110.574;
var theta, x, y;
for(var i=0; i<points; i++) {
theta = (i/points)*(2*Math.PI);
x = distanceX*Math.cos(theta);
y = distanceY*Math.sin(theta);
ret.push([coords.longitude+x, coords.latitude+y]);
}
ret.push(ret[0]);
return {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [ret]
}
}]
}
};
};
You can use it like this:
map.addSource("polygon", createGeoJSONCircle([-93.6248586, 41.58527859], 0.5));
map.addLayer({
"id": "polygon",
"type": "fill",
"source": "polygon",
"layout": {},
"paint": {
"fill-color": "blue",
"fill-opacity": 0.6
}
});
If you need to update the circle you created later you can do it like this (note the need to grab the data
property to pass to setData):
map.getSource('polygon').setData(createGeoJSONCircle([-93.6248586, 41.58527859], 1).data);
And the output looks like this: