0%

Leaflet和OpenSourceMap-Vue寫法

這一篇就記錄一下,使用Vue的環境來製作口罩地圖的過程。

安裝相關套件和口罩地圖API網址

step1.
首先先用vue create指令創建你的專案。
step2.
我們先把,原本vue專案中預設設置的Helloworld的元件內容先拿掉。
直接在APP.vue的元件檔中,做所有的事。
step3.
將bootstrap加入你的專案檔中。
所以,輸入指令npm install bootstrap
接著,導入bootstrap。
你就在App.vue的檔案中的引入

1
2
3
4
---App.vue元件檔---
<style lang="scss">
@import 'bootstrap/scss/bootstrap'
</style>

然後,你就再這個檔案中隨便套一個bootstrap的元件看看你有沒有引入成功囉。

step4.
接著你到課堂上提供的公版 貼到你的App.vue元件檔中。,

step5.
以下這個連結就是口罩地圖的API
你打開這個api的網址,就可以看到資料個格式和內容囉。

step6.
我們要利用vue-axios這個套件來將以上的api內容,接進來你的專案檔裡面。
接著,我們就輸入指令npm install --save axios vue-axios來安裝這個套件。
再來你要將vue-axios的相關程式碼加入到你的main.js檔案。

1
2
3
4
5
---main.js---
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

將API的資料接進來

step7.
引入完成以上的vue-axios套件之後,我們就可以套過它,來將上面的口罩地圖的api內的資料,接進來囉。
這邊要特別注意一下,我們因為要在地圖的元件完整建立好之後,才去取得api的資訊,
所以,我們要在App.vue元件檔中的mounted生命週期時,才加入取得api資料的內容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---App.vue---
<script>
export default {
name: 'App',
data: () => ({

}),
mounted () {
const api = 'https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json'
this.$http.get(api).then((response) => {
console.log(response)
})
}
}
</script>

從以上的內容中,我們利用vue-axios元件的get方法,就可以取得api的內容囉。

step8.
接著,我們將從api取得的內容存入我們定義的物件裡面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
export default {
name: 'App',
data: () => ({
data: []
}),
mounted () {
const vm = this
const api = 'https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json'
this.$http.get(api).then((response) => {
console.log(response)
vm.data = response.data.features // 將資料存入data陣列中
console.log(vm.data)
})
}
}
</script>

利用leaflet將圖資放上網頁

step9.
接著,我們要將leaflex元件加入我們的專案檔中囉。
你就輸入指令npm install leaflet,來安裝這個套件。
另外,你還要再額外手動加入它的css的cdn到你的public資料夾中的index.html檔案中。

1
2
3
4
5
6
7
8
---index.html---
<head>

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/> // 將leaflet的cdn加入index.html裡面

</head>

step10.
你要在App.vue的元件檔中,將leaflet檔案載入進來。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
import L from 'leaflet' // 載入leaflet元件,它叫做L
console.log(L) // 加這一行的原因是因為,ESLint會報錯,說你沒有在用L元件。
export default {
name: 'App',
data: () => ({
data: []
}),
mounted () {
const vm = this
const api = 'https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json'
this.$http.get(api).then((response) => {
console.log(response)
vm.data = response.data.features
console.log(vm.data)
})
}
}
</script>

step11.
接著,將leaflet的地圖放上來。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---App.vue的HTML---
<template>
<div id="app">
<div class="row no-gutters">
<div class="col-sm-3"></div>
<div class="col-sm-9">
<div id="map"></div>
</div>
</div>
</div>
</template>


---App.vue的JS---
<script>
import L from 'leaflet'
console.log(L)
let osmMap = {} // 宣告一個變數來將一些圖資資訊存入在它裡面
export default {
name: 'App',
data: () => ({
data: {}
}),
mounted () {
const vm = this
const api = 'https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json'
this.$http.get(api).then((response) => {
console.log(response)
vm.data = response.data.features
console.log(vm.data)
})
osmMap = L.map('map', {
center: [25.03, 121.55],
zoom: 15
}) // 存入座標和縮放大小
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '<a target="_blank" href="https://www.openstreetmap.org/">© OpenStreetMap 貢獻者</a>',
maxZoom: 18
}).addTo(osmMap) // 以該變數的座標為中心,來展開地圖
}
}
</script>

經過以上的操作你應該就可以看到,你的畫面上,有地圖在上面了。

