1.はじめに
投稿された情報(緯度経度)からGooleMapsAPIを使用して地図を表示、地点間のルート検索機能、周辺情報の取得を実装したので知識の定着、復習のために記事を書きます。
一度に書くと長くなるので、4回にわけて投稿していきます。
今回はその1回目でMAP表示まで実装します。
2.環境
Ruby (2.6.4)
Rails (6.1.7)
Maps JavaScript API
3.前提条件
APIキー取得済み
投稿機能を実装している
4.実装
使用gem
gem 'geocoder'
gem 'gon'
テーブル構造
create_table "posts", force: :cascade do |t|
t.string "address"
t.float "latitude"
t.float "longitude"
end
1.投稿された住所、地名から緯度経度を保存できるようにする
1.gemgeocoder
をインストール
gem 'geocoder'
上記記載後bundle install
2.geocodingを行いたいカラム(今回はaddress
)があるPostモデルに以下記述
class Post < ApplicationRecord
# addressカラムの値(住所、地名など)からgeocoded_byが緯度経度を算出し保存してくれる
geocoded_by :address
# after_validation :geocodeでaddressカラムに変更があった場合に変更後の緯度経度を保存してくれる
after_validation :geocode, if: :address_changed?
end
以上で投稿された住所や地名から緯度経度を算出しlatitudeカラム
とlongitudeカラム
に保存できるようになりました
2.Railsで定義した変数をJavascriptに渡せるようにする
1.gemgon
をインストール
gon
はRailsアプリ内でJavaScriptに変数を渡すことが出来るgem
gem 'gon'
bundle install
を忘れずに
2.Postモデルの投稿をデータベースから取得する
gon.posts = @posts
と変数の頭にgon
をつけることでjavascriptで使用できるようになります。
class PostsController < ApplicationController
def show
@posts = Post.all
gon.posts = @posts
#
@post = Post.find(params[:id])
gon.post = @post
end
以上でjavascriptにデータを渡す準備が整ったので次はAPIを使用してマップを表示させていきます。
3.投稿された緯度経度の情報を中心地点としてGooleMapを表示する
1.viewの記述
ここからMaps JavaScript API
を使用してマップを表示させていきます
<div class="map">
<div id="map_index"></div> # ここにマップが表示される
</div>
<script async src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_API'] ?>&callback=initMap"></script>
- GOOGLE_MAP_APIの箇所は取得したkeyを直接記述するか、envファイルへ記述し環境変数で設定してください。
2.MAPを表示させる
// 変数定義
let map;
let geocoder;
const spot = gon.post; // postsコントローラーから現在表示されている投稿のデータを格納している
function initMap() {
// Google MapsのGeocoderを初期化
geocoder = new google.maps.Geocoder(); // ①
map = new google.maps.Map(document.getElementById('map_index'), { // ②
center: { // ③
lat: spot.latitude,
lng: spot.longitude
},
zoom: 16, // ④
});
①では、Googleサーバーと通信するために必要なgoogle.maps.Geocoderのオブジェクト(インスタンス)を生成しています。
- APIには、このオブジェクトを通してアクセスします。
②地図オブジェクトの作成
-
google.maps.Map
: 地図オブジェクトを生成するコンストラクタです。 -
document.getElementById('map_index')
でHTML内のmap_index
要素を取得し、地図をその要素に描画します。
③地図の初期表示設定
-
center
: 地図の初期表示位置を指定します。spot.latitude
とspot.longitude
は、投稿データから取得した緯度と経度です。 -
const spot = gon.post;
で変数を定義しています。 - これにより、地図が表示されるときにこの座標が中心になります。
④zoom: 16
: 地図の初期ズームレベルを設定します。ズームレベルが大きいほど詳細な地図が表示されます。
3.投稿されたすべての緯度経度からマップに表示させる
// 変数定義
const spots = gon.posts; // postsコントローラーからスポットのデータを格納
for (let i = 0; i < spots.length; i++) { // ①
const markerLatLng = new google.maps.LatLng({ // ②
lat: spots[i]['latitude'],
lng: spots[i]['longitude']
});
①for (let i = 0; i < spots.length; i++)
は、spots 配列内の各要素に対して順番に処理を行うためのループです。
②google.maps.LatLngオブジェクトの作成
-
google.maps.LatLng
コンストラクタは、指定された緯度と経度を持つLatLngオブジェクトを作成します。 - spots[i]['latitude'] と spots[i]['longitude'] は、各スポットの緯度と経度を指定しています。
4. マーカーの表示
// 変数宣言
let marker = [];
marker[i] = new google.maps.Marker({ // ①
position: markerLatLng, // ②
map: map // ③
});
①new google.maps.Marker
で、新しいgoogle.maps.Markerオブジェクトを作成しています。
- このオブジェクトは、地図上に表示されるマーカーを表します。
②マーカーの位置を指定
-
position: markerLatLng
で、先程作成したgoogle.maps.LatLngオブジェクトmarkerLatLngを使用し、マーカーの位置を指定しています。
③マーカーを表示する地図オブジェクトを指定
-
map: map
で、マーカーを表示する対象の地図オブジェクトを指定しています。この地図オブジェクトは、前述のmap変数に格納されています。
5.吹き出し表示
// 変数宣言
let infoWindow = null; // InfoWindowのインスタンスを格納
const spots_location = []; // スポットの場所を格納する配列
const spots_lat = []; // スポットの緯度を格納する配列
const spots_lng = []; // スポットの経度を格納する配列
// 吹き出しの表示
let id = spots[i]['id']; // ①
spots_location[i] = spots[i]['location']; // スポットの場所(location)を配列に保存
spots_lat[i] = spots[i]['latitude']; // スポットの緯度を配列に保存
spots_lng[i] = spots[i]['longitude']; // スポットの経度を配列に保存
infoWindow = new google.maps.InfoWindow(); // 新しい情報ウィンドウを作成 // ②
①スポットの情報取得
-
let id = spots[i]['id'];
で、各スポットのIDを取得しています。 -
spots_location[i] = spots[i]['location'];
、spots_lat[i] = spots[i]['latitude'];
、spots_lng[i] = spots[i]['longitude'];
で、場所、緯度、経度を配列に保存しています。
②infoWindow = new google.maps.InfoWindow();
で、新しいgoogle.maps.InfoWindowオブジェクトを作成しています。
- これは吹き出しの内容を表示するためのものです。
6.吹き出しをクリックしたときの処理を追加
google.maps.event.addListener(marker[i], 'click', function () { // ①
infoWindow.setContent( // ②
`<a href='/posts/${id}'>${spots[i]['location']}</a>`); // マーカーに対応する情報ウィンドウを地図上に表示
infoWindow.open(map, marker[i]);
});
}
①マーカーのクリックイベントの設定
-
google.maps.event.addListener(marker[i], 'click', function () { ... }
で、各マーカーがクリックされたときの処理を設定しています。
②情報ウィンドウの内容設定
-
infoWindow.setContent(...)
で、情報ウィンドウの内容を設定しています。 -
<a href='/posts/${id}'>${spots[i]['location']}</a>
は、スポットの場所をリンクとして表示しています。リンクのURLには対応するスポットのIDが含まれています。 -
infoWindow.open(map, marker[i]);
で、対応するマーカーに紐づく情報ウィンドウを地図上に表示します。
5.終わりに
ここまでで、地図の表示まで実装できました。
間違っている点などあればご連絡いただけると助かります。