jsフレームワークstimulusでyahoo地図を操作してみた（その四、最終回）


# やったこと、やる予定のこと
#### 0. [railsアプリへのstimulus適用](https://qiita.com/wkya_4a/items/e85bd6324fe4085dce0e)
#### 1. [stimuluｓでyahoo地図を表示](https://qiita.com/wkya_4a/items/6e1224550ca0b7aed9d9)

#### ２. [表示した地図上で、指定座標に移動](https://qiita.com/wkya_4a/items/3e2f5bb6cf8abe525bf0)

#### 3. [住所から座標を取得し、それをDBに登録](https://qiita.com/wkya_4a/items/883ad988f2ad5cf58f55)（前回）

#### 4. 「3」で登録した情報を選択し、yahoo地図上でその場所に移動（←今ここ）

だいぶ間が空いてしまいましたが、最終回。
一覧画面にて、
【「3」で登録した座標情報を選択→その地図の場所に移動】
をできるようにします。

##まずは、一覧画面にて地図を表示
今回は、作成するjsファイルの名称は「index_map_controller.js」にしました
(この場合、html側の名称は「index-map」にする必要あり……詳しくは[こちら](https://qiita.com/wkya_4a/items/3f187213c01b071edcd6)を参照）。


```erb:app/views/maps/index.html.erb
<!-- 「data-controller」開始 -->
<div data-controller="index-map">

  <!-- 中略 -->

  </table><!-- ←scaffoldで自動作成される「table」の終了 -->

  <!-- これで地図を表示 -->
  <div id="map" style="width:800px; height:400px"  data-target="index-map.map" ></div>

</div>
<!-- 「data-controller」終了 -->

```


前回・前々回と同様の、地図表示。
ただし今回は、
　a.地図の中心点表示なし
　b.縮尺変更用のスライドバー表示
　c.マウスのスクロールホイールでも地図縮尺変更可能
としています。

```js:app/javascript/controllers/index_map_controller.js
import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "map"]

  initialize() {

       this.map = new Y.Map(this.mapTarget.id,{configure : {

　　　　　// ↓【c.マウスのスクロールホイールでも地図縮尺変更可能】
         scrollWheelZoom : true

       }});

       this.map.drawMap(new Y.LatLng(0, 0), 17, Y.LayerSetId.NORMAL);

　　　　// ↓【a.地図の中心点表示なし_1】
       // var center = new Y.CenterMarkControl

       var control = new Y.LayerSetControl();

　　　　// ↓【a.地図の中心点表示なし_2】
       // this.map.addControl(center);

       this.map.addControl(control);

　　　　// ↓【b.縮尺変更用のスライドバー表示】
       var sliderzoom = new Y.SliderZoomControlVertical();
       this.map.addControl(sliderzoom);

  }
}
```

このへんの細かな地図表示方法については、[こちら](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/js/)
……とYOLP公式頁を覗いてみたら、「API提供終了のお知らせ」って、マジか！！！

…………………………………………まあ、気を取り直して。

##次に、一覧画面のレコードごとに「押したらその場所に移動するボタン」を設置します

```erb:app/views/maps/index.html.erb

  <tbody>
    <% @maps.each do |map| %>
      <tr>
        <!-- 中略 -->
        <td><%= link_to 'Destroy', map, method: :delete, data: { confirm: 'Are you sure?' } %></td>

        <!-- ↓scaffoldで自動作成されている「レコード削除」の後ろに、追記 -->
        <!-- 　→「@maps」に格納されているレコード数だけ、ボタンも作られる。 -->
        <td><input type="button" value="移動" data-action="click->index-map#move" data-lat = <%= map.latitude %>  data-lon = <%= map.longitude %> ></td>

      </tr>
    <% end %>
  </tbody>
```
ボタンの「data-action」設定
　　→クリックしたらjs側で「move」メソッドを走らせる

また↑の「move」メソッド内で、そのレコードの位置情報（経度、緯度）を使いたいので、
それも**「data-〇〇」形式で**ボタンに持たせてやります（この場合は、「data-lat」と「data-lon」）。


##最後に、js側で地図を移動する動き＝「move」メソッドを記述する。
これは、かんたん
……html側にて「data-〇〇＝」で設定した値は、js側では「el（アクション対象を引数として取得).target.dataset.〇〇」で取得できるので、

```js:app/javascript/controllers/index_map_controller.js
  move(el){
    var current_location = new Y.LatLng(el.target.dataset.lat,el.target.dataset.lon);
    this.map.panTo(current_location, true);
  }
```
取得した緯度、経度を「current_location」に放り込み、それをmapの「panTo」に与えてやればいいわけです（この場合は「current_location」なんて作らずに、一行で記述しても良かったかも）。

これで、
![スクリーンショット 2020-04-17 18.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410674/a7811a10-3b85-9eff-7fb9-b3894afd6856.png)
「移動」ボタンを押すとその場所に地図上を移動できるようになります。

##おまけで、ピンを立ててみる。
移動できるのはいいけど、そのレコードの位置情報がどこを指しているのかが若干分かりにくい
──ということで、登録されているレコードの場所にははじめ（画面ロード時）から📍が立っていることにしてみます。

画面ロード時に📍を立てるには、【js側のinitializeメソッド内】で【全レコードの位置情報】を取得する必要があります。

そこでhtml側では「移動」ボタンに、

```erb:app/views/maps/index.html.erb
<td><input type="button" value="移動" data-action="click->index-map#move" data-lat = <%= map.latitude %>  data-lon = <%= map.longitude %> <%# これ追記→ %>data-target="index-map.pin" <%# ←これ追記 %> > ></td>
```
と、【お前は『pin』というdata-targetだ！】という記述を追加してやります。

ただ、この「移動」ボタンはレコード数だけあるので、【『pin』というdata-target】もレコード数だけ存在します。

……さっきも出した
![スクリーンショット 2020-04-17 18.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410674/3f93c9d5-b579-47f7-7eb8-072aed78e05d.png)
　↑の場合、
「大洗」「銚子」「焼津」「境港」それぞれのボタンが【『pin』というdata-target】となっています。

この複数ある【target】は、js側では【targets】として纏めて取得することができます。

↓は画面ロード時、【js側のinitializeメソッド】の途中でストップさせたコンソール画像
　　登録されているレコードは、上に貼った画像と同じ「大洗」「銚子」「焼津」「境港」です。
![スクリーンショット 2020-04-17 18.53.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410674/6d09349c-a920-a26e-d2f7-9d7ff3d9e17a.png)
this.pinTargets　→　4つのボタン全てをターゲットとして取得
this.pinTargets[0] →そのうち1つ目、「大洗」のボタンをターゲットとして取得

「座標情報を持ったターゲット」の取得目処がついたので、
あとは取得したターゲット分だけ、地図に📍を立ててあげます。

```js:app/javascript/controllers/index_map_controller.js
  initialize(){

    //地図を表示する記述……中略

    var map_box = this.map;

    this.pinTargets.forEach(function(pin){
      var current_location = new Y.LatLng(pin.dataset.lat,pin.dataset.lon);
      var marker = new Y.Marker(current_location);
      map_box.addFeature(marker);
    });
  }
```

これで
・地図の「登録された場所」全てにピンが立ち、
・レコードを選択すれば「その登録地点に地図が移動」
するようになります。

サンプルコードはscaffoldで作った一覧なので見栄えがいまいちですが、レイアウトを整えて画像登録と組み合わせれば

　　[● 東海道五十三次](http://mappura.com/plans/5/presentation)

　　[● シン・ゴジラ、進撃経路(パスワードは「sin」と入力してみてください)](http://mappura.com/plans/4/presentation)

なんてものも作れるようになります。

なんですが…………………………………………
メインで使っていたAPI、[Yahoo! JavaScriptマップAPI](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/js/)が2020年10月末で提供終了予定。
代替サービスは紹介されてるけど──無料プランだとアクセス数その他、色々制約がありそうです　orz。