やったこと、やる予定のこと
0. railsアプリへのstimulus適用
1. stimulusでyahoo地図を表示
2. 表示した地図上で、指定座標に移動
3. 住所から座標を取得し、それをDBに登録(前回)
4. 「3」で登録した情報を選択し、yahoo地図上でその場所に移動(←今ここ)
だいぶ間が空いてしまいましたが、最終回。
一覧画面にて、
【「3」で登録した座標情報を選択→その地図の場所に移動】
をできるようにします。
まずは、一覧画面にて地図を表示
今回は、作成するjsファイルの名称は「index_map_controller.js」にしました
(この場合、html側の名称は「index-map」にする必要あり……詳しくはこちらを参照)。
<!-- 「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.マウスのスクロールホイールでも地図縮尺変更可能
としています。
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);
  }
}
このへんの細かな地図表示方法については、こちら
……とYOLP公式頁を覗いてみたら、「API提供終了のお知らせ」って、マジか!!!
…………………………………………まあ、気を取り直して。
次に、一覧画面のレコードごとに「押したらその場所に移動するボタン」を設置します
  <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.〇〇」で取得できるので、
  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」なんて作らずに、一行で記述しても良かったかも)。
これで、

「移動」ボタンを押すとその場所に地図上を移動できるようになります。
おまけで、ピンを立ててみる。
移動できるのはいいけど、そのレコードの位置情報がどこを指しているのかが若干分かりにくい
──ということで、登録されているレコードの場所にははじめ(画面ロード時)から📍が立っていることにしてみます。
画面ロード時に📍を立てるには、【js側のinitializeメソッド内】で【全レコードの位置情報】を取得する必要があります。
そこでhtml側では「移動」ボタンに、
<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】もレコード数だけ存在します。
……さっきも出した

 ↑の場合、
「大洗」「銚子」「焼津」「境港」それぞれのボタンが【『pin』というdata-target】となっています。
この複数ある【target】は、js側では【targets】として纏めて取得することができます。
↓は画面ロード時、【js側のinitializeメソッド】の途中でストップさせたコンソール画像
  登録されているレコードは、上に貼った画像と同じ「大洗」「銚子」「焼津」「境港」です。

this.pinTargets → 4つのボタン全てをターゲットとして取得
this.pinTargets[0] →そのうち1つ目、「大洗」のボタンをターゲットとして取得
「座標情報を持ったターゲット」の取得目処がついたので、
あとは取得したターゲット分だけ、地図に📍を立ててあげます。
  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で作った一覧なので見栄えがいまいちですが、レイアウトを整えて画像登録と組み合わせれば
● シン・ゴジラ、進撃経路(パスワードは「sin」と入力してみてください)
なんてものも作れるようになります。
なんですが…………………………………………
メインで使っていたAPI、Yahoo! JavaScriptマップAPIが2020年10月末で提供終了予定。
代替サービスは紹介されてるけど──無料プランだとアクセス数その他、色々制約がありそうです orz。