Google Maps Embed API & JavaScript API

前言

很多年前寫過一篇 Google Map 谷歌地圖, 這篇算是翻新版本.

 

Google Map Registration

Google Maps Platform 是整個 Google Map 的大本營. 裏面有許許多多的 Services. Embed 和 JavaScript API 只是其中的兩個.

首先, Services 不是免費的. 只是 Google 每個月有 free USD 200 塊讓你花. 可以算是間接免費.

但是申請賬戶需要綁定銀行卡哦 (以前是不需要的)

下圖是它的 Documentation

這篇的內容, 大部分都是來自 JS API 和 Embed API 文檔.

申請的部分我就不 step by step 講了. 大概有幾個東西需要弄:

1. 申請 Google Cloud (Map 屬於 Cloud 的一部分)

2. 綁卡

3. Create New Project

4. Enable Services (Maps Embed / JavaScript API)

5. 做 App Key (App Key 只有在設定的 Domain 內, 才能發請求, 它的計費也是通過 request 來計算的)

 

Google Maps Embed API

Embed Map 就是把 Map 嵌套進網站裏. 效果:

它是通過 iframe 完成的. 左上角是一個 location info. 中間有一個 drop point 就是目標地點 (通常就是公司的地址)

要製作 iframe 不需要什麼 coding. 用 Generating an iframe 就可以了.

輸入查詢, 比如公司名字 > 點擊 Looks good!

然後輸入 API Key

API 在 Cloud 裏面

接着 copy iframe 的 code, 放到要 display 的頁面區域就可以了.

Options

想配置 config 可以通過 parameters. 參考: Embedding a map

上面我們使用了 iframe generator, 但其實它就是替我們生成 parameters 而已.

下面這個是手寫的 iframe src

https://www.google.com/maps/embed/v1/place?q=place_id:ChIJcXt2BFgZ2jERY1RQlGLGTzU&zoom=10&key=your-key

通常可能需要配置的變量是: version, place_id (或者直接用 q, q stand for query), zoom, key, language. 參考: place mode

侷限

Embed API 雖然簡單, 但是也有不少侷限性.

1. 不支持 multiple location. 它只可以放一個地點. 如果公司有許多分行. 那就不夠用了.

2. marker (中間的 drop point 術語叫 marker) 沒有任何點擊事件. location info 在右上角並不顯眼. 用戶可能會點擊 marker, 但卻沒有任何反應.

而這兩點可以通過 Maps JavaScript API 來解決.

 

Google Maps JavaScript API

最終效果

一開始有 3 個 location, 點擊 location 會出現 location info.

 

Simple Map

最終效果有幾個難點, 我們先從最簡單的開始.

setup HTML

首先是 HTML 引入 Script 和一個 div 作爲 map 的渲染位置

bundle.js 是我們的 main.ts

<script src="./bundle.js" defer></script>
<script
  src="https://maps.googleapis.com/maps/api/js?key=your-key&libraries=places&callback=initMap"
  defer
></script>

這個 Script 可以直接放在 HTML 或者用 JavaScript 動態 append 出去都可以. 確保執行的順序就可以了.

有 3 個 parameters 需要注意

1. key 和 Embed API 是相同的 key

2. libraries, 由於會使用到 PlacesService 所以這裏需要 "import" 它.

3. callback, 當 Script 加載好後會調用 initMap 這個全局函數. 所以在 main.ts 我們 assign callback 方法到 window.initMap 裏.

setup JavaScript

先安裝 types 

yarn add @types/google.maps --dev

然後定義 callback

declare global {
  interface Window {
    initMap: () => void;
  }
}

window.initMap = () => {
  new google.maps.Map(document.querySelector(".map")!, {
    center: {
      lat: 1.284491,
      lng: 103.845951,
    },
    zoom: 10,
  });
};

效果

這個就是最簡單的 map 了.

center 和 zoom 是一定要 set 的, 不然什麼都看不見哦.

 

Scolling Problem

默認情況下, 在 map 上 scrolling 的效果是 zoom. 這個體驗不一定是期望的, 用戶可能是想 scroll 頁面, 只是鼠標碰巧放在 map 上面.

解決方法是在 config 添加 gestureHandling

new google.maps.Map(document.querySelector(".map")!, {
  gestureHandling: "cooperative",
});

效果

當用戶不小心 scroll 到的, 不會有 zoom 的效果, 同時會出現提示. 用 zoom 請使用 ctrl + scroll.

 

Custom Map Style

上面最終效果的主題顏色並不是默認的. 它是灰色系的.

主題可以到這裏 mapstyle.withgoogle.com, 它有 2 種方法.

1. 用 Cloud, 這樣代碼就不需要包含 styling 邏輯. 它在一開始的 Script API 就會鏈接到 Cloud 設置好的 Styling.

2. 下載 JSON 文件.

下面就是最終效果的配置

 

它默認的 labels.icon 會把 Singapore 給 hide 起來, 所以我修改了它的 JSON file.

