私はmapbox.jsをmapbox-gl.js、ピクセルの代わりに半径にマイルまたはメートルを使用する円の描画に問題があります。この特定の円は、中心点から任意の方向の距離の領域を示すために使用されます。
以前は、レイヤーグループに追加された次のものを使用できました。
// 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は次のとおりです。
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を使用して、ズームと距離とスケールに基づく円(または複数)でレイヤーをレンダリングする方法はありますか?
現在、Mapbox GL v0.19.0を使用しています。
Lucas 'answer について詳しく説明すると、特定のメトリックサイズに基づいて円を描くためにパラメーターを推定する方法を思いつきました。
マップは0〜20のズームレベルをサポートしています。半径を次のように定義するとします。
_"circle-radius": {
stops: [
[0, 0],
[20, RADIUS]
],
base: 2
}
_
最小ズームレベル(0)と最大ズームレベル(20)の値を定義したため、マップはすべてのズームレベルで円をレンダリングします。その間のすべてのズームレベルについて、半径は(およそ)RADIUS/2^(20-zoom)
になります。したがって、RADIUS
をメトリック値に一致する正しいピクセルサイズに設定すると、すべてのズームレベルで正しい半径が取得されます。
したがって、基本的には、ズームレベル20でメートルをピクセルサイズに変換する変換係数を使用します。もちろん、この係数は緯度に依存します。最大ズームレベル20で赤道で水平線の長さを測定し、この線がまたがるピクセル数で割ると、係数〜0.075m/px(ピクセル/メートル)が得られます。 1 / cos(phi)
のメルカトル緯度スケーリング係数を適用すると、どの緯度でも正しいメーター対ピクセル比が得られます。
_const metersToPixelsAtMaxZoom = (meters, latitude) =>
meters / 0.075 / Math.cos(latitude * Math.PI / 180)
_
したがって、RADIUS
をmetersToPixelsAtMaxZoom(radiusInMeters, latitude)
に設定すると、正しいサイズの円が得られます。
_"circle-radius": {
stops: [
[0, 0],
[20, metersToPixelsAtMaxZoom(radiusInMeters, latitude)]
],
base: 2
}
_
GeoJSONポリゴンを使用して、ユースケースでこの問題を解決しました。厳密には円ではありませんが、多角形の辺の数を増やすことで、かなり近づけることができます。
この方法の追加の利点は、マップでピッチ、サイズ、方位などが自動的に正しく変更されることです。
GeoJSONポリゴンを生成する関数は次のとおりです
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]
}
}]
}
};
};
次のように使用できます。
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
}
});
後で作成したサークルを更新する必要がある場合は、次のようにできます(setDataに渡すdata
プロパティを取得する必要があることに注意してください)。
map.getSource('polygon').setData(createGeoJSONCircle([-93.6248586, 41.58527859], 1).data);
出力は次のようになります。
この機能はGL JSには組み込まれていませんが、 functions を使用してエミュレートできます。
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.19.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.19.0/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoibHVjYXN3b2oiLCJhIjoiNWtUX3JhdyJ9.WtCTtw6n20XV2DwwJHkGqQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v8',
center: [-74.50, 40],
zoom: 9,
minZoom: 5,
maxZoom: 15
});
map.on('load', function() {
map.addSource("source_circle_500", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-74.50, 40]
}
}]
}
});
map.addLayer({
"id": "circle500",
"type": "circle",
"source": "source_circle_500",
"Paint": {
"circle-radius": {
stops: [
[5, 1],
[15, 1024]
],
base: 2
},
"circle-color": "red",
"circle-opacity": 0.6
}
});
});
</script>
</body>
</html>
重要な注意事項: