やったこと、やる予定のこと
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。