1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘録】Google Maps APIを使用した店舗検索

Last updated at Posted at 2024-09-25

下記2パターンの店舗検索を実装した際の備忘録

  • シンプルな店舗検索
  • マーカー クラスタを使用した店舗検索

シンプルな店舗検索

マップに複数マーカーを立てるシンプルな店舗検索。
マーカーが密集すると重なって操作性が悪いため、
店舗数が多く全国展開しているようなサービスには向かない。

公式チュートリアル

実装の流れ

  1. 地図の作成
  2. マーカーのデータ(GeoJSON)を読み込んでマーカーを立てる
  3. マーカーのクリック時の処理を追加する

地図の作成

チュートリアルにある下記のコードが、マップ作成のために必要な最小限のコード。
関数initMapをAPIのJS読み込みタグにパラメータcallbackに渡すことで、
マーカーのない必要最低限のマップが作成される。

要件に合わせて関数initMapに処理を追加していく

index.html
<!-- The div to hold the map -->
<div id="map"></div>

<script src="app.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap&solution_channel=GMP_codelabs_simplestorelocator_v1_a"></script>
app.js
function initMap() {
   // Create the map.
    const map = new google.maps.Map(document.getElementById('map'), {
        zoom: 7,
        center: { lat: 52.632469, lng: -1.689423 },
    });

}

店舗のデータを読み込んでマーカーを立てる

チュートリアルを参考に作成したGeoJSONを、関数initMap内でmap.dataに渡すことでマップにマーカーが立つ。

app.js
function initMap() {
  // Create the map.
  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 7,
    center: {lat: 52.632469, lng: -1.689423},
  });

  // Load the stores GeoJSON onto the map.
  map.data.loadGeoJson('stores.json', {idPropertyName: 'storeid'});
}

GeoJSONをファイルパスではなく変数で読み込む場合、addGeoJsonを使用する。

app.js
const stores =
{
    "type": "FeatureCollection",
    "features": [{
            "geometry": {
                "type": "Point",
                "coordinates": [-0.1428115,
                    51.5125168
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Modern twists on classic pastries. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Mayfair",
                "phone": "+44 20 1234 5678",
                "storeid": "01"
            }
        },
};

function initMap() {
  // Create the map.
  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 7,
    center: {lat: 52.632469, lng: -1.689423},
  });

  // GeoJSONを変数で渡す場合
  map.data.addGeoJson(stores);
}

マーカーのクリック時の処理を追加する

map.data.addListenerにクリックイベントを追加する。
infoWindowはマーカーの周りに表示されるポップアップで、ソースコードや表示位置などを設定できる。

app.js
function initMap() {
  // Create the map.
  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 7,
    center: {lat: 52.632469, lng: -1.689423},
  });

  // Load the stores GeoJSON onto the map.
  map.data.loadGeoJson('stores.json', {idPropertyName: 'storeid'});

  const infoWindow = new google.maps.InfoWindow();

  // Show the information for a store when its marker is clicked.
  map.data.addListener('click', (event) => {
    const category = event.feature.getProperty('category');
    const name = event.feature.getProperty('name');
    const description = event.feature.getProperty('description');
    const hours = event.feature.getProperty('hours');
    const phone = event.feature.getProperty('phone');
    const position = event.feature.getGeometry().get();
    const content = `
      <h2>${name}</h2><p>${description}</p>
      <p><b>Open:</b> ${hours}<br/><b>Phone:</b> ${phone}</p>
    `;

    infoWindow.setContent(content);
    infoWindow.setPosition(position);
    infoWindow.setOptions({pixelOffset: new google.maps.Size(0, -30)});
    infoWindow.open(map);
  });
}

マーカー クラスタを使用した店舗検索

密集したマーカーをクラスタ化した店舗検索。
店舗数が多く全国展開しているサービスでは、
マーカーのクラスタ化が必要になる場合が多い。

公式チュートリアル

チュートリアルが古いマーカーgoogle.maps.Markerを使用した例のため、
下記を参考に新しいマーカーAdvancedMarkerを使用する。

実装の流れ

  1. Marker Clustererの読み込み
  2. 地図の作成
  3. マーカー配列を読み込んでマーカーを立てる
  4. マーカーのクリック時の処理を追加する

Marker Clustererの追加

マーカーのクラスタ化するにはmarkerclustererというJSを追加で読み込む。
読み込み方法は色々あるが、下記はCDNを使用する例

index.html
<!-- The div to hold the map -->
<div id="map"></div>

<script src="https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"></script>
<script src="app.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap&solution_channel=GMP_codelabs_simplestorelocator_v1_a"></script>

地図の作成

新しいマーカーAdvancedMarkerを使用する場合、mapIdが必要になるため追加する。

app.js
function initMap() {
   // Create the map.
    const map = new google.maps.Map(document.getElementById('map'), {
        zoom: 7,
        center: { lat: 52.632469, lng: -1.689423 },
        mapId: 'MAP_ID', // AdvancedMarkerを使用する場合必須
    });
}

window.initMap = initMap;

マーカー配列を読み込んでマーカーを立てる

チュートリアルを参考に店舗の座標をまとめた配列locationsを定義し、
locationsをmapしマーカー配列markersを作成する。

古いマーカーの記述は新しいマーカーAdvancedMarkerのものに書き換える必要があるが、
チュートリアルの記法も一部古いため下記の記事を参考に修正する。

修正箇所は下記クラス名

  • google.maps.marker.AdvancedMarkerViewgoogle.maps.marker.AdvancedMarkerElement
  • google.maps.marker.PinViewgoogle.maps.marker.PinElement
