iT邦幫忙

2021 iThome 鐵人賽

DAY 29
0
Modern Web

我的Vue學習筆記系列 第 29

Day29-實作(地圖) (part1)

進入到尾聲,範例的最後一片拼圖,馬上開始吧!!!

地圖的部分使用了leaflet JS和OpenStreetMap,所以在開始前先裝一下leaflet,在終端機打上

npm install leaflet

地圖元件

完成後,接下來和先前的步驟一樣,先在components下建立一個maskMap.vue,把App.vue的地圖部分搬過來

<template>
  <div class="mask-map" id="mask-map"></div>
</template>

<script>
export default {
  name: "maskMap",
};
</script>

再來修改App.vue

<template>
  <div id="app">
    <!-- aside-menu 左側欄 -->
    <asideMenu />

    <!-- 地圖區塊 -->
    <maskMap />

    <!-- lightBox -->
    <light-box />
  </div>
</template>

<script>
import { mapActions } from "vuex";
import asideMenu from "./components/asideMenu.vue";
import lightBox from "./components/lightBox.vue";
import maskMap from "./components/maskMap.vue";

export default {
  name: "App",
  components: {
    asideMenu,
    lightBox,
    maskMap,
  },
  //...略
};
</script>

回到maskMap.vue將leaflet弄進來

import L from "leaflet";

export default {
  name: "maskMap",
  data() {
    return {
			//別的地方用不到map,所以不用丟到vuex
      map: {},
    };
  },
  mounted() {
		//初始化地圖
    this.map = L.map("mask-map", {
      center: [25.03, 121.55],
      zoom: 14,
    });

    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(this.map);
  },
};

完成後可以看到完整地圖的畫面

Untitled

讓地圖移動到指定的位置

有了地圖後就要讓他和右邊的縣市行政區去做反應,選擇哪個區域就要到對應的地圖區塊,只要從vuex拿state.currCity和getters.districtList做比對就可以完成,先在getters加上:

currDistrictInfo(state, getters) {
  // 目前所選行政區
  return getters.districtList.find((d) => d.name === state.currDistrict) || {}
}

也在maskMap.vue加上computed,把getter拿回

computed: {
    currDistrictInfo() {
      return this.$state.getters.currDistrictInfo;
    },
  },

並在此加上watch,當使用者切換行政區地圖也會跟著移動

  watch: {
    currDistrictInfo(dist) {
			//this.map.panTo可以指定地圖中心點
      this.map.panTo(new L.LatLng(dist.latitude, dist.longitude));
    },
  },

設定藥局標記

藥局的資料在剛剛已經有從vuex拿到手了,再來就是在maskMap.vue加入computed

filteredStores() {
  return this.$store.getters.filteredStores;
},

還有在watch身上新增filteredStores,列表變動透過addMarker來增加圖釘


filteredStores(stores) {
  stores.forEach((element) => this.addMarker(element));
},

再來就是在methods定義剛剛的addMarker

addMarker(item) {
	//標記圖案
  const ICON = {
    iconUrl:
      "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-violet.png",
    shadowUrl:
      "https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png",
    iconSize: [25, 41],
    iconAnchor: [12, 41],
    popupAnchor: [1, -34],
    shadowSize: [41, 41],
  };
	//將標記放到地圖上
  const marker = L.marker([item.longitude, item.latitude], ICON)
    .addTo(this.map)
    .bindPopup(`<h2 class="popup-name">${item.name}</h2>`);
},

當多次切換行政區時標記的點並不會清除,反而是累加上去的,所以在methods上要加上clearMarker來清除

clearMarkers() {
  //清除地圖所有標記
  this.map.eachLayer((layer) => {
    if (layer instanceof L.Marker) {
      this.map.removeLayer(layer);
    }
  });
},

並改寫一下watch中的filteredStores

filteredStores(stores) {
  //先清除原有marker
  this.clearMarkers();
  //根據藥局資訊加上對應的marker
  stores.forEach((element) => this.addMarker(element));
},

Untitled

就差一點點了!! 今天來不及弄完,明天再續


上一篇
Day28-實作(燈箱)
下一篇
Day30-實作(地圖) (part2)
系列文
我的Vue學習筆記30

尚未有邦友留言

立即登入留言