とあるハッカソンで、台風の進路を投票で決めるというジョークアプリを作成しました。
動画
アプリ製作にはmapboxを用い、補助としてTurf.jsを使用しました。
Turf.js、めちゃめちゃ便利でmapboxでの開発速度が爆上がりしたのですが、
さすがに「円のリストをつなぐ線を引く」といった関数まではなかったので用意しました。
Turf.jsを利用しているのでとても簡単に実装できています。
// get 2vertices line array from circle array
// in:[{coord:[lng,lat],radius:r},{coord:[lng,lat],radius:r},{},...]
// out [lineStringGeojson,lineStringGeojson,...]
getEmvelopeLineArrayFromCirclleArray = function(_circleArray){
var outArr=[];
if(_circleArray.length > 1){
for(var i=0;i<_circleArray.length-1;++i){
// 1番目の円の中心
var pt0 = turf.point(_circleArray[i+0].coord);
// 2番目の円の中心
var pt1 = turf.point(_circleArray[i+1].coord);
// 直線pt0-pt1の角度
var ang = turf.rhumbBearing(pt0,pt1, {units: 'kilometers'});
var pos0a = turf.rhumbDestination(pt0,_circleArray[i+0].radius,ang-90, {units: 'kilometers'}); // pt0から、直線pt0-pt1に垂直で、距離が1番目の円の半径である場所
var pos0b = turf.rhumbDestination(pt0,_circleArray[i+0].radius,ang+90, {units: 'kilometers'}); // pt0から、直線pt0-pt1に垂直で、距離が1番目の円の半径である場所(反対側)
var pos1a = turf.rhumbDestination(pt1,_circleArray[i+1].radius,ang-90, {units: 'kilometers'}); // pt0から、直線pt0-pt1に垂直で、距離が2番目の円の半径である場所
var pos1b = turf.rhumbDestination(pt1,_circleArray[i+1].radius,ang+90, {units: 'kilometers'}); // pt0から、直線pt0-pt1に垂直で、距離が2番目の円の半径である場所(反対側)
outArr.push(turf.lineString([pos0a.geometry.coordinates,pos1a.geometry.coordinates])); // 直線geojsonを作成してpush
outArr.push(turf.lineString([pos0b.geometry.coordinates,pos1b.geometry.coordinates]));
}
}
return outArr;
}
円のリストを渡すと頂点数2のLineリストが返ってくるので、
var LineArr = getEmvelopeLineArrayFromCirclleArray(tmpCircleArr);
if (!map.getSource('multiLineEmvSrc')){
map.addSource('multiLineEmvSrc', {
'type': 'geojson',
'data': {'type': 'FeatureCollection', 'features': LineArr}
});
}
if (!map.getLayer('multiLineEmv')){
map.addLayer({
'id':'multiLineEmv',
'type':'line',
'source':'multiLineEmvSrc',
'layout': {},
'paint': {
'line-color': '#fff',
'line-width': 1,
'line-opacity': 0.5
}
});
}
のようにaddSource()/addLayer()してあげると円を結ぶ線を引いてくれます。