API Key
Maps JavaScript API 會用到
可以限制Key的
- 使用的API 權限,如Geocoding API
- 平台使用,如限制IP、網站、Android APP、iOS APP
簽章私鑰
Map Static API 會用到
如果是一次性需求,可以使用官方的小工具;如果需要動態產生簽名,需要從server side 簽名,官方有提供常見語言的範例
官方強烈建議加上簽章,如果每日要求超過 25,000 個,就必須提供 API 金鑰和數位簽章
Maps JavaScript API
載入Maps JavaScript API
1<script>
2 (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
3 key: "YOUR_API_KEY",
4 v: "weekly",
5 // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
6 // Add other bootstrap parameters as needed, using camel case.
7 });
8</script>
載入地圖
1const { Map } = await google.maps.importLibrary("maps");
2const map = new Map(document.getElementById("map"), {
3 zoom: 18, // 地圖縮放等級
4 center: { lat: 43.773145, lng: 11.2559602 }, // 地圖中心
5});
可以設置地圖類型mapTypeId
:
- 道路地圖(預設)
- 衛星影像
- 道路+衛星 混合
- 地形
標記marker
1const marker = new google.maps.Marker({
2 position: { lat: 43.7731426, lng: 11.2456317 }, // 標記的位置
3 map,
4 title: "Hello World!", // 游標懸停時顯示的文字
5});
資訊視窗InfoWindow
1const infowindow = new google.maps.InfoWindow({
2 content: '<div><h1>聖母百花大教堂</h1>位於義大利<a href="https://zh.wikipedia.org/wiki/佛羅倫斯">佛羅倫斯</a>的一座天主教堂</div>',
3});
4infowindow.open({anchor: marker, map}); // 配合marker顯示在地圖上
事件event
地圖可以監聽事件,如點擊、游標移動等
範例:監聽點擊事件並取得經緯度
1map.addListener("click", (mapsMouseEvent) => {
2 console.log(mapsMouseEvent.latLng.toJSON());
3});
上面的latLng.toJSON()印出來長這樣:
1{
2 "lat": 23.373429728008887,
3 "lng": 6.3121497631073
4}
Geocoding API
反向地理編碼
使用 經緯度 取得地理資訊
取得的地理資訊會是一個array,從最相符到最不相符排序
範例:監聽點擊事件並取得經緯度,再用經緯度取得地理資訊
1map.addListener("click", (mapsMouseEvent) => {
2 geocoder
3 .geocode({ location: mapsMouseEvent.latLng })
4 .then((response) => {
5 if (response.results[0]) {
6 console.log(response.results[0]);
7 } else {
8 window.alert("No results found");
9 }
10 })
11 .catch((e) => window.alert("Geocoder failed due to: " + e));
上面的response.results[0]印出來長這樣:
1 {
2 "address_components": [
3 {
4 "long_name": "臺北車站(忠孝)[雙層巴士]",
5 "short_name": "臺北車站(忠孝)[雙層巴士]",
6 "types": [
7 "establishment",
8 "point_of_interest",
9 "transit_station"
10 ]
11 },
12 {
13 "long_name": "中正區",
14 "short_name": "中正區",
15 "types": [
16 "administrative_area_level_2",
17 "political"
18 ]
19 },
20 {
21 "long_name": "台北市",
22 "short_name": "台北市",
23 "types": [
24 "administrative_area_level_1",
25 "political"
26 ]
27 },
28 {
29 "long_name": "台灣",
30 "short_name": "TW",
31 "types": [
32 "country",
33 "political"
34 ]
35 },
36 {
37 "long_name": "100",
38 "short_name": "100",
39 "types": [
40 "postal_code"
41 ]
42 }
43 ],
44 "formatted_address": "100台灣台北市中正區臺北車站(忠孝)[雙層巴士]",
45 "geometry": {
46 "location": {
47 "lat": 25.04644,
48 "lng": 121.517189
49 },
50 "location_type": "GEOMETRIC_CENTER",
51 "viewport": {
52 "south": 25.0450910197085,
53 "west": 121.5158400197085,
54 "north": 25.0477889802915,
55 "east": 121.5185379802915
56 }
57 },
58 "place_id": "ChIJkYopX3KpQjQRFWVH5PyqOSM",
59 "plus_code": {
60 "compound_code": "2GW8+HV 台灣台北市中正區黎明里",
61 "global_code": "7QQ32GW8+HV"
62 },
63 "types": [
64 "establishment",
65 "point_of_interest",
66 "transit_station"
67 ]
68 }
- place_id:地點專屬ID,如商家、地標等都會有place_id,並且可能隨時間改變。參考官方文件
- formatted_address:人類可讀地址
- geometry:經緯度、可視區域等
Map Static API
地圖靜態圖片連結
1https://maps.googleapis.com/maps/api/staticmap?parameters
常用parameters:
- key:API key,必填
- signature:數位簽章
- center:圖片中心,格式為
緯度,精度
- zoom:縮放等級
- size:圖片尺寸
- format:圖片格式
- scale:影響回傳圖片的像素等級,可用值為1或2
- markers:一或多組mark
Map URLs
取得某座標和地址的連結
總共有四種格式
- 搜尋:顯示特定地點圖釘的地圖
- 路線
- 顯示地圖:不含標記或路線的地圖
- 街景服務
搜尋
1https://www.google.com/maps/search/?api=1¶meters
parameters:
- query:可以為地點名稱、地址或經緯度
- query_place_id:如果只有經緯度沒有place id,則不會在側邊面板顯示地點資訊(如商家、地標等)
費用
每月提供 $200 美元的抵免額 一項產品可能會有多個費率,不同的 SKU(如Maps JavaScript API 的地圖和街景費用不同) SKU 是按用量分級計費,分為三個級別:
- 0–100,000 次
- 100,001–500,000 次
- 500,001 次以上
費用計算方式:SKU 用量 x 每次使用單價
- Geocoding API 計費(取得地址等資訊)
0–100,000 次 | 100,001–500,000 個 | 500,000 個以上 |
---|---|---|
每個 0.005 美元(每 1,000 個 5.00 美元) | 每個 0.004 美元(每 1,000 個 4.00 美元) | 請https://cloud.google.com/contact-maps?hl=zh-tw洽詢高用量定價資訊 |
- Maps Static API 計費(靜態圖片)
0–100,000 次 | 100,001–500,000 個 | 500,000 個以上 |
---|---|---|
每次 0.002 美元(每 1,000 次 2.00 美元) | 每次 0.0016 美元(每 1,000 次 1.60 美元) | 請https://cloud.google.com/contact-maps?hl=zh-tw洽詢高用量定價資訊 |
- Maps JavaScript API 計費(載入地圖、取得經緯度)
Static Maps 計費
0–100,000 次 | 100,001–500,000 次 | 500,000 次以上 |
---|---|---|
每次 $0.007 美元(每 1,000 次 $7.00 美元) | 每次 $0.0056 美元(每 1,000 次 $5.60 美元) | 請https://cloud.google.com/contact-maps?hl=zh-tw洽詢高用量定價資訊 |
- Maps URLs(取得某座標和地址的連結):不計費
費用計算器: https://mapsplatform.google.com/pricing/?hl=zh-tw
範例
顯示地圖,點擊地圖上的一點後,console顯示三個連結,分別是:
- 靜態地圖連結
- 地址連結
- 地址連結,含 place_id,會找點擊的地點最近的有place_id的點,因此可能不準確
index.html
1<html>
2 <head>
3 <title>Event Click LatLng</title>
4 <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
5
6 <link rel="stylesheet" type="text/css" href="./style.css" />
7 <script type="module" src="./index.js"></script>
8 </head>
9 <body>
10 <div id="map"></div>
11
12 <!-- prettier-ignore -->
13 <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
14 ({key: "YOUR_API_KEY", v: "weekly"});</script>
15 </body>
16</html>
style.css
1#map {
2 height: 100%;
3}
4html,
5body {
6 height: 100%;
7 margin: 0;
8 padding: 0;
9}
index.js
1var APIKey = 'YOUR_API_KEY';
2var marker;
3
4async function initMap() {
5 // Request needed libraries.
6 const { Map } = await google.maps.importLibrary("maps");
7 const geocoder = new google.maps.Geocoder();
8 const map = new Map(document.getElementById("map"), {
9 zoom: 18,
10 center: { lat: 43.773145, lng: 11.2559602 },
11 });
12 // Create the initial InfoWindow.
13 let infoWindow = new google.maps.InfoWindow();
14
15 // Configure the click listener.
16 map.addListener("click", (mapsMouseEvent) => {
17 console.log(mapsMouseEvent.latLng.toJSON());
18 geocoder
19 .geocode({ location: mapsMouseEvent.latLng })
20 .then((response) => {
21 if (response.results[0]) {
22 console.log(response.results[0]);
23 // map.setZoom(11);
24
25 if (marker) {
26 marker.setPosition(mapsMouseEvent.latLng);
27 } else {
28 marker = new google.maps.Marker({
29 position: mapsMouseEvent.latLng,
30 map: map,
31 });
32 }
33
34 infoWindow.setContent(response.results[0].formatted_address);
35 infoWindow.open(map, marker);
36
37 const center = `${mapsMouseEvent.latLng.lat()},${mapsMouseEvent.latLng.lng()}`;
38 const picture = `http://maps.googleapis.com/maps/api/staticmap?center=${center}&zoom=${map.getZoom()}&size=800x600&markers=${center}&scale=2&format=jpeg&key=${APIKey}`;
39
40 console.log(picture);
41
42 var url = `https://www.google.com/maps/search/?api=1&query=${center}`;
43 console.log(url);
44 if (response.results[0].place_id) {
45 url += `&query_place_id=${response.results[0].place_id}`;
46 console.log(url);
47 }
48 } else {
49 window.alert("No results found");
50 }
51 })
52 .catch((e) => window.alert("Geocoder failed due to: " + e));
53 });
54}
55
56initMap();