如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)
簡介
一如既往,我來給大家分享一個項目中遇到的比較有意思的需求并介紹一下相應的實現(xiàn)過程。
話不多說,直接上圖:

具體的應用場景簡而言之就是需要我們在地圖上添加如圖中所示的自定義覆蓋物。實現(xiàn)的過程作者分為以下兩點給大家介紹介紹。
- 水波紋的實現(xiàn)
- 自定義覆蓋物的實現(xiàn)
水波紋的實現(xiàn)
這個需求的實現(xiàn)肯定是離不開我們自己寫自定義覆蓋物的,那么首先我們來討論一下水波紋動畫的實現(xiàn)。
首先我們可以看到圖中的覆蓋物是由一個紅心和水波紋組成,其中紅心是固定不動的,那么我們可以直接這么寫:
<div class="radar"></div>
.radar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
}

這樣子我們首先就實現(xiàn)了紅心部分的樣式。那么水波紋又是怎么實現(xiàn)的呢?
我們可以從圖中觀察得出先后總共有三個水波紋從里到外逐漸的往外擴散。我們單獨從一個水波紋來看的話,其實往外擴散的原理是通過動畫讓水波紋的寬高逐漸遞增到一定程度即可,具體擴散多大呢讀者可以根據(jù)自己的需求設定水波紋的最后寬高。
水波紋的基本結構和樣式實現(xiàn)如下:
<div class="radar"> <div class="ripple"></div> <div class="ripple"></div> <div class="ripple"></div> </div>
.radar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
position: relative;
.ripple {
width: 40px;
height: 40px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border: 1px solid red;
animation: ripple 2s linear infinite;
}
}
之所以將水波紋的dom節(jié)點嵌套在radar節(jié)點里面主要是做一個“子絕父相”定位以達到水波紋居中對齊的效果,這個應該很容易理解。至于水波紋的初始寬高呢,為了方便動畫延遲時間的計算,我就設置為跟紅心寬高相等即可,如果讀者有興趣可以嘗試一下寬高設置在0~40px任意值的看看效果(作者盲猜動畫可能會有點瑕疵,可能也不會------>“手動狗頭”))。
至于動畫的實現(xiàn)呢,這個就很簡單了,我們只需要同時將水波紋的寬高都逐漸變大即可,但是有個點要注意一下就是水波紋最后是會消失的,這里我們利用opacity:0配合動畫達到逐漸消失的效果。
@keyframes ripple {
to {
width: 150px;
height: 150px;
opacity: 0;
}
}
代碼到了這里,我們水波紋已經(jīng)是實現(xiàn)了,但是不是少了點什么?說好的三個水波紋呢?
這個問題也很好解決,我們只需要給水波紋設置對應的動畫延遲即可。
.radar :nth-child(1) {
animation-delay: 0.666s;
}
.radar :nth-child(2) {
animation-delay: 1.322s;
}
這樣子我們就把水波紋給實現(xiàn)出來啦。

自定義覆蓋物的實現(xiàn)
本次作者采用的是百度地圖實現(xiàn)的需求,那么如何通過百度地圖來實現(xiàn)自定義覆蓋物呢?
其實百度地圖開發(fā)文檔中也很直白的向我們展示自定義覆蓋物的開箱方法。這里作者用es6的class稍微改寫了一下寫法,道理都一樣的,官方案例可以參考百度地圖demo
自定義覆蓋物實現(xiàn)分以下三步:
- 定義構造函數(shù)并繼承Overlay
- 初始化自定義覆蓋物
- 繪制覆蓋物
定義構造函數(shù)并繼承Overlay
按照官網(wǎng)的說法是:“首先您需要定義自定義覆蓋物的構造函數(shù),通過構造函數(shù)參數(shù)可以傳遞一些自由的變量。設置自定義覆蓋物對象的prototype屬性為Overlay的實例,以便繼承覆蓋物基類”。
運用es6 class我們可以很快的實現(xiàn):
其中point傳遞的是坐標位置,用于后續(xù)計算覆蓋物在地圖上的位置。
class RadarOverlay extends BMap.Overlay {
constructor(point) {
super();
this.point = point;
}
}
初始化自定義覆蓋物
官方的說法是:“實現(xiàn)initialize方法,當調(diào)用map.addOverlay方法時,API會調(diào)用此方法。當調(diào)用map.addOverlay方法添加自定義覆蓋物時,API會調(diào)用該對象的initialize方法用來初始化覆蓋物,在初始化過程中需要創(chuàng)建覆蓋物所需要的DOM元素,并添加到地圖相應的容器中。這里我們選擇添加在容器markerPane上。”
其實意思大概就是說,因為百度地圖在添加overLay時會調(diào)用自定義覆蓋物構造函數(shù)中的initialize方法,這個initialize方法是用來初始化覆蓋物的,他會在初始化過程中創(chuàng)建所需要的DOM,因此我們要在我們自己的構造函數(shù)(這里我們用的是類)中實現(xiàn)一個initialize。
百度地圖官網(wǎng)的方法:

