使用Mapbox GL JS绘制半径为英里/米的圆 [英] Drawing a circle with the radius in miles/meters with Mapbox GL JS
问题描述
我正在将地图从使用 mapbox.js 转换为 mapbox-gl.js 的过程中,但在绘制使用英里或英里的圆时遇到了麻烦以米为单位的半径而不是像素.这个特定的圆圈用于显示从中心点向任意方向的距离区域.
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"
});
我发现唯一的文档 Mapbox GL中的内容如下:
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
}
});
但这会以像素为单位渲染圆,该圆不会随着缩放而缩放. Mapbox GL当前是否存在一种方法来渲染基于距离(并带有缩放比例)的圆形(或多个)的图层?
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?
我当前正在使用Mapbox GL v0.19.0.
I am currently using v0.19.0 of Mapbox GL.
推荐答案
详细说明卢卡斯的答案,我已经提出了一种估计参数的方法,以便根据特定的度量标准大小绘制圆.
Elaborating on Lucas' answer, I've come up with a way of estimating the parameters in order to draw a circle based on a certain metric size.
地图支持0到20之间的缩放级别.假设我们定义半径如下:
The map supports zoom levels between 0 and 20. Let's say we define the radius as follows:
"circle-radius": {
stops: [
[0, 0],
[20, RADIUS]
],
base: 2
}
由于我们定义了最小缩放级别(0)和最大缩放级别(20)的值,因此地图将在所有缩放级别上渲染圆.对于介于两者之间的所有缩放级别,其半径为(大约)RADIUS/2^(20-zoom)
.因此,如果将RADIUS
设置为与指标值匹配的正确像素大小,则对于所有缩放级别,我们都会获得正确的半径.
The map is going to render the circle at all zoom levels since we defined a value for the smallest zoom level (0) and the largest (20). For all zoom levels in between it results in a radius of (approximately) RADIUS/2^(20-zoom)
. Thus, if we set RADIUS
to the correct pixel size that matches our metric value, we get the correct radius for all zoom levels.
因此,基本上,我们使用的转换因子是将米转换为缩放级别20的像素大小.当然,该因子取决于纬度.如果我们在最大缩放级别20处测量赤道水平线的长度,并除以该线所跨越的像素数,则得出的系数约为0.075m/px(米/像素).应用墨卡托度纬度缩放因子1 / cos(phi)
,我们可以针对任何纬度获得正确的米/像素比:
So we're basically after a conversion factor that transforms meters to a pixel size at zoom level 20. Of course this factor depends on the latitude. If we measure the length of a horizontal line at the equator at the max zoom level 20 and divide by the number of pixels that this line spans, we get a factor ~0.075m/px (meters per pixel). Applying the mercator latitude scaling factor of 1 / cos(phi)
, we obtain the correct meter to pixel ratio for any latitude:
const metersToPixelsAtMaxZoom = (meters, latitude) =>
meters / 0.075 / Math.cos(latitude * Math.PI / 180)
因此,将RADIUS
设置为metersToPixelsAtMaxZoom(radiusInMeters, latitude)
会得到一个大小正确的圆:
Thus, setting RADIUS
to metersToPixelsAtMaxZoom(radiusInMeters, latitude)
gets us a circle with the correct size:
"circle-radius": {
stops: [
[0, 0],
[20, metersToPixelsAtMaxZoom(radiusInMeters, latitude)]
],
base: 2
}
这篇关于使用Mapbox GL JS绘制半径为英里/米的圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!