這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 仿貝殼地圖畫圈找房功能實現(高德地圖) 前言 在最近租房時,看到貝殼找房上線了一個地圖畫圈找房的功能,感覺很是新奇。接觸地圖開發也有很長一段時間了,以前大部分都是基於web pc端開發,所以一般遇到這種圈選,繪製多邊形圓形都是直接基於官方 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
仿貝殼地圖畫圈找房功能實現(高德地圖)
前言
在最近租房時,看到貝殼找房上線了一個地圖畫圈找房的功能,感覺很是新奇。接觸地圖開發也有很長一段時間了,以前大部分都是基於web pc端開發,所以一般遇到這種圈選,繪製多邊形圓形都是直接基於官方API直接修改使用的,對於PC端滑鼠操作來說,現有的交互用起來已經很不錯了,但是對於H5移動端來說,只能通過手指觸摸來模擬滑鼠滑動,直接使用現有的API對於移動端交互體驗來說並不是特別好。因此,看到了貝殼找房上這一新穎的功能,確實讓我眼前一亮。話不多說,直接開搞,自己手動實現一個看看。有需要的小伙伴可以直接查看源碼demo:gitee.com/fcli/map-ed…
效果圖如下:
實現思路
剛看到這個功能時,腦海裡閃過一個想法,點成線、線成面。既然是線,那肯定是由一堆點組成的,那最終的圈選的面,也是由線包圍起來的。然後一頓噼里啪啦操作,當我在PC端模擬的時候發現,並沒有那麼絲滑,這不經讓我思考如此絲滑的滑動體驗是怎麼實現的,難道是通過畫板canvas之類的,然後通過獲取繪製的圈範圍再和地圖經緯度重合計算。事實證明,我完全想多了,當我把它放到H5上時,發現操作起來很絲滑,繪製的線段也是平滑的,這讓我醍醐灌頂。一頓測試發現PC端監聽 mouseMove
事件並沒有移動端的touchmove
事件的觸發的那麼頻繁,像是瀏覽器有節流之類的操作。
主要代碼
地圖初始化
首先,我使用vue3腳手架,所以在引入地圖時與官方demo不太一樣,通過createElement將地圖API載入到頁面上,併在地圖載入完畢後再觸發對應的地圖操作。
onMounted(() => { //創建了一個回調函數,高德地圖載入完畢會調用 window.onload = () => { // 所有關於地圖的邏輯全部都要寫在這個回調裡面 // 保證高德地圖載入完畢 myMap.value = new AMap.Map('map', { resizeEnable: true, center: [121.429516, 31.151997], zoom: 13 }); drawMap(); }; // key是申請的值 let url = 'https://webapi.amap.com/maps?v=2.0&key=0cc611512938634634bac0969fdef3c1'; //創建一個 script dom元素 let jsapi = document.createElement('script'); //設定script標簽屬性 jsapi.src = url; //將API文件引入頁面中,載入完畢以後會調用函數 document.head.appendChild(jsapi); })
監聽繪開始制地圖
當開始繪製地圖時,先將地圖固定,即:不可縮放、不可拖動... 同時將之前繪製的圖層remove
myMap.value.on('touchstart', () => { myMap.value.setStatus({ showIndoorMap: false, dragEnable: false, keyboardEnable: false, doubleClickZoom: false, zoomEnable: false, rotateEnable: false }); if (lastPolyLine.value) { myMap.value.remove(lastPolyLine.value) } if (polygonAfterDraw.value) { myMap.value.remove(polygonAfterDraw.value) } lastPolyLine.value = null; polyPointArray.value = []; isMouseDown.value = true; });
監聽繪製過程
當開始繪製時,監聽touchmove
事件,記錄每次move觸發的點並保存,通過這些點的集合繪製多邊形,每次繪製多邊形之前清除之前繪製的線段,在視覺上就能看到一條連續的線。
myMap.value.on('touchmove', (e: any) => { if (isMouseDown.value) { const point = [e.lnglat.lng, e.lnglat.lat] polyPointArray.value.push(point); if (lastPolyLine.value) { myMap.value.remove(lastPolyLine.value) } const polyline = new AMap.Polyline({ path: polyPointArray.value, //多邊形輪廓 isOutline: true, strokeColor: "#3366FF", strokeOpacity: 1, strokeWeight: 2, // 折線樣式還支持 'dashed' strokeStyle: "solid", // strokeStyle是dashed時有效 strokeDasharray: [15, 5], lineJoin: 'round', lineCap: 'round', zIndex: 50, }); myMap.value.add([polyline]) lastPolyLine.value = polyline; } })
繪製結束
繪製結束,使用線段的點生成一個面的範圍,通過這個範圍就能獲取到範圍內的信息了,最後恢復地圖正常狀態。
document.addEventListener('touchend', () => { if (isMouseDown.value) { // 退出畫線狀態 isMouseDown.value = false; // 添加多邊形覆蓋物,設置為禁止點擊 polygonAfterDraw.value = new AMap.Polygon({ fillOpacity: 0.5, fillColor: '#7bccc4', strokeOpacity: 1, strokeColor: '#3366FF', strokeWeight: 4, strokeStyle: 'solid', strokeDasharray: [5, 5], //多邊形數據 path: polyPointArray.value //多邊形輪廓 }); myMap.value.add(polygonAfterDraw.value); if (lastPolyLine.value) { myMap.value.remove(lastPolyLine.value) } myMap.value.setStatus({ showIndoorMap: true, dragEnable: true, keyboardEnable: true, doubleClickZoom: true, zoomEnable: true, rotateEnable: true }); } });