app.js
function initMap() {
   // Create the map.
    const map = new google.maps.Map(document.getElementById('map'), {
        zoom: 7,
        center: { lat: 52.632469, lng: -1.689423 },
        mapId: 'MAP_ID',
    });
    
    // Create an array of alphabetical characters used to label the markers.
    const labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    // Add some markers to the map.
    const markers = locations.map((position, i) => {
        const label = labels[i % labels.length];

        // 古いマーカー
        //const marker = new google.maps.Marker({
        //  position,
        //  label,
        //});
        
        // 新しいマーカー
        const pin = new google.maps.marker.PinElement({
          scale: 1.5,  // マーカーの大きさ( 等倍: 1)
          background: '#e44631', // マーカーの色
          borderColor: '#b01500', // マーカーの輪郭の色
          glyphColor: '#b01500', // グリフの色
          // glyph: '', // グリフを非表示にする場合
        });
        
        const marker = new google.maps.marker.AdvancedMarkerElement({
          map,
          position: position,
          content: pin.element
        });
    
        return marker;
      });

  // Add a marker clusterer to manage the markers.
  // CDN用の記述に修正
  const markerCluster = new markerClusterer.MarkerClusterer({ map, markers });

}

const locations = [
  { lat: -31.56391, lng: 147.154312 },
  { lat: -33.718234, lng: 150.363181 },
  { lat: -33.727111, lng: 150.371124 },
  { lat: -33.848588, lng: 151.209834 },
  { lat: -33.851702, lng: 151.216968 },
  { lat: -34.671264, lng: 150.863657 },
  { lat: -35.304724, lng: 148.662905 },
  { lat: -36.817685, lng: 175.699196 },
  { lat: -36.828611, lng: 175.790222 },
  { lat: -37.75, lng: 145.116667 },
  { lat: -37.759859, lng: 145.128708 },
  { lat: -37.765015, lng: 145.133858 },
  { lat: -37.770104, lng: 145.143299 },
  { lat: -37.7737, lng: 145.145187 },
  { lat: -37.774785, lng: 145.137978 },
  { lat: -37.819616, lng: 144.968119 },
  { lat: -38.330766, lng: 144.695692 },
  { lat: -39.927193, lng: 175.053218 },
  { lat: -41.330162, lng: 174.865694 },
  { lat: -42.734358, lng: 147.439506 },
  { lat: -42.734358, lng: 147.501315 },
  { lat: -42.735258, lng: 147.438 },
  { lat: -43.999792, lng: 170.463352 },
];

window.initMap = initMap;

マーカーのクリック時の処理を追加する

infoWindowを定義してmakeraddListenerでイベントを追加する。

app.js
function initMap() {
   // Create the map.
    const map = new google.maps.Map(document.getElementById('map'), {
        zoom: 7,
        center: { lat: 52.632469, lng: -1.689423 },
        mapId: 'MAP_ID',
    });

    const infoWindow = new google.maps.InfoWindow({
        content: "",
        disableAutoPan: true,
    });
    
    // Create an array of alphabetical characters used to label the markers.
    const labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    // Add some markers to the map.
    const markers = locations.map((position, i) => {
        const label = labels[i % labels.length];

        // 古いマーカー
        //const marker = new google.maps.Marker({
        //  position,
        //  label,
        //});
        
        // 新しいマーカー
        const pin = new google.maps.marker.PinElement({
          scale: 1.5,  // マーカーの大きさ( 等倍: 1)
          background: '#e44631', // マーカーの色
          borderColor: '#b01500', // マーカーの輪郭の色
          glyphColor: '#b01500', // グリフの色
          // glyph: '', // グリフを非表示にする場合
        });
        
        const marker = new google.maps.marker.AdvancedMarkerElement({
          map,
          position: position,
          content: pin.element
        });
    
        // markers can only be keyboard focusable when they have click listeners
        // open info window when marker is clicked
        marker.addListener("click", () => {
          infoWindow.setContent(label);
          infoWindow.open(map, marker);
        });
        return marker;
      });

  // Add a marker clusterer to manage the markers.
  // CDN用の記述に修正
  const markerCluster = new markerClusterer.MarkerClusterer({ map, markers });

}

const locations = [
  { lat: -31.56391, lng: 147.154312 },
  { lat: -33.718234, lng: 150.363181 },
  { lat: -33.727111, lng: 150.371124 },
  { lat: -33.848588, lng: 151.209834 },
  { lat: -33.851702, lng: 151.216968 },
  { lat: -34.671264, lng: 150.863657 },
  { lat: -35.304724, lng: 148.662905 },
  { lat: -36.817685, lng: 175.699196 },
  { lat: -36.828611, lng: 175.790222 },
  { lat: -37.75, lng: 145.116667 },
  { lat: -37.759859, lng: 145.128708 },
  { lat: -37.765015, lng: 145.133858 },
  { lat: -37.770104, lng: 145.143299 },
  { lat: -37.7737, lng: 145.145187 },
  { lat: -37.774785, lng: 145.137978 },
  { lat: -37.819616, lng: 144.968119 },
  { lat: -38.330766, lng: 144.695692 },
  { lat: -39.927193, lng: 175.053218 },
  { lat: -41.330162, lng: 174.865694 },
  { lat: -42.734358, lng: 147.439506 },
  { lat: -42.734358, lng: 147.501315 },
  { lat: -42.735258, lng: 147.438 },
  { lat: -43.999792, lng: 170.463352 },
];

window.initMap = initMap;

参考

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?