---
# System prepended metadata

title: Google Map API 使用手冊

---

# 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)