那么我們就按照官網(wǎng)的要求,在類中定義一個initialize方法。其中template存的是我們初始化中所需要的DOM元素,這里的dom節(jié)點會比上文中實現(xiàn)水波紋的環(huán)節(jié)多了一個className為rader-box的父節(jié)點,因為在官網(wǎng)中我們也可以看到官方實例在創(chuàng)建DOM元素時給DOM節(jié)點添加了position:absolute的樣式,但由于我們的radar節(jié)點的position為relative,所以我們需要在最外層多嵌套一層dom節(jié)點以確保整個dom相對于地圖定位。當然啦該父節(jié)點的position也就為絕對定位
initialize(map) {
this._map = map;
const template = `<div class="radar-box">
<div class="radar">
<div class="ripple"></div>
<div class="ripple"></div>
<div class="ripple"></div>
</div>
</div>`;
// 創(chuàng)建文檔碎片
const divFragment = document.createRange().createContextualFragment(template);
const div = divFragment.querySelectorAll('.radar-box')[0];
// 將div添加到覆蓋物容器中
map.getPanes().markerPane.appendChild(div);
this._div = div;
return div;
}
這樣子我們就成功的在類中定義了一個initialize方法,至于為什么要將div添加到覆蓋物容器中官網(wǎng)的也有如下說明:
大概就是說百度地圖里面已經(jīng)給我們提供了若干的覆蓋物展示方法,我們自定義的覆蓋物其實是保存在我們選擇的其中某個覆蓋物容器之下,有興趣的小伙伴可以去了解一下各種覆蓋物容器。。。
繪制覆蓋物
這里作者繼續(xù)拋磚引玉阿,官方的說法是:“到目前為止,我們僅僅把覆蓋物添加到了地圖上,但是并沒有將它放置在正確的位置上。您需要在draw方法中設置覆蓋物的位置,每當?shù)貓D狀態(tài)發(fā)生變化(比如:位置移動、級別變化)時,API都會調(diào)用覆蓋物的draw方法,用于重新計算覆蓋物的位置。通過map.pointToOverlayPixel方法可以將地理坐標轉換到覆蓋物的所需要的像素坐標。”
簡單來講就是比如地圖縮放比例之后,會重新調(diào)用覆蓋物中的draw方法,用于重新雞算覆蓋物的位置。
那么問題來了,draw方法哪里來的?
所以官方的意思是我們在自定義覆蓋物中的構造函數(shù)定義一個draw方法,方法中我們利用百度地圖的map.pointToOverlayPixel方法(用來將地理坐標轉換為像素坐標)可以將地理坐標轉換到覆蓋物的所需要的像素坐標。
那么我們只需要在類中加入draw方法即可:
其中this.point就是我們構造函數(shù)中的point坐標點,40表示的是我們整個水波紋的初始寬高,讀者其實可以將40改為可以傳參的形式比如this.size,這樣會方便后續(xù)代碼的維護,這里為了直觀的讓讀者理解就不講太復雜了。
draw() {
// 根據(jù)地理坐標轉換為像素坐標,并設置給容器
const position = this._map.pointToOverlayPixel(this.point);
this._div.style.left = `${position.x - 40 / 2}px`;
this._div.style.top = `${position.y - 40 / 2}px`;
}
到此,我們整個自定義覆蓋物的類就已經(jīng)實現(xiàn)了,整體代碼圖下(這里把40改為this.size代碼維護起來稍微方便點):
class RadarOverlay extends BMap.Overlay {
constructor(point, size) {
super();
this.point = point;
this.size = size;
}
initialize(map) {
this._map = map;
const template = `<div class="radar-box">
<div class="radar">
<div class="ripple"></div>
<div class="ripple"></div>
<div class="ripple"></div>
</div>
</div>`;
const divFragment = document.createRange().createContextualFragment(template);
const div = divFragment.querySelectorAll('.radar-box')[0];
map.getPanes().markerPane.appendChild(div);
this._div = div;
return div;
}
draw() {
// 根據(jù)地理坐標轉換為像素坐標,并設置給容器
const position = this._map.pointToOverlayPixel(this.point);
this._div.style.left = `${position.x - this.size / 2}px`;
this._div.style.top = `${position.y - this.size / 2}px`;
}
}
自定義覆蓋物的使用
那既然我們都已經(jīng)實現(xiàn)了自定義的覆蓋物,第一件事當然就是把它給使用上,具體如下:
initMap() {
const map = new BMap.Map(this.$refs.map);
map.centerAndZoom(new BMap.Point(116.404, 39.915), 15);
// 實例化我們要繪制自定義覆蓋物的點坐標
const point = new BMap.Point(116.404, 39.915);
// 實例化自定義覆蓋物,將坐標點和水波紋的尺寸傳進構造函數(shù)中
const radar = new RadarOverlay(point, 40);
// 添加自定義覆蓋物
map.addOverlay(radar);
}
效果如圖:

結語
至于構造自定義覆蓋物的其他內(nèi)容,大佬們?nèi)绻钊氲脑捒梢詤⒖及俣鹊貓D的文檔,里面講的肯定要比作者更加詳細(狗頭)。如果文章的內(nèi)容有問題話的歡迎留言點出,希望能與各路大佬們交流交流,喜歡作者的文章的話也別忘了給我點個贊,這對我來說很重要。
源碼地址:https://gitee.com/zhao_jiahao/baidu-map-custom-cover
到此這篇關于如何在vue中使用百度地圖添加自定義覆蓋物(水波紋)的文章就介紹到這了,更多相關vue用百度地圖添加自定義覆蓋物內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue使用自定義事件的表單輸入組件用法詳解【日期組件與貨幣組件】
這篇文章主要介紹了vue使用自定義事件的表單輸入組件用法,結合實例形式詳細分析了vue.js日期組件與貨幣組件相關操作技巧及注意事項,需要的朋友可以參考下2020-06-06
vuejs實現(xiàn)標簽選項卡動態(tài)更改css樣式的方法
這篇文章主要介紹了vuejs實現(xiàn)標簽選項卡-動態(tài)更改css樣式的方法,代碼分為html和js兩部分,需要的朋友可以參考下2018-05-05
詳解vue的數(shù)據(jù)劫持以及操作數(shù)組的坑
這篇文章主要介紹了vue的數(shù)據(jù)劫持以及操作數(shù)組的坑,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
Ant Design Vue table中列超長顯示...并加提示語的實例
這篇文章主要介紹了Ant Design Vue table中列超長顯示...并加提示語的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10

