# Leaflet新手村
> 撰寫於 2021/05
> 萌新專用使用教學,讓我們來歡樂的戳戳史萊姆吧(๑╹ヮ╹๑)ノ
[TOC]
###### tags: `技術文件`
## leaflet官方介紹
* [官方網站](https://leafletjs.com/)
* 於 2020/09/04 釋出 Leaflet 1.7.1版本。
* 開源的 Javascript 函式庫。
* 對行動裝置友善的互動地圖。
* 檔案大小只有 39kb。
* 有很多擴充插件。
* 齊全的 [API文檔](https://leafletjs.com/reference-1.7.1.html)和[易讀的原始碼](https://github.com/Leaflet/Leaflet)。
* 最重要的是,官方提供簡單易懂的一些[基本使用教學文](https://leafletjs.com/examples.html),讓你可以輕鬆上手(ゝ∀・)╭☆
### Docs&Plugin 使用訣竅
> 只講我有些許了解或是使用過的部分,如未來有使用到其他功能,會再補充。
#### Tile & image layers有哪些地圖資源可以用呢?
> 以下介紹如何找到不同的地圖資源。
1. 官網點選 ==Plugins==

2. 點選 Tile & image layers 下方的 ==Basemap providers==

3. 可以看到很多不同的地圖,我們就選 ==leaflet-providers==來看看吧~

4. 打開 ==leaflet-providers==頁面,點選 ==右邊連結==

5. 就可以看到 L.tileLayer 可以使用的不同地圖資料囉!

## Vue leaflet介紹
* [官方網站](https://vue2-leaflet.netlify.app/)
* 完整的文件。
* 大多數的leaflet功能都能用 Vue的方式來使用。
* 豐富的插件生態系。
### 如何安裝
> 只介紹我有用的安裝方式,官網有全部的可使用方式 [所有安裝方式&使用方法](https://vue2-leaflet.netlify.app/quickstart/#cdn)
> 還不熟悉看官方文件的萌新,大多數套件和框架,都會有完整的介紹如何安裝和基本使用方式;今天如果接觸到自己不熟悉的套件和框架,建議先從官方的使用說明開始,或是找一個與自己想做的功能類似的範例,下載下來使用和研讀。 :female_mage:
1. NPM
```sh=
npm install leaflet vue2-leaflet --save
```
2. 用 webpack全域註冊自己想要用的 components,[全部 Components頁面](https://vue2-leaflet.netlify.app/components/LTileLayer.html#demo)
```javascript=
import Vue from 'vue';
import { LMap, LTileLayer, LMarker } from 'vue2-leaflet';
import 'leaflet/dist/leaflet.css';
Vue.component('l-map', LMap);
Vue.component('l-tile-layer', LTileLayer);
Vue.component('l-marker', LMarker);
```
### 如何使用
> 這邊只會介紹我有使用過的 Components;同前述,如未來還有使用到其他 Components,會再補充。
## LMap
> 最基本與核心的組件,用於在畫面上創建地圖和操作,相容所有其他組件。
[LMap](https://vue2-leaflet.netlify.app/components/LMap.html#demo)
:::warning
需要注意的是,這個組件把所有其他組件包在裡面,是==必要的==組件:+1:
:::
:::info
這個組件只是創建出一個放置地圖svg的框,需要另外加入其他組件才會有地圖出現。
:::
```javascript=
// 這個組件用來決定地圖的大小,使用 inline-style,設定 width和 height。
// 並給定地圖中心點和地圖顯示大小,來初始化地圖。
<l-map
style="height: 80%; width: 100%"
zoom="3"
center="[47.413220, -1.219482]"
>
// 其他組件
</l-map>
```
### Props
| Prop name | 介紹 | 使用心得 |
| -------- | -------- | -------- |
| options | leaflet map可用的 options,皆可放入使用。 | 到 [laeflet DOCS](https://leafletjs.com/reference-1.7.1.html#map-example),點 Map底下的 ++Options++,就可以看到可用的 Options了。 |
| center | 地圖的中心點,支援 .sync修飾符。 | .sync是用來雙向綁定,今天要動態修改地圖的中心點時,要記得加上此修飾符。 |
| maxBounds | 地圖的最大範圍,移動超出範圍,將會被彈回範圍內。 | 這邊要注意的是,當地圖縮放尺度大,顯示的地圖大於設定的 maxBounds時,還是可以看到範圍外的地圖,以及點擊範圍外的地圖,但卻無法拖曳移動,會被彈回。 |
| zoom | 地圖的縮放尺度,支援 .sync修飾符。 | zoom的尺度範圍限制為 1~18。 |
| minZoom | 地圖的最小縮放尺度。 | - |
| maxZoom | 地圖的最大縮放尺度。 | - |
### Events
| Event name | 介紹 | 使用心得 |
| ----------- | ---- | -------- |
| update:zoom | 當改變尺度時觸發。 | 可以得到當前的 zoom大小 |
| update:center | 當移動改變地圖中心點時觸發。 | 可以得到中心點 Object,裡面有 lat, lng的 key。 |
## LTileLayer
> 從地圖伺服器取得地圖資訊,並根據 L.map設置的寬高、中心點和尺度來顯示地圖。
> [LTileLayer](https://vue2-leaflet.netlify.app/components/LTileLayer.html#demo)
:::info
有關於可以用的地圖伺服器和資源,可以參考 [Tile & image layers有哪些地圖資源可以用呢?](#Tile-amp-image-layers有哪些地圖資源可以用呢) 這一段落的說明。 :smiley:
:::
:::info
如果要看更多詳細內容介紹,移步到 [leaflet tilelayer](https://leafletjs.com/reference-1.7.1.html#tilelayer),就有更多詳細內容囉。 :mage:
:::
```javascript=
// 記得在外面加上 L.map,並給予寬高、中心點和尺度。
<l-map style="height: 350px" :zoom="zoom" :center="center">
<l-tile-layer :url="url"></l-tile-layer>
</l-map>
```
### Props
| Prop name | 介紹 | 使用心得 |
| -------- | -------- | ------------- |
| url | 放置地圖伺服器提供的 URL。 | 詳細介紹請看 [Raster Layers底下的 tilelayer](https://leafletjs.com/reference-1.7.1.html#tilelayer) |
| attribution | 大多數的地圖伺服器都要求你放上你目前使用的地圖資源的來源,例: 
。 | 會顯示在地圖的右下角。 |
| visible | 地圖是否顯示。 | 可以搭配 L.map的 update:zoom 來決定地圖是否要顯示。 |
## LMarker
> 在地圖上放置一個可供點擊和移動的可客製化標記。
> [LMarker](https://vue2-leaflet.netlify.app/components/LMarker.html#demo)
:::info
如果要看更多詳細內容介紹,移步到 [leaflet marker](https://leafletjs.com/reference-1.7.1.html#marker),就有更多詳細內容囉。 :mage:
:::
```javascript=
<l-map style="height: 350px" :zoom="zoom" :center="center">
<l-tile-layer :url="url"></l-tile-layer>
<l-marker :lat-lng="markerLatLng" ></l-marker>
</l-map>
```
### Props
| Prop name | 介紹 | 使用心得 |
| --------- | ------------------ | -------- |
| latLng | 標記放置的經緯度。 | - |
| zIndexOffset | 標記的 z軸位置。沒設置的話,會自動給予緯度的數值。 | - |
### marker icon消失之解決方法
> 方法是參照 [git issue](https://github.com/PaulLeCam/react-leaflet/issues/453)別人的解答。
```javascript=
// 找到你引入 Vue app的 .js檔案,將以下 code複製貼上。
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
iconUrl: require('leaflet/dist/images/marker-icon.png'),
shadowUrl: require('leaflet/dist/images/marker-shadow.png')
});
```
### marker icon客製化之方法
> 請參考[LIcon](##LIcon)
## LIcon
> 在創建 LMarker標記時,給予圖標。
> [LIcon](https://vue2-leaflet.netlify.app/components/LIcon.html#demo)
:::info
如果要看更多詳細內容介紹,移步到 [leaflet icon](https://leafletjs.com/reference-1.7.1.html#icon),就有更多詳細內容囉。 :mage:
:::
1. 在 LMarker裡面放入 LIcon,可以用 icon-url加入你放置的 icon靜態檔案,或是在 LIcon裡面放置你自己的客製化內容。
```javascript=
// icon圖
<l-marker :lat-lng="[47.413220, -1.199482]">
<l-icon
:icon-size="dynamicSize"
:icon-anchor="dynamicAnchor"
icon-url="static/images/baseball-marker.png" >
</l-icon>
</l-marker>
// 客製化內容
<l-marker
:lat-lng="[lat, lng]"
>
<l-icon
class-name="cusom-icon"
>
<div class="custom-name">{{ custom_content }}</div>
</l-icon>
</l-marker>
```
2. 直接在 LMarker的 prop加入 icon,並引入 L.icon,根據給予的 option選項,創建 icon實例。
```javascript=
<l-marker
:lat-lng="[47.413220, -1.209482]"
:icon="icon" >
</l-marker>
// script
data () {
return {
icon: L.icon({
iconUrl: '/images/baseball-marker.png', // option選項,你的 icon靜態檔
iconSize: [32, 37], // option選項,大小
iconAnchor: [16, 37] // option選項,座標
}) // icon實例,
};
},
```
## LGeoJson
> 解析 GeoJSON,並將其顯示在地圖上。
> [LGeoJson](https://vue2-leaflet.netlify.app/components/LGeoJson.html#demo)
:::info
如果要看更多詳細內容介紹,移步到 [leaflet geojson](https://leafletjs.com/reference-1.7.1.html#geojson),就有更多詳細內容囉。 :mage:
:::
```javascript=
<l-map style="height: 350px" :zoom="zoom" :center="center">
<l-geo-json :geojson="geojson"></l-geo-json>
</l-map>
```
### Props
| Prop name | 介紹 | 使用心得 |
| --------- | ---- | -------- |
| geojson | 地圖數據。 | 如果想要得到台灣地圖的 geojson,可以到 [國土測繪中心](https://maps.nlsc.gov.tw/),取得開放資料。 |
| visible | 地圖是否顯示。 | 可以搭配 L.map的 update:zoom 來決定地圖是否要顯示。 |
| optionsStyle | 給予 geojson客製化樣式。 | 可以使用的 options,可以看 [leaflet 提供的 path-option](https://leafletjs.com/reference-1.7.1.html#path-option) |

## 畫出一個台灣
[Taiwan map DEMO](https://codesandbox.io/s/taiwan-uq325?file=/src/components/leaflet-map.vue)
### 如何得到台灣地圖資訊?
1. 從 [政府資料開放平臺](https://data.gov.tw/dataset/7442)或是 [內證資料開放平臺_國土測繪中心](https://data.moi.gov.tw/MoiOD/Data/DataDetail.aspx?oid=141718DF-0213-48C3-A7F7-AD6222B1D1F2)下載 ==直轄市、縣市界線(TWD97經緯度)SHP格式==。
2. 將檔案放上 [mapshaper](https://mapshaper.org/),線上轉換成 ==GeoJson 格式==。
3. 轉換步驟[參考資料](https://ithelp.ithome.com.tw/articles/10223786)。
### 如何得到地圖中心點?
> LMap提供 @update:center 方法,可以取得目前顯示地圖的中心點經緯度。
### 如何在縮放的時候,顯示不同地圖?
> LMap提供 @update:zoom 方法,如果搭配其他 Components的 visable,來決定到某個 zoom尺度時,你想要顯示的地圖。
### 我想只顯示台灣地圖的線圖,不想要使用其他地圖伺服器的地圖怎麼辦?
> 政府有提供開放資料,請參考 [如何得到台灣地圖資訊?](###如何得到台灣地圖資訊?),使用 LGeojson,放入你的 geojson就可以得到只有線條的台灣地圖;如果你今天想要在只有線條的台灣地圖上,放上縣市名稱,可以先去 [下載台灣鄉鎮市名稱和中心位置資料](https://data.gov.tw/dataset/40281),使用 LMarker 客製化標誌,渲染出各縣市名稱。
### csv檔案要怎麼讀取?
> 可以使用 [fetch](https://www.twblogs.net/a/5d7e091abd9eee5327ffbe96)。
> 用 vue-cli&webpack的話,可以安裝 csv-loader。
- vue-cli: 修改vue.config.js
- npm i csv-loader --save
```javascript=
chainWebpack: config => {
config
.module
.rule('csv')
.test(/\.csv$/)
.use('csv-loader')
.loader('csv-loader')
.options({
dynamicTyping: true,
header: true,
skipEmptyLines: true
})
.end()
}
```
- webpack:
```javascript=
module: {
rule:[
{
test: /\.csv$/,
loader: 'csv-loader',
options: {
dynamicTyping: true,
header: true,
skipEmptyLines: true
}
},
]
}
```
### csv讀取成功,但是產生亂碼怎麼辦?
> 可能是因為使用 import的方式載入 csv產生。詳細原因應該是轉碼出問題,但如果用 fetch方式載入,會自動轉碼)。
>
- 讓excell打開變成中文
- 原本檔案打開長這樣
- 
- 打開一個新的excel
- 
- 選擇 UTF-8
- 
- 逗點打勾
- 
- 選擇文字
- 
- 選新工作表
- 
- 儲存後打開
- 
- 讓js可以讀到中文
- 右鍵檔案,用==記事本==打開檔案
- 存檔類型 ==所有檔案==
- 
- 編碼 ==UTF-8==
- 
- 另存檔案成.csv檔案,js讀取檔案後就不會亂碼了
- 
### 我的地圖載入不正常,但在改變畫面寬高以後就正常,怎麼辦?
> leaflet可能會出現渲染不正確問題,在 mouted時,將整個畫面重新調整大小,就可以正確載入了。
> [leaflet render issue](https://github.com/vue-leaflet/Vue2Leaflet/issues/96)
```javascript=
mounted () {
setTimeout(function() { window.dispatchEvent(new Event('resize')) }, 250);
},
```
### 我改變了 center,但是地圖沒有變動怎麼辦?
> 有些 props支援 .sync雙向綁定,加上去就可以變動了。
> [詳細說明 prop.sync](https://fpjs.fun/vue/component/prop/sync/)