# Google Map API 使用手冊 ## 什麼是 Google Map API >「Google 地圖 API」可讓您利用 JavaScript 將「Google 地圖」嵌入自己的網頁。此 API 透過多種服務提供一些公用程式,以操控地圖 (如同 http://maps.google.com 網頁上所示),並新增地圖內容,能讓您在網站上建立強大的地圖應用程式。——[Google 地圖 API 的使用方法](https://johnisacoolboy.pixnet.net/blog/post/89324684) ## 開始使用 1. 在index.html加入,地圖會顯示在這個標籤裡。 ```html <div id="map"></div> ``` \ 2. 再加上這行引用,請寫在所有script的最上層。 ```html <script async defer src="https://maps.googleapis.com/maps/api/js?key=your_key&libraries=places,drawing,geometry&v=3&callback=initMap"> </script> ``` \ 3. 在```<body>```插入```<script>```成對標籤,並寫入```function initMap()```。 ```javascript var map; function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: {lat: 25.04, lng: 121.512}, zoom: 18 }); } ``` \ 4. 新增index.css,寫入以下樣式: ```css= html, body { height: 100%; margin: 0; padding: 0; } ``` :::info 記得一定要寫出height,才會看到地圖出現在網頁上。 ::: \ 5. 瀏覽器展示成果。 ![](https://i.imgur.com/0hQaS1g.png) ## 初始化地圖相關設定(initMap) 1. 修改initMap() ```javascript function initMap() { const directionsService = new google.maps.DirectionsService(); // 載入路線服務 const directionsRenderer = new google.maps.DirectionsRenderer( { map: map, polylineOptions: { strokeColor: '#6224BF', strokeOpacity: 0.8, strokeWeight: 8, }, suppressMarkers: true, // 隱藏座標 draggable: true // 拖曳路線 } ); map = new google.maps.Map(document.getElementById("map"), { center:new google.maps.LatLng(24.114128, 120.61554), // 地圖的起始顯示位置 zoom: 20, mapTypeControl: false, // 街景 streetViewControl: false // 地圖樣式 // 上面兩個要關掉,避免而外收費。 }); directionsRenderer.setMap(map); // 加入地圖圖層 const onChangeHandler = function() { vehicleRouteMap(directionsService, directionsRenderer); }; document.getElementById("go").addEventListener("change", onChangeHandler); // 行車路線的起始點。 document.getElementById("fin").addEventListener("change", onChangeHandler); // 行車路線的目的地。 document.getElementById("showBtn").addEventListener("click", () => { vehicleRouteMap(directionsService, directionsRenderer); // 呼叫行車路線 }); } ``` 一 其他補充 - **polylineOptions**:對座標與行車路線外觀與顏色進行改變。 | 參數名稱 | 代表意思 | | ------------- | ------------- | | fillColor | 簡單多邊形 (Simple Polygon) 覆蓋區域顏色 | | strokeColor | 行車路線線條顏色 | | strokeOpacity | 行車路線線條透明度,數值越低透明越高,反之。 | | strokeWeight | 行車路線線條寬度,數值越低線條越細,反之。 | | 參數名稱 | 代表意思 | | ------------- | ------------- | | suppressMarkers | 隱藏座標 | | draggable | 是否可以拖曳,更改行車路線。 | - **google.maps.Map**:預設載入地圖時的相關設定,會寫在這裡。 | 參數名稱 | 代表意思 | | ------------- | ------------- | | center | 地圖預設出現的經緯度位置,有很多種不同的寫法,也可以寫成:{lat:24.0861162, lng: 120.6933002}這種格式。| | zoom | 載入地圖後,預設的縮放值。 | | mapTypeControl | 街景服務。 | | streetViewControl | 地圖樣式。 | | setMap | 加入地圖圖層。 | :::danger 注意mapTypeControl和streetViewControl要關閉(false),避免被而外收取費用。 ::: ## 標示座標點(Marker)與製作資訊視窗(InfoWindow) 1. 在最外圈宣告全域變數```markers```與```infoWindows``` ```javascript var markers = []; var infoWindows = []; ``` - ```markers``` 用來儲存座標點。 - ```new google.maps.Marker``` 儲存座標的資訊視窗內容。 \ 2. 新增加```markWaypointMap```的function。 ```javascript function markWaypointMap() { // 載入座標和資訊視窗 marker_config.forEach(function(e,i){ markers[i] = new google.maps.Marker(e); markers[i].setMap(map); infoWindows[i] = new google.maps.InfoWindow({ content: "<table id='mapTable' cellspacing='0'>\ <thead><tr><th colspan='2'>座標資訊</th></tr></thead>\ <tr><td>路名一</td><td>" + markers[i].name + "</td></tr>\ <tr><td>地址一</td><td>" + markers[i].site + "</td></tr>\ <tr><td>經度一</td><td>" + markers[i].position.lat() + "</td></tr>\ <tr><td>緯度一</td><td>" + markers[i].position.lng() + "</td></tr>\ </table>", disableAutoPan: true // 設置爲true時可禁用自動平移功能 }); }); // 自訂座標,顯示資訊視窗。 marker_config.forEach(function(e,i) { markers[i].addListener('click', function() { infoWindows[i].open(map, markers[i]); }); }); // 點擊跳出顯示資訊視窗。 } ``` - ```new google.maps.Marker```根據**e**內容產生座標點。 - ```new google.maps.InfoWindow```根據**content**內容產生資訊視窗。 \ 3. 在initMap()加入,```markWaypointMap()```呼叫函式。 ```javascript markWaypointMap() // 呼叫座標和資訊視窗 ``` \ 4. 瀏覽器展示成果 ( 可依需求再加上樣式 ) 。 ![](https://i.imgur.com/q7PyBL5.png) :::info [Marker 官方網站](https://developers.google.com/maps/documentation/javascript/markers) ::: :::info [infowindows 官方網站](https://developers.google.com/maps/documentation/javascript/infowindows) ::: ## 標記叢集(MarkerClusterer) 1. 新增加```zoomInOutMap```的function。 ```javascript function zoomInOutMap() { const markerCluster = new markerClusterer.MarkerClusterer({ markers, map }); // 當座標在一起時,改用Marker Clustering(標記叢集)。 } ``` - ```markerClusterer.MarkerClusterer```管理markers製造出標記叢集。 2. 在initMap()加入,```zoomInOutMap()```呼叫函式。 ```javascript zoomInOutMap() // 呼叫zoomInOutMap ``` \ 3. 瀏覽器展示成果。 ![](https://i.imgur.com/Cv0p3Uo.png) :::info [MarkerClusterer 官方網站](https://developers.google.com/maps/documentation/javascript/marker-clustering) ::: ## 畫行車路線(setDirections) 1. 在全域變數宣告```marker_config```,用來儲存經過點,行車路線會經過這些座標點。 ```json var marker_config = [ { "id": 1, "name": "台灣大道一段", "site": "400台中市中區台灣大道一段1號鐵鹿大街A10", "type": "Point", "position": { lat: 24.1372369, lng: 120.68687 } }, { "id": 2, "name": "台灣大道一段", "site": "400台中市中區台灣大道一段1號", "type": "Point", "position": { lat: 24.1370597, lng: 120.6869718 } }, { "id": 3, "name": "台灣大道一段", "site": "400台中市中區台灣大道一段1號B3櫃位", "type": "Point", "position": { lat: 24.1373346, lng: 120.6872849 } }, { "id": 4, "name": "新民街", "site": "401台中市東區新民街88號", "type": "Point", "position": { lat: 24.137648, lng: 120.686498 } }, { "id": 5, "name": "復興路四段", "site": "401台中市東區復興路四段186號", "type": "Point", "position": { lat: 24.136575, lng: 120.6862517 } }, { "id": 6, "name": "公園東路", "site": "401台中市東區公園東路150號", "type": "Point", "position": { lat: 24.1397534, lng: 120.683731 } }, { "id": 7, "name": "自由路二段", "site": "404台中市北區自由路二段湖心亭", "type": "Point", "position": { lat: 24.1397534, lng: 120.683731 } }, { "id": 8, "name": "南京路", "site": "4F, No. 66號南京路東區台中市401", "type": "Point", "position": { lat: 24.1361803, lng: 120.6883141 } }, { "id": 9, "name": "樂業一路", "site": "401台中市東區樂業一路79號", "type": "Point", "position": { lat: 24.1348453, lng: 120.6907701 } }, { "id": 10, "name": "林森路", "site": "403台中市西區林森路100巷", "type": "Point", "position": { lat: 24.1223663, lng: 120.6662814 } }, { "id": 11, "name": "民生路", "site": "40358台中市西區民生路368巷2弄12號", "type": "Point", "position": { lat: 24.1319946, lng: 120.6610709 } }, { "id": 12, "name": "興大路", "site": "402台中市南區興大路145號", "type": "Point", "position": { lat: 24.1218507, lng: 120.6742067 } }, { "id": 13, "name": "忠孝路", "site": "402台中市南區忠孝路", "type": "Point", "position": { lat: 24.1292282, lng: 120.6741345 } }, { "id": 14, "name": "育德路", "site": "404台中市北區育德路2號", "type": "Point", "position": { lat: 24.1507654, lng: 120.6792589 } }, { "id": 15, "name": "館前路", "site": "404台中市北區館前路1號", "type": "Point", "position": { lat: 24.1417558, lng: 120.6627565 } }, { "id": 16, "name": "文昌東十一街", "site": "406台中市北屯區文昌東十一街14巷1號", "type": "Point", "position": { lat: 24.1437317, lng: 120.677408 } } ]; ``` 2. 新增加```vehicleRouteMap```的function。 ```javascript function vehicleRouteMap(directionsService, directionsRenderer) { // 行車路線 const waypoint = []; for (let i = 0; i < marker_config.length; i++) { waypoint.push({ location: marker_config[i].position, stopover: true }); } // 將經過點存入waypoint var request = { origin: document.getElementById("go").value, // 出發點 destination: document.getElementById("fin").value, // 目的地 waypoints: waypoint, // 經過點 optimizeWaypoints: true, // 使用更有效的順序重新排列waypoints來優化 travelMode: 'DRIVING' // 開車 } // 設定出發點與目的地的座標和移動方式 directionsService.route(request) .then((response) => { directionsRenderer.setDirections(response); }).catch((e) => window.alert("status not 200!")); // 根據request條件,畫行車路線。 } ``` - ```waypoint```將marker_config的座標位置儲存。 - ```optimizeWaypoints``` 指定使用提供的路線waypoints可以通過以更有效的順序重新排列航點來優化。如果是true ,方向服務將waypoints 在waypoint_order字段中返回重新排序的內容 一 [[官方介紹]](https://developers.google.com/maps/documentation/javascript/directions)。 一 ```travelMode``` 補充 | 參數名稱 | 代表意思 | | ------------- | ------------- | | BICYCLING | 起點到終點的移動方式為**腳踏車** | | DRIVING | 起點到終點的移動方式為**開車** | | WALKING | 起點到終點的移動方式為**走路** | | TRANSIT | 起點到終點的移動方式為**轉運** | 3. 在initMap()加入,```vehicleRouteMap()```呼叫函式。 ```javascript vehicleRouteMap() // 呼叫行車路線 ``` \ 4. 瀏覽器展示成果。 ![](https://i.imgur.com/m9kRuhN.png) :::info [directions 官方網站](https://developers.google.com/maps/documentation/javascript/examples/directions-travel-modes) ::: ## 根據zoom縮放呈現不同marker個數 1. 因客戶需求在不同的縮放數值(getZoom()),需呈現**不同的marker**數量,伴隨的資訊視窗顯示內容也不同,因此會在原先的**zoomInOutMap()** function加入判斷式和新增兩個json檔案。 2. 新增 10.json 和 16.json。 ![](https://i.imgur.com/aimfozk.png) ![](https://i.imgur.com/ZlgpluW.png) 將縮放數值顯示不同座標與資訊內容的json data個別存到json檔案。 \ 3. 新增function zoomInOutMarkerMap(),讀取10.json 與 16.json資料,標記座標與產生資訊視窗。 ```javascript function zoomInOutMarkerMap(jsonData) { $.getJSON( jsonData, function( data ) { data.data.forEach(function(e,i){ markers[i] = new google.maps.Marker({ position: { lat: data.data[i].latitude, lng: data.data[i].longitude }, animation: google.maps.Animation.DROP }); markers[i].setMap(map); infoWindows[i] = new google.maps.InfoWindow({ content: "<table id='mapTable' cellspacing='0'>\ <thead><tr><th colspan='2'>座標資訊</th></tr></thead>\ <tr><td>編號一</td><td>" + data.data[i].plateNumber + "</td></tr>\ <tr><td>路名一</td><td>" + data.data[i].direction + "</td></tr>\ <tr><td>經度一</td><td>" + data.data[i].latitude + "</td></tr>\ <tr><td>緯度一</td><td>" + data.data[i].longitude + "</td></tr>\ </table>", disableAutoPan: true // 設置爲true時可禁用自動平移功能 }); }); // 自訂座標,顯示資訊視窗。 data.data.forEach(function(e,i) { markers[i].addListener('click', function() { infoWindows[i].open(map, markers[i]); }); }); // 點擊跳出顯示資訊視窗。 }); } ``` 4. 新增function deleteMarkersMap(),用來清空上次的座標標記。 ```javascript function deleteMarkersMap() { for (let i = 0; i < markers.length; i++) { markers[i].setMap(null); } markers = []; }; ``` 5. 修改function zoomInOutMap()內容。 ```javascript function zoomInOutMap() { // 縮放地圖時,改變座標狀態。 map.addListener("zoom_changed", () => { $('#zoom').text(""); $('#zoom').append("目前縮放數值: " + map.getZoom()); // 左上方加入縮放數值顯示。 let originalNum = true, tenNum = true, sixNum = true; tenNum = false, sixNum = false, originalNum = false; /* 當zoom縮放改變時,將三個Num都改成false ,這樣當zoomValue條件成立,也不會重複標記。 */ if ( map.getZoom() == 10 ) { zoomValue = 10; tenNum = true; } else if ( map.getZoom() == 16 ) { zoomValue = 16; sixNum = true; } else if (map.getZoom() > 16){ zoomValue = 20; originalNum = true; } if ((zoomValue == 10)&&(tenNum == true)) { deleteMarkersMap() // 呼叫清空上次的座標 zoomInOutMarkerMap("/js/10.json") // 呼叫10.json 與 16.json 標記座標用 } else if ((zoomValue == 16)&&(sixNum == true)) { deleteMarkersMap() // 呼叫清空上次的座標 zoomInOutMarkerMap("/js/16.json") // 呼叫10.json 與 16.json 標記座標用 } else if ((zoomValue == 20)&&(originalNum == true)) { deleteMarkersMap() // 呼叫清空上次的座標 markWaypointMap() } }); // 當zoom的數值改變時,觸發條件式。 $.getJSON( "/js/response_1646112019728.json", function( data ) { // 這條$.getJSON一定得加。 markerCluster = new markerClusterer.MarkerClusterer({ markers, map }); // 如果沒有顯示出Clustering,可以檢查markers有沒有值。 }); // 當座標在一起時,改用Marker Clustering(標記叢集)。 } ``` - 條件設定在當.getZoom()為 10 或者是 16 時,function裡的條件式會重新判斷,呼叫哪個function做重新標記的動作以及清空上次的標記。 6. 瀏覽器展示成果。 ![](https://i.imgur.com/g6YgVLN.png) ![](https://i.imgur.com/Tnu0mzV.png) ![](https://i.imgur.com/ldI0TNh.png)