今天我們來思考在外送平台
常見的
拖曳地圖抓地址的功能怎麼做?
當以上問題解完其實就能寫出來了
抓目前題圖的中心點 經緯度
map.getCenter();
//{
// "lat": 24.153940200805668,
// "lng": 120.6743698120117
// }
透過免費的 API 將經緯度轉地址名稱
可以到以下官網試試看:
https://nominatim.openstreetmap.org/ui/reverse.html
我們可以用"address"或是"display_name"的資訊
要特別注意"display_name"對我們來說是反向的
// "display_name": "210號, 五權一街, 大忠里, 西區, 田心, 臺中市, 403, 臺灣",
// "address": {
// "house_number": "210號",
// "road": "五權一街",
// "neighbourhood": "大忠里",
// "suburb": "西區",
// "village": "田心",
// "city": "臺中市",
// "ISO3166-2-lvl4": "TW-TXG",
// "postcode": "403",
// "country": "臺灣",
// "country_code": "tw"
// },
//地圖開始移動:隱藏 tooltip
map.on("movestart", () => {
this.centerMarker.closeTooltip();
});
//地圖移動中:更改 marker 位置
map.on("move", () => {
const center = map.getCenter();
this.centerMarker.setLatLng(center);
});
//地圖移動完成:更改文字後,開啟 tooltip
map.on("moveend", () => {
updateMarker();
this.centerMarker.openTooltip();
});
// 先取得 marker 的經緯度再轉換成地址
const updateMarker = () => {
const latlng = this.centerMarker.getLatLng();
updateAddress(latlng, this.centerMarker);
};
//call api 轉換後將 marker 文字更改
function updateAddress({ lat, lng }, centerMarker) {
centerMarker.setTooltipContent("Loading...");
const url = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`;
fetch(url)
.then((response) => response.json())
.then((data) => {
const address = data.display_name || "No address found";
const reverseAddress = address.split(",").reverse().join("");
centerMarker.setTooltipContent(reverseAddress);
})
.catch(() => {
centerMarker.setTooltipContent("Unable to load address");
});
}
其實最早我完成的是這個
demo2
手動移動 marker 來更新地圖
但使用後發現不好用XD
果然外送平台的做法UX還是比較讚!
移動地圖抓中心點非常直覺~
有興趣可以實際操作看看最後的成果:
demo1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DAY-4 移動地圖抓中心點地址 Example</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
<style>
body {
background-color: black;
padding: 0;
margin: 0;
}
.wrapper {
width: 99dvw;
height: 99dvh;
display: flex;
justify-content: center;
align-items: center;
}
#map {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div class="wrapper">
<div id="map"></div>
</div>
<script>
const myMap = {
map: null,
centerMarker: null,
init() {
this.map = L.map("map").setView(
[24.153940200805668, 120.6743698120117],
14
);
//圖層
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors",
}).addTo(this.map);
},
generateMarker() {
const map = this.map;
// 在地圖中心放一個可移動的 marker
this.centerMarker = L.marker(map.getCenter(), {
draggable: true,
}).addTo(map);
// 初始化 Tooltip
this.centerMarker
.bindTooltip("Loading address...", {
permanent: true,
direction: "top",
})
.openTooltip();
},
main() {
// 產生marker
this.generateMarker();
// 更新 marker 的位置和地址
const updateMarker = () => {
const latlng = this.centerMarker.getLatLng();
updateAddress(latlng, this.centerMarker);
};
// 初次載入地圖時更新一次 marker 位置和地址
updateMarker();
const map = this.map;
// 當地圖拖動結束時更新 marker 位置和地址
map.on("movestart", () => {
this.centerMarker.closeTooltip();
});
map.on("move", () => {
const center = map.getCenter();
this.centerMarker.setLatLng(center);
});
map.on("moveend", () => {
updateMarker();
this.centerMarker.openTooltip();
});
},
};
myMap.init();
myMap.main();
// call api 更新地點的地址
function updateAddress({ lat, lng }, centerMarker) {
centerMarker.setTooltipContent("Loading...");
const url = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`;
fetch(url)
.then((response) => response.json())
.then((data) => {
const address = data.display_name || "No address found";
const reverseAddress = address.split(",").reverse().join("");
centerMarker.setTooltipContent(reverseAddress);
})
.catch(() => {
centerMarker.setTooltipContent("Unable to load address");
});
}
</script>
</body>
</html>