0
0

GoogleMapsAPIを使用した開発1(地図の表示)

Last updated at Posted at 2023-11-02

1.はじめに

投稿された情報(緯度経度)からGooleMapsAPIを使用して地図を表示、地点間のルート検索機能、周辺情報の取得を実装したので知識の定着、復習のために記事を書きます。
一度に書くと長くなるので、4回にわけて投稿していきます。
今回はその1回目でMAP表示まで実装します。

2.環境

Ruby (2.6.4)
Rails (6.1.7)
Maps JavaScript API

3.前提条件

APIキー取得済み
投稿機能を実装している

4.実装

使用gem

Gemfile
gem 'geocoder'
gem 'gon'

テーブル構造

schema.rb
  create_table "posts", force: :cascade do |t|
    t.string "address"
    t.float "latitude"
    t.float "longitude"
  end

1.投稿された住所、地名から緯度経度を保存できるようにする

1.gemgeocoderをインストール

Gemfile
gem 'geocoder'

上記記載後bundle install

2.geocodingを行いたいカラム(今回はaddress)があるPostモデルに以下記述

app/models/post.rb
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

Gemfile
gem 'gon'

bundle installを忘れずに

2.Postモデルの投稿をデータベースから取得する

gon.posts = @postsと変数の頭にgonをつけることでjavascriptで使用できるようになります。

app/controllers/posts_controller.rb
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を使用してマップを表示させていきます

view
      <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.latitudespot.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.終わりに

ここまでで、地図の表示まで実装できました。
間違っている点などあればご連絡いただけると助かります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0