goaでバスの路線図APIを作る(ビュー編)

ビュー実装

前回のAPIから取得できるデータを使ったビューを作る。

ビューは地図上に路線図を書くので、leafletを使う。

APIから取れるデータはこんな感じになっていて、

図にするとこんな感じ。

elementをrelationのA→Bの順に繋いでいくと路線経路が引ける様になっている。

このデータをLeaflet用のデータに変換するところを書いて

// Geojson型へキャスト
function getCoordinate(c){
    return [c.latitude,c.longitude]
}
// 経路を生成
function getCoordinates(cs){
    var coordinates = []
    for(let c of cs){
        coordinates.push(getCoordinate(c))
    }
    if(coordinates.length==1){
        coordinates.push(coordinates[0])
    }
    return coordinates
}
// elementをleafletのFeatureへキャスト
function getFeature(element){
    return {
        "type": "Feature",
        "geometry": {
            "type": "LineString",
            "coordinates": getCoordinates(element.coordinates)
        }
    }
}
// elementsをleafletのFeatureCollectionへキャスト
function GetFeatures(elements){
    var features = []
    for(let e of elements){
        features.push(getFeature(e))
    }
    return {
        "type": "FeatureCollection",
        "features": features
    }
}
// operationalPointの位置を取得
function GetBusstops(elements, ops){
    var busstops = []
    for(let op of ops){
        for(let e of elements){
            if(op.elementID == e.id){
                coordinate = getCoordinate(e.coordinates[0])
                busstops.push({
                    "coordinate": [coordinate[1],coordinate[0]],
                    "name": op.name
                })
            }
        }
    }
    return busstops
}

このデータをleafletに渡す。

// 線(FeatureCollection)オブジェクト生成
var line = GetFeatures(res.elements)
// 線を描画
L.geoJSON(line,{
    onEachFeature: function onEachFeature(
         feature,
         layer
  ){
      if(feature.properties && feature.properties.popupContent){
        layer.bindPopup(feature.properties.popupContent);
     }
     }
}).addTo(map)
// バス停情報の配列生成
var busstops = GetBusstops(res.elements,res.operationalPoints)
// バス停の表示
var popup = L.popup();
for(let busstop of busstops){
     L.marker(busstop.coordinate).addTo(map).on("click",function(e){
        popup.setLatLng(e.latlng).setContent(busstop.name).openOn(map);
     })
}

ここまでで、地図上に線とバス停が描ける。

これに加えて、relationでelementを辿って経路を矢印で描く処理を作る。

// 矢印を引く
for(let r of res.relations){
     var elementA=[], elementB=[]
   var arrow = false
   for(let e of res.elements){
      // 矢印の起点
      if(r.elementA == e.id){
          if(e.coordinates.length>1){
              elementA = getCoordinate(e.coordinates[e.coordinates.length-2])
          }else if(e.coordinates.length==1){
              elementA = getCoordinate(e.coordinates[0])
          }else{
              console.error("coordinate not found")
          }
      }
      // 矢印の終点
      if(r.elementB == e.id){
              if(e.coordinates.length>1){
              elementB = getCoordinate(e.coordinates[1])
          }else if(e.coordinates.length==1){
              elementB = getCoordinate(e.coordinates[0])
              arrow = true
          }else{
              console.error("coordinate not found")
          }
      }
   }
  // polylineDecoratorへ矢印を引く座標を渡す
   if(arrow) {
       var polyline = L.polyline([[elementA[1],elementA[0]],[elementB[1],elementB[0]]]).addTo(map);
       var decorator = L.polylineDecorator(polyline, {
            patterns: [
                 {offset: '100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 5, polygon: true, pathOptions: {stroke: true}})}
            ]
       }).addTo(map);
   }
}

矢印を引くのは下記を使った。

経路を引いたのがこちら。

というわけで、goaでAPI作り終わりました。

感想

というわけで、goaでAPI作り終わりました。
goaはわからないことを調べるのが少し大変だけど、慣れればすごく良さそう。
何よりAPIとして動くモックがすぐにできて、designが変わってもある程度は自動生成の範囲でカバーできるので、開発効率上がりそうだなと。
以上、読んでくださりありがとうございました。

今回作ったコードは下記に置いておきます。


この記事が気に入ったらサポートをしてみませんか?