@naoki_komiya

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Google Maps APIを使って複数のマーカーを表示したい。

解決したいこと

Laravelで食べログ風アプリを作成しています。
Google Maps APIを使用して、地図上に複数のマーカーを表示したいのですが、
1つしか表示されていない状況です。
解決方法を教えてください。

発生している問題・エラー

スクリーンショット 2024-04-05 0.29.48.png

該当するソースコード

// viewファイルよりお気に入り店舗の情報を取得している
var markerData = Laravel.favorite_shops;
var marker =[];

// googleMapsAPIを持ってくるときに,callback=initMapと記述しているため、initMap関数を作成
async function initMap() {

  // welcome.blade.phpで描画領域を設定するときに、id=mapとしたため、その領域を取得し、mapに格納します。
  map = document.getElementById("map");

  async function setLocation(pos) {

    // 現在の緯度・経度を取得
    const currentLat = pos.coords.latitude;
    const currentLng = pos.coords.longitude;

    // 現在の緯度経度を代入
    let currentLocation = { lat: currentLat, lng: currentLng };

    var marker = new Array();
    // 複数のピンを作成する
    for (var i = 0; i < markerData.length; i++) {

      var place = markerData[i]['name'];

      const geocoder = new google.maps.Geocoder(); // Googlgのサーバーと通信するためのインスタンスを生成
      geocoder.geocode(
        {
          address: markerData[i]['address'], // 住所から緯度経度に変換
          region: "jp",
        },
        async function (results, status) {
      
          if (status == google.maps.GeocoderStatus.OK) {

            // 取得が成功した場合
            // 結果をループして取得します。
            for (var i in results) {
              if (results[i].geometry) {

                // 緯度を取得します。
                var lat = results[i].geometry.location.lat();
                // 経度を取得します。
                var lng = results[i].geometry.location.lng();

                map = document.getElementById("map");
                
                // オプションを設定
                opt = {
                  zoom: 11, //地図の縮尺を指定
                  center: currentLocation, //センターを取得した緯度経度に指定
                };
                
                // 地図のインスタンスを作成します。第一引数にはマップを描画する領域、第二引数にはオプションを指定
                mapObj = new google.maps.Map(map, opt);

                var markerLatLng = new google.maps.LatLng({lat: lat, lng: lng}); // 緯度経度のデータ作成  

                marker[i] = new google.maps.Marker({
                  // ピンを差す位置を決めます。
                  position: markerLatLng,
                  // ピンを差すマップを決めます。
                  map: mapObj,
                  
                });

                // marker[i]をコンソールで確認したが、正しい緯度経度が取得できている。
                console.log(marker[i]);

                // そもそも、ループを回して、検索結果にあっているものをiに入れていっているため
                // 精度の低いものもでてきてしまう。その必要はないから、一回でbreak
                break;
              }
              
            }
          } else if (status == google.maps.GeocoderStatus.ERROR) {
            alert("サーバ接続に失敗しました。");
          } else if (status == google.maps.GeocoderStatus.INVALID_REQUEST) {
            alert("リクエストが無効でした。");
          } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
            alert("リクエストの制限回数を超えました。");
          } else if (status == google.maps.GeocoderStatus.REQUEST_DENIED) {
            alert("サービスが使えない状態でした。");
          } else if (status == google.maps.GeocoderStatus.UNKNOWN_ERROR) {
            alert("原因不明のエラーが発生しました。");
          }
        }
      );
    }
  }

  // エラー時に呼び出される関数
  function showErr(err) {
    switch (err.code) {
      case 1:
        alert("位置情報の利用が許可されていません");
        break;
      case 2:
        alert("デバイスの位置が判定できません");
        break;
      case 3:
        alert("タイムアウトしました");
        break;
      default:
        alert(err.message);
    }
  }

  // geolocation に対応しているか否かを確認
  if ("geolocation" in navigator) {
    var opt = {
      "enableHighAccuracy": true,
      "timeout": 10000,
      "maximumAge": 0,
    };
    navigator.geolocation.getCurrentPosition(setLocation, showErr, opt);
  } else {
    alert("ブラウザが位置情報取得に対応していません");
  }

}