最後把 style 掉進去就可以了.

new google.maps.Map(document.querySelector(".map")!, {
  styles: [], // <-- put json array here
});

 

Places Library

參考: Docs – Places Library 

它是一個 service, 可以通過 query 找到 place info. 比如 query=my-company-name

它會返回座標, 地址, reviews count, reviews rating, opening hours 等等.

它有許多方法可以用來 search, 但目前只用到 Find Place from Query 就足夠了. 

代碼

const map = new google.maps.Map(document.querySelector(".map")!);
const service = new google.maps.places.PlacesService(map);
service.findPlaceFromQuery(
  {
    query: "Coolman Aircon",
    fields: [
      "place_id",
      "geometry",
      "name",
      "formatted_address",
      "rating",
      "user_ratings_total",
    ],
  },
  (results, status) => {
    if (status === google.maps.places.PlacesServiceStatus.OK) {
      console.log("callback", results![0]);
    }
  }
);

還有什麼可用的 fields 可以參考這裏,

效果

 

分別對應了 info window 需要的內容

name, formatted_address, rating, user_ratings_total

view larger map 需要 place_id

directions 則是 name + formatted_address

geometry 是給 marker 用的

 

Marker

const map = new google.maps.Map(document.querySelector(".map")!, {
  center: {
    lat: 1.284491,
    lng: 103.845951,
  },
  zoom: 10,
});
new google.maps.Marker({
  map,
  position: {
    lat: 1.284491,
    lng: 103.845951,
  },
});

position 就拿上面 place info 的 geometry.

Marker Styling

參考: 

Docs – Markers

Docs – Custom Markers

默認的 marker 是紅色的. 通常和網站主題顏色不搭.

有 2 種替換方式.

1. 用 svg path. 這個挺難搞的, 它長這樣.

首先那個 path 可以從 .svg file 裏面抄出來. 如果有多個 path 就用逗號分割, 然後拼接到後面就可以了.

fillColor 控制顏色, fillOpacity 默認是 0 哦. 如果要顏色記得配置

stroke 是控制 border 

最難搞的是 icon 的 size. 它只能通過 scale 去控制大小. 然後 origin 老是抓不準. 所以會一直跑位. 估計是修改配置 anchor 或者 origin 之類的.

但我已經沒有耐性玩了. 所以還是用第 2 種方法吧.

2. 用 .svg 圖片

提前把 svg 圖片弄好. fill, width, heigth 都 set 好. 然後直接 link 就可以了.

不嫌棄的話, 也可以用 Google 提供的 icon: Google Earth/Maps Icons

 

Zoom to All Marker

上面 create map 的時候, 我們 hardcode 了 center 和 zoom. 這樣是不 ok 的.

正確的做法是依據所有的 marker 調整 zoom, 儘可能的顯示所有 markers.

參考: Stack Overflow – Auto-center map with multiple markers in Google Maps API v3

const map = new google.maps.Map(document.querySelector(".map")!, {
  maxZoom: 10, // 避免 auto zoom 太大
});
const bounds = new google.maps.LatLngBounds();
bounds.extend({
  // 收集 marker 座標 1
  lat: 1.284491,
  lng: 103.845951,
});
bounds.extend({
  // 收集 marker 座標 2
  lat: 1.284491,
  lng: 103.845951,
});
map.fitBounds(bounds); // 調整 map zoom 和 center

主要用到了 LatLngBounds 和 fitBounds 方法. 擔心自動 zoom 太大的話, 可以 set 一個 maxZoom.

 

Info Window

參考: Docs – Info Windows

const map = new google.maps.Map(document.querySelector(".map")!, {
  center: {
    lat: 1.284491,
    lng: 103.845951,
  },
  zoom: 10,
});

const marker = new google.maps.Marker({
  position: {
    lat: 1.284491,
    lng: 103.845951,
  },
  map,
  clickable: true,
});

const infowindow = new google.maps.InfoWindow({
  content: `<h1 class="my-h1">Hello World</h1>`,
});

marker.addListener("click", () => {
  infowindow.open({
    anchor: marker,
    map,
    shouldFocus: false,
  });
});

assign Raw HTML 給 InfoWindow.content 就可以了. CSS Selector 可以直接 select 到 .map .my-h1

所以 apply style 不是問題. (以前好像是不可以的, 在 Stack Overflow 有看到以前的許多提問)

 

Google Map Link

最後說一下 reviews, view larger map, directions 的 link

參考:

Stack Overflow – Link to Google Maps Directions using place_id

Stack Overflow – Getting Google Maps link from place_id

Docs – directions

reviews link

const reviewsLink = `https://search.google.com/local/reviews?placeid=${data.placeId}`

placeId 到 place info 裏拿.

view larger map link

const viewLargerMapLink = `https://maps.google.com/maps?q=place_id:${data.placeId}`

directions link

const directionsLink = `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(
        `${data.name},${data.address}`
      )}`

direction 沒有用到 placeId, 反而是用到了 name 和 formatted_address

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章