Google Maps API 學習筆記 – 1：地圖、標記、客製樣式
Tags: googlemaps, javascript, marker, api
Published: 2022-07-01 13:23:56

## 本篇大綱：

- [原來 Google Maps API 有每個月的免費額度](https://www.letswrite.tw/google-map-api-marker-custom/#%e4%b8%80%e3%80%81%e5%8e%9f%e4%be%86-google-maps-api-%e6%9c%89%e6%af%8f%e5%80%8b%e6%9c%88%e7%9a%84%e5%85%8d%e8%b2%bb%e9%a1%8d%e5%ba%a6)
- [申請 Google Maps API Key](https://www.letswrite.tw/google-map-api-marker-custom/#%e4%ba%8c%e3%80%81%e7%94%b3%e8%ab%8b-google-maps-api-key)
- [開始使用 Maps Javascript API](https://www.letswrite.tw/google-map-api-marker-custom/#%e4%b8%89%e3%80%81%e9%96%8b%e5%a7%8b%e4%bd%bf%e7%94%a8-maps-javascript-api)
- [放置多個標記](https://www.letswrite.tw/google-map-api-marker-custom/#%e5%9b%9b%e3%80%81%e6%94%be%e7%bd%ae%e5%a4%9a%e5%80%8b%e6%a8%99%e8%a8%98)
- [標記（Marker）客製化](https://www.letswrite.tw/google-map-api-marker-custom/#%e4%ba%94%e3%80%81%e6%a8%99%e8%a8%98%ef%bc%88marker%ef%bc%89%e5%ae%a2%e8%a3%bd%e5%8c%96)  
  - [Google 預設的 4 種圖案](https://www.letswrite.tw/google-map-api-marker-custom/#google-%e9%a0%90%e8%a8%ad%e7%9a%84-4-%e7%a8%ae%e5%9c%96%e6%a1%88)  
  - [直接讀一個圖檔](https://www.letswrite.tw/google-map-api-marker-custom/#%e7%9b%b4%e6%8e%a5%e8%ae%80%e4%b8%80%e5%80%8b%e5%9c%96%e6%aa%94)  
  - [marker 的另外 2 個參數](https://www.letswrite.tw/google-map-api-marker-custom/#marker-%e7%9a%84%e5%8f%a6%e5%a4%96-2-%e5%80%8b%e5%8f%83%e6%95%b8)
- [Info Windows](https://www.letswrite.tw/google-map-api-marker-custom/#%e5%85%ad%e3%80%81info-windows)
- [客製化地圖樣式](https://www.letswrite.tw/google-map-api-marker-custom/#%e4%b8%83%e3%80%81%e5%ae%a2%e8%a3%bd%e5%8c%96%e5%9c%b0%e5%9c%96%e6%a8%a3%e5%bc%8f)  
  - [night mode 地圖](https://www.letswrite.tw/google-map-api-marker-custom/#night-mode-%e5%9c%b0%e5%9c%96)  
  - [2 個重要的連結](https://www.letswrite.tw/google-map-api-marker-custom/#2-%e5%80%8b%e9%87%8d%e8%a6%81%e7%9a%84%e9%80%a3%e7%b5%90) 
  - [隱藏地圖上其他商家](https://www.letswrite.tw/google-map-api-marker-custom/#%e9%9a%b1%e8%97%8f%e5%9c%b0%e5%9c%96%e4%b8%8a%e5%85%b6%e4%bb%96%e5%95%86%e5%ae%b6)
- [隱藏地圖上 UI](https://www.letswrite.tw/google-map-api-marker-custom/#%e5%85%ab%e3%80%81%e9%9a%b1%e8%97%8f%e5%9c%b0%e5%9c%96%e4%b8%8aui)
- [本篇原始檔下載](https://www.letswrite.tw/google-map-api-marker-custom/#%e4%b9%9d%e3%80%81%e6%9c%ac%e7%af%87%e5%8e%9f%e5%a7%8b%e6%aa%94%e4%b8%8b%e8%bc%89)
- [Google Maps API 學習筆記系列](https://www.letswrite.tw/google-map-api-marker-custom/#google-maps-api-%e5%ad%b8%e7%bf%92%e7%ad%86%e8%a8%98%e7%b3%bb%e5%88%97)

---

## 原來 Google Maps API 有每個月的免費額度

之前聽到 Google Maps API 要錢，就一直沒想碰這塊，最近朋友在問，回頭去看了一下定價後，才發現官網上面寫每個月有 200 美金的免費額度。

照免費的額度表上看，因為這篇會用到的是「Maps JavaScript API」，是屬於「Dynamic Maps」這個，每個月可以載入 28000 次，超過才開始計價。

28000 次耶，一般頁面正常使用，那個流量都可以放個廣告了吧。覺得自己平常在玩的小頁面不會到這個量，就想來學一下。


![Google Maps API 定價表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08i1oqolckt1qzfnyupw.png)

Google Maps API 定價表：[https://cloud.google.com/maps-platform/pricing/sheet/?hl=zh-tw](https://cloud.google.com/maps-platform/pricing/sheet/?hl=zh-tw)


這篇筆記主要想寫的，是文件上從「Get an API Key」，一直看到「Interacting with the Map」這邊的學習記錄，一邊看一邊實作。

因為想要記下的是以後會常用到的功能，所以想看所有 Google Maps API 的話，可以直接看官方文件。

本篇參考、使用資源如下：

1. [官網 Maps Javascript API 文件](https://developers.google.com/maps/documentation/javascript/tutorial?hl=zh-tw)  
2. JS Framework：[Vue.js](https://vuejs.org/)  
3. CSS Framework：[Bootstrap4](https://getbootstrap.com/)  
4. Icon：[Eva Icons](https://akveo.github.io/eva-icons/#/)

---

## 申請 Google Maps API Key

API Key 要從 [Google Cloud Platform（GCP）](https://cloud.google.com/console/google/maps-apis/overview?hl=zh-tw) 的後台申請。

這邊新開一個專案來用，填寫完專案名稱後按確認，GCP 就會執行開新專案的動作。

![GCP上建立新專案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kfbmoxww63e26vzzhud.png)

建立完後，點選剛新增的專案，就會列出跟 Maps 相關的一堆 API：

![Map 相關 API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/njzny1ln7gco0kv5gdxc.png)

這邊用的是 Maps Javascript API，點進去後再點啟用，GCP 就可以看到了：

![確認 Maps JavaScript API 是啟用的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zo79gd7f238tste5tqdy.png)

確認完要用的 API 是啟用狀態後，接著生成一組 API Key，以及對這組 API Key 設定限制，防止有人看到你的 API Key 後，拿去偷用。

直接點啟用 API 那邊的項目，再點憑證，或是直接進入 [GCP 憑證頁面](https://console.cloud.google.com/apis/credentials) 後，就會看見要申請的區塊：

![點選 API 金鑰](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtvk6tx9m3x72vzf0rln.png)

點選 API 金鑰，會出現一個金鑰的 Key，把值 copy 下來，之後頁面在引用 JS 時，就是這樣：

```html
<script async defer  
  src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY">  
</script>
```

![取得API Key後，點選「限制金鑰」](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3aeyiw9qqemu4bcsik0e.png)

GCP 很貼心的提醒要為金鑰增加限制，點選「限制金鑰」後，會看見 4 種限制方式：

![API Key的4種限制方式](https://cdn.hashnode.com/res/hashnode/image/upload/v1655130694296/C8_CLeMfK.png)

要用哪一種就看各人了。

官方文件連結：[Get an API Key](https://developers.google.com/maps/documentation/javascript/get-api-key?hl=zh-tw)。

---

## 開始使用 Maps Javascript API

新增一個 HTML 的頁面，引用 Map JS：

```html
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"</script>
```

這邊因為有用Vue.js，所以會把後面的「`callback=initMap`」刪掉，改成 `window load` 完後再執行 `initMap()`。

> 以下寫的 code，很偷懶的直接用 ES6，如果要支援度高一點的話，請自行編譯成 ES5

初始化地圖（initMap）的 function，做 2 件事：

1. 建立地圖，設定地圖中心點  
2. 放置標記（marker）

HTML 如下（CSS Framework：Bootstrap4）：

```html
<div id="app" class="container">  
  <div class="row">  
    <div class="col">  
      <div id="map" class="embed-responsive embed-responsive-16by9"></div>  
    </div>  
  </div>  
</div>
```

JS 如下：

{% embed https://gist.github.com/letswritetw/d39fe88018acbf326981b057200f1aa1 %}

開啟頁面後，就會看到如下：


![基本 Google Maps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x50gwypclqyjryg2ql5t.png)

對，看起來就跟一般我們在用 Google Maps 差不多，畢竟只用了基本功能，想有些不一樣就要再加一些code。

---

## 放置多個標記

要放多個標記前，當然可以直接在頁面上加一個陣列，然後資料全寫在裡面。

但 Google 文件上在這部份用了比較好的做法，就是把資料收集在一個檔案上，然後 GET 進來。

之所以會寫這點，是因為他的檔案不是常見的 xxx.json，而是 xxx.geojson。

看了文件後才知道有 geojson 這格式，[維基百科](https://zh.wikipedia.org/wiki/GeoJSON) 上寫是拿來記錄地理訊息的 JSON。

參考 [Google 文件的範例](https://developers.google.com/maps/documentation/javascript/importing_data?hl=zh-tw)，把幾個點的位置存成了 map.geojson，如下：

{% embed https://gist.github.com/letswritetw/ba2477aea3aa2639e652869388250246 %}

`geometry` 裡的經緯度必填。

`properties`，看示範時很像是可以填自己客製的東西，就拿來填名稱跟地址，之後在 info windows 時會用到。

有了各地點的檔案後，就是用回圈把每個地點設成 marker，JS 如下：

{% embed https://gist.github.com/letswritetw/256523748cead02eb27fc266d3906a25 %}

開啟頁面後，看到如下：

![多個標記的 Google Maps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rty5tsay4ojok38zym0l.png)

對，看上去也跟用 [My Map](https://www.google.com/intl/zh-TW/maps/about/mymaps/) 的功能一樣，沒什麼厲害的。畢竟這也只是在基本的地圖上，多放了幾個標記而已。

接下來再加上可以用的參數，看上去就會不一樣了。

---

## 標記（Marker）客製化

對網頁上要放 Google Maps 來說，最會被企畫問到的問題就是：「標記的圖案可以改嗎？」、「標記可以改成公司的 Logo 嗎？」

Google Maps API 有提供修改標記的參數，主要有 2 個可以用：

1. 用 Google 預設的 4 種圖案  
2. 直接讀一個圖檔

### Google 預設的 4 種圖案

使用的方式很簡單，在 JS 裡，`marker` 的部份改成以下：

```javascript
var marker = new google.maps.Marker({  
  position: latLng,  
  icon: {  
    path: google.maps.SymbolPath.CIRCLE,  
    scale: 10  
  },  
  map: map  
});
```

`icon.path`，有 4 種可用，顯示出來的樣式如 Google 提供的圖表：

![https://developers.google.com/maps/documentation/javascript/symbols?hl=zh-tw#predefined](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofinil42tmiszc1xp0xf.png)

### 直接讀一個圖檔

直接讀一個圖檔，是更能達成企畫需求的方式，code 如下：

```javascript
var marker = new google.maps.Marker({  
  position: latLng,  
  icon: '圖檔的絕對路徑.png',  
  map: map  
});
```

code 很簡單，`icon` 的值直接寫入圖檔路徑就行。

這邊直接在 Eva Icons 上抓一張圖來用，code 如下：

{% embed https://gist.github.com/letswritetw/2cd5f817e9e3051381f2bd0ac8a6723d %}

### marker 的另外 2 個參數

「標記」除了自定 icon，還有另外 2 個參數可以用：

1. 可否拖拉  
2. 動態效果

可否拖拉的參數是「draggable」，動態效果是「animation」：

```javascript
let marker = new google.maps.Marker({  
  position: latLng,  
  map: this.map,  
  animation: google.maps.Animation.DROP, // DROP掉下來、BOUNCE一直彈跳
  draggable: false // true、false可否拖拉  
});
```

這一階段會看到的結果如下：

![標記（Marker）客製化](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvebdh7n1l26ej93sigo.png)

---

## Info Windows

在標記上，還有一個很特別的功能，是要用 API 才會有的，就是 Info Windows，資訊小視窗，樣式如下：

![Google Maps Info Windows](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pytizh9t8l4btnhf8msl.png)

官方文件中，Info Windows 有專門的一頁在介紹，這邊就直接製作一個範例出來。([Info Windows 官方文件](https://developers.google.com/maps/documentation/javascript/infowindows?hl=zh-tw))

在用回圈寫入 `marker` 時，就要把 Info Windows 加進去，並監聽 `click` 事件。

這邊的範例再特別寫入一個，由外面的按鈕讓 `marker` 上的 Info Windows 被打開，而不是一定要點到 `marker` 才會打開。

HTML 用 `v-for` 為每個地點加入一個按鈕，並加上 `@click` 事件：

```html
<button type="button" class="btn btn-outline-secondary"  
  v-for="f in features" @click="openInfoWindows(f.properties.id)"  
>  
  {{ f.properties.name }}  
</button>
```

JS 部份如下：

{% embed https://gist.github.com/letswritetw/ee40de4e758feb386a93e050725e62a6 %}

看到的頁面截圖如下：

![Google Maps Info Windows](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/heka06v8af2f2itdho4b.png)

---

## 客製化地圖樣式

API 除了可以做出客製標記（marker）、Info Windows 外，還可以做一個直接用 Google Maps 做不到的事，就是客製化地圖樣式。

這邊直接參考文件的示範，寫一個 night mode 的地圖，跟隱藏商家的地圖。

### night mode 地圖

在一開始建立地圖，也就是以下這段的時候：

```javascript
this.map = new google.maps.Map(document.getElementById('map'), {  
  center: location,  
  zoom: 16,  
  mapTypeId: 'terrain',  
  styles: [ /* ... */ ] // 這邊可加入客製 style  
});
```

就可以加入一個「styles」的參數，把想要的樣式給加進去了。當然，加的規則必須照著文件上的寫。([Start Styling your Map 官方文件](https://developers.google.com/maps/documentation/javascript/styling?hl=zh-tw))

這邊寫一個可以用 toggle 按鈕，切換日間 / 夜間地圖的範例：

{% embed https://gist.github.com/letswritetw/33e0244822d99934158b8d6dc35ae544 %}

以下是頁面截圖：

![Google Maps night mode demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11uqkuofctypsgl25ov3.png)

### 2 個重要的連結

這邊附上 2 個重要連結：

1. 每一個 feature、element 的說明：

<https://developers.google.com/maps/documentation/javascript/style-reference?hl=zh-tw#style-features>

2. styles 生成器：

<https://mapstyle.withgoogle.com/>

有了以上這 2 個連結，想用一些自訂的模式就比較容易了。

### 隱藏地圖上其他商家

以下附上隱藏商家的 demo，主要是覺得會有企畫提出「地圖上東西太多太干擾了想隱藏掉」、「地圖上出現其他同業了啦要刪掉」這種需求。

其實會了上面的 night mode 以後，隱藏商家就容易了，設定的 styles 比夜間模式還少，styles 上改成以下就行：

```javascript
hideStyle: [{  
  featureType: 'poi.business',  
  stylers: [{  
    visibility: 'off'  
  }]  
}]
```

頁面的截圖如下：

![Google Maps hide business](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vk065rrw6o4v58wc0gy.png)

拿掉商家後，地圖一整個乾淨很多。

---

## 隱藏地圖上 UI

Google Maps 上有一些預設的 UI，如下圖紅框：

![Google Maps 預設顯示的 UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6bydunofv3nd5pxn89qj.png)

Google Maps API 有提供參數去隱藏/顯示它們，如下：

- zoomControl: boolean  
- mapTypeControl: boolean  
- scaleControl: boolean  
- streetViewControl: boolean  
- rotateControl: boolean  
- fullscreenControl: boolean

要使用時，只要在建立地圖上加上這些參數就行了，例如：

```javascript
this.map = new google.maps.Map(document.getElementById('map'), {  
  center: location,  
  zoom: 16,  
  mapTypeId: 'terrain',  
  mapTypeControl: false  
});
```

---

## 本篇原始檔下載

Google Maps API 的官方文件有好幾頁，有很多東西可以玩，這篇是看到現在的第一階段筆記，記錄一下覺得以後會遇到的需求。

上面的原始碼整理在 Github 上了，歡迎使用：

<https://github.com/letswritetw/letswrite-google-map-api-1>

---

## Google Maps API 學習筆記系列  

1. [地圖、標記、客製樣式](https://letswrite.tw/google-map-api-marker-custom/)  
2. [在地圖上畫個日本結界](https://letswrite.tw/google-map-api-geometry/)  
3. [用熱圖（Heat Map）製作全台 12 小時雨量分佈圖](https://letswrite.tw/google-map-api-heat-map/)  
4. [Place API 自動完成地址、地點評論摘要](https://letswrite.tw/google-map-api-place-api/)
5. [抓目前位置、計算到各點距離](https://letswrite.tw/google-map-api-distance-matrix/)
6. [畫新冠肺炎分佈圖](https://letswrite.tw/google-map-api-covid/)