自分で試したこと

var marker[i] の中身をコンソールで確認した。
→緯度経度は正しく取得できている。

さまざまなサイトを参考にし、解決しようと試みましたが、
なかなか上手くいきませんでした。
解決方法がわかる方がいらっしゃいましたら、教えていただけますと幸いです。

0 likes

1Answer

var marker[i] の中身をコンソールで確認した。
→緯度経度は正しく取得できている

  1. 二重のforループになっていますが、どちらのfor文も変数がiになっています。
    内側のループでmaker[i]に設定していますが、内側のfor文のiを参照するので、結果として常にmaker[0]にしか設定していないのでは?

  2. 設定したmaker[]を参照する処理がありませんが、これで良いのでしょうか?

  3. そもそもですが、 var marker = new Array();を関数内で宣言しているので、marker[]はこの関数のローカル変数になっています。コードの上から3行目var marker =[];で宣言したmakerとは別な変数になっていることを理解されていますか。

0Like

Comments

  1. @naoki_komiya

    Questioner

    ご回答いただきありがとうございました。

    1. 内側のfor文の変数をjに変更し、maker[i]を設定しましたが上手く処理できませんでした。
      2.3. maker[]をコメントアウトしました。

    上記を試してみましたが、上手く動作しませんでした。
    アドバイスいただけますと幸いです。
    ※参考サイト
    https://zenn.dev/kota111/articles/dbdd1ae9a88f646c8f4c
    https://www.tam-tam.co.jp/tipsnote/javascript/post7755.html

  2. 2. 設定したmaker[]を参照する処理がありませんが、これで良いのでしょうか?

    ↑これはどう対応されたのでしょうか?
    変更後のコードの全体を貼ってください。

  3. @naoki_komiya

    Questioner

    2.については、必要かどうか分からなかったので、一旦コメントアウトして試してみました。

    // viewファイルよりお気に入り店舗の情報を取得している
    var markerData = Laravel.favorite_shops;
    // var marker =[];

    // googleMapsAPIを持ってくるときに,callback=initMapと記述しているため、initMap関数を作成
    async function initMap() {

    // welcome.blade.phpで描画領域を設定するときに、id=mapとしたため、その領域を取得し、mapに格納します。
    map = document.getElementById("map");

    async function setLocation(pos) {

    // 現在の緯度・経度を取得
    const currentLat = pos.coords.latitude;
    const currentLng = pos.coords.longitude;
    
    // 現在の緯度経度を代入
    let currentLocation = { lat: currentLat, lng: currentLng };
    
    var marker = new Array();
    // 複数のピンを作成する
    for (var i = 0; i < markerData.length; i++) {
    
      var place = markerData[i]['name'];
    
      const geocoder = new google.maps.Geocoder(); // Googlgのサーバーと通信するためのインスタンスを生成
      geocoder.geocode(
        {
          address: markerData[i]['address'], // 住所から緯度経度に変換
          region: "jp",
        },
        async function (results, status) {
      
          if (status == google.maps.GeocoderStatus.OK) {
    
            // 取得が成功した場合
            // 結果をループして取得します。
            for (var j in results) {
              
              if (results[j].geometry) {
                console.log(i);
    
                // 緯度を取得します。
                var lat = results[j].geometry.location.lat();
                // 経度を取得します。
                var lng = results[j].geometry.location.lng();
    
                // console.log(results[j]);
    
                map = document.getElementById("map");
                
                // オプションを設定
                opt = {
                  zoom: 11, //地図の縮尺を指定
                  center: currentLocation, //センターを取得した緯度経度に指定
                };
                
                // 地図のインスタンスを作成します。第一引数にはマップを描画する領域、第二引数にはオプションを指定
                mapObj = new google.maps.Map(map, opt);
    
                var markerLatLng = new google.maps.LatLng({lat: lat, lng: lng}); // 緯度経度のデータ作成  
    
                marker[i] = new google.maps.Marker({
                  // ピンを差す位置を決めます。
                  position: markerLatLng,
                  // ピンを差すマップを決めます。
                  map: mapObj,
                  
                });
    
                // marker[i]をコンソールで確認したが、正しい緯度経度が取得できている。
                // console.log(marker[i]);
    
                // そもそも、ループを回して、検索結果にあっているものをiに入れていっているため
                // 精度の低いものもでてきてしまう。その必要はないから、一回でbreak
                break;
              }
              
            }
          } else if (status == google.maps.GeocoderStatus.ERROR) {
            alert("サーバ接続に失敗しました。");
          } else if (status == google.maps.GeocoderStatus.INVALID_REQUEST) {
            alert("リクエストが無効でした。");
          } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
            alert("リクエストの制限回数を超えました。");
          } else if (status == google.maps.GeocoderStatus.REQUEST_DENIED) {
            alert("サービスが使えない状態でした。");
          } else if (status == google.maps.GeocoderStatus.UNKNOWN_ERROR) {
            alert("原因不明のエラーが発生しました。");
          }
        }
      );
    }
    

    }

    // エラー時に呼び出される関数
    function showErr(err) {
    switch (err.code) {
    case 1:
    alert("位置情報の利用が許可されていません");
    break;
    case 2:
    alert("デバイスの位置が判定できません");
    break;
    case 3:
    alert("タイムアウトしました");
    break;
    default:
    alert(err.message);
    }
    }

    // geolocation に対応しているか否かを確認
    if ("geolocation" in navigator) {
    var opt = {
    "enableHighAccuracy": true,
    "timeout": 10000,
    "maximumAge": 0,
    };
    navigator.geolocation.getCurrentPosition(setLocation, showErr, opt);
    } else {
    alert("ブラウザが位置情報取得に対応していません");
    }

    }

  4. よく見ると、ループの内側でマップを生成していますね。これが原因だと思います。
    ループさせているのは、マーカーを表示させたい複数の位置情報を得るためですよね。このループでmarkerの配列に位置情報を設定します。
    そして、マップの生成は一度だけ行えば良いはずです。

    Laravel での書き方がよく分かりませんが、以下のHTML(javascript)で複数のマーカーを表示します。これが参考になりませんか?

    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>複数のマーカーを表示</title>
        <style>
          #map {
            height: 100%;
          }
          html,
          body {
            height: 100%;
            margin: 0;
            padding: 0;
          }
        </style>
      <script>
    
    let map;
    let marker;
    let geocoder;
    
    var markerData = [
      {
        name: '東京駅',
        lat: 35.68123620000001,
        lng: 139.7671248
      }, {
        name: '品川駅',
        lat: 35.6284713,
        lng: 139.7387597
      }, {
        name: '蒲田駅',
        lat: 35.5624794,
        lng: 139.7160731
      }
    ];
    
    function initMap() {
      map = new google.maps.Map(document.getElementById("map"), {
        zoom: 11,
        center: { lat: 35.68123620000001, lng: 139.7671248 },
        mapTypeControl: false,
      });
    
      geocoder = new google.maps.Geocoder();
    
      marker = new Array();
      for (var i = 0; i < markerData.length; i++) {
        markerLatLng = new google.maps.LatLng({lat: markerData[i]['lat'], lng: markerData[i]['lng']}); // 緯度経度のデータ作成
        marker[i] = new google.maps.Marker({
          position: markerLatLng,
          map: map
        });
      }
    }
    
    window.initMap = initMap;
    
      </script>
      </head>
      <body>
        <div id="map"></div>
    
        <script
          src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap"
        ></script>
      </body>
    
    </html>
    
    map.png

Your answer might help someone💌