step12.
我們將課堂上提供的一份,將各主城市中的縣市做過分類的口罩地圖資料 ,存成JSON檔案。
這個json的分類檔,為的是要當你點擊特定縣市的時候,你的圖磚不會呈現所有的資訊,只會呈現局部的資訊而已,這樣你的網頁就比較不會卡頓了。
那這邊呢,我只有擷取cityName:台北市這一區塊的資料而已。
接著,你將這些資料貼到一個新的檔案中,並將它命名為cityName.json並把它存在assets資料夾中。
然後,我們在App.vue元件檔中,以cityName這個變數將這個json資料中的檔案讀進來,
並將這個變數新增成App.vue元件的其中一個成員

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<script>
import L from 'leaflet'
import cityName from './assets/cityName.json' // 新增cityName變數,將該json資料存進來
console.log(L)
let osmMap = {}
export default {
name: 'App',
data: () => ({
data: {},
cityName // 將cityName新增其中一個成員屬性
}),
mounted () {
const vm = this
const api = 'https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json'
this.$http.get(api).then((response) => {
console.log(response)
// vm.data = response.data.features
vm.data = response.data.features.filter((item, index) => {
if (index < 10) {
return true
}
})
console.log(vm.data)
})
osmMap = L.map('map', {
center: [25.03, 121.55],
zoom: 15
})
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '<a target="_blank" href="https://www.openstreetmap.org/">© OpenStreetMap 貢獻者</a>',
maxZoom: 18
}).addTo(osmMap)
}
}
</script>

step13.
接著,我們將左邊呈現可以選擇縣市公版的內容貼上去。
並新增了成員屬性

1
2
3
4
select: {
city: '臺北市',
area: '大安區'
}

這個時候,你應該就可以,成功的在你的畫面上看到,選擇欄的內容囉。

加入Marker的效果

step14.
接下來,我們要將Marker的效果補上去。
首先,我們會先增一個方法,用來將跟你在選擇欄中選擇的城市一樣的資料都另外存到另一個陣列中。
接著,再利用這個陣列取出每一個元素的經緯度,接著,在將這些經緯度塞到Marker的語法中,就可以在各經緯度上
創出相對應的Marker囉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<script>
import L from 'leaflet'
import cityName from './assets/cityName.json'
console.log(L)
let osmMap = {}
export default {
name: 'App',
data: () => ({
data: [],
cityName,
select: {
city: '臺北市',
area: '大安區'
}
}),
methods: {
updateMap () {
const pharmacies = this.data.filter(item => {
if (item.properties.county === this.select.city) return true // 當該資料的county跟選取的一樣,就存入pharmacies中
})
pharmacies.forEach(item => {
L.marker([item.geometry.coordinates[1], item.geometry.coordinates[0]]).addTo(osmMap) // 為每個元素都加上Marker
})
}
},
mounted () {
const vm = this
const api = 'https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json'
vm.$http.get(api).then((response) => {
console.log(response)
vm.data = response.data.features
vm.updateMap() // 當將data的資料存取完成後,才執行updateMap方法,來繪製Marker
})
osmMap = L.map('map', {
center: [25.03, 121.55],
zoom: 15
})
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '<a target="_blank" href="https://www.openstreetmap.org/">© OpenStreetMap 貢獻者</a>',
maxZoom: 18
}).addTo(osmMap)
}
}
</script>

經過以上的撰寫,你就可以看到畫面上在各點上都有相對應的Marker囉。

為Marker加入bindPopup的內容

step15.
將該藥局的相關文字描述利用popup來呈現在地圖上面。
你就直接在updateMap裡面加上popup的語法就可以囉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---App.vue---
methods: {
updateMap () {
const pharmacies = this.data.filter(item => {
if (item.properties.county === this.select.city) return true
})
pharmacies.forEach(item => {
L.marker([item.geometry.coordinates[1], item.geometry.coordinates[0]]).addTo(osmMap).bindPopup(`<strong>${item.properties.name}</strong> <br>
口罩剩餘:<strong>成人 - ${item.properties.mask_adult ? `${item.properties.mask_adult} 個` : '未取得資料'}/ 兒童 - ${item.properties.mask_child ? `${item.properties.mask_child} 個` : '未取得資料'}</strong>
<br>
地址: <a href="https://www.google.com.tw/maps/place/${item.properties.address}" target="_blank">${item.properties.address}</a><br>
電話: ${item.properties.phone}<br>
<small>最後更新時間: ${item.properties.updated}</small>`)
})
}
}

你可以看到我們在addTo後面加上了bindPopup那一大串,就是為每一個Marker加上註釋囉。

step15.
另外,還有PenTo的功能相關連結 ,你再看看要怎麼寫吧,這邊就不贅述囉,概念就是將圖資的中心經緯度轉移成
你選取的那筆資料的經緯度。