# 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. 瀏覽器展示成果。

## 初始化地圖相關設定(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. 瀏覽器展示成果 ( 可依需求再加上樣式 ) 。

:::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. 瀏覽器展示成果。

:::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. 瀏覽器展示成果。

:::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。


將縮放數值顯示不同座標與資訊內容的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. 瀏覽器展示成果。


