如何在vue中使用百度地图添加自定义覆盖物(水波纹)


Posted in Javascript onNovember 03, 2020

简介

一如既往,我来给大家分享一个项目中遇到的比较有意思的需求并介绍一下相应的实现过程。

话不多说,直接上图:

如何在vue中使用百度地图添加自定义覆盖物(水波纹)

具体的应用场景简而言之就是需要我们在地图上添加如图中所示的自定义覆盖物。实现的过程作者分为以下两点给大家介绍介绍。

  • 水波?的实现
  • 自定义覆盖物的实现

水波?的实现

这个需求的实现肯定是离不开我们自己写自定义覆盖物的,那么首先我们来讨论一下水波纹动画的实现。

首先我们可以看到图中的覆盖物是由一个红心和水波?组成,其中红心是固定不动的,那么我们可以直接这么写:

<div class="radar"></div>
.radar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: red;
 }

如何在vue中使用百度地图添加自定义覆盖物(水波纹)

这样子我们首先就实现了红心部分的样式。那么水波?又是怎么实现的呢?

我们可以从图中观察得出先后总共有三个水波?从里到外逐渐的往外扩散。我们单独从一个水波?来看的话,其实往外扩散的原理是通过动画让水波?的宽高逐渐递增到一定程度即可,具体扩散多大呢读者可以根据自己的需求设定水波?的最后宽高。

水波?的基本结构和样式实现如下:

<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节点嵌套在radar节点里面主要是做一个“子绝父相”定位以达到水波?居中对齐的效果,这个应该很容易理解。至于水波?的初始宽高呢,为了方便动画延迟时间的计算,我就设置为跟红心宽高相等即可,如果读者有兴趣可以尝试一下宽高设置在0~40px任意值的看看效果(作者盲猜动画可能会有点瑕疵,可能也不会------>“手动狗头”))。

至于动画的实现呢,这个就很简单了,我们只需要同时将水波?的宽高都逐渐变大即可,但是有个点要注意一下就是水波?最后是会消失的,这里我们利用opacity:0配合动画达到逐渐消失的效果。

@keyframes ripple {
 to {
  width: 150px;
  height: 150px;
  opacity: 0;
 }
 }

代码到了这里,我们水波?已经是实现了,但是不是少了点什么?说好的三个水波?呢?

这个问题也很好解决,我们只需要给水波?设置对应的动画延迟即可。

.radar :nth-child(1) {
 animation-delay: 0.666s;
 }
 .radar :nth-child(2) {
 animation-delay: 1.322s;
 }

这样子我们就把水波?给实现出来啦。

如何在vue中使用百度地图添加自定义覆盖物(水波纹)

自定义覆盖物的实现

本次作者采用的是百度地图实现的需求,那么如何通过百度地图来实现自定义覆盖物呢?

其实百度地图开发文档中也很直白的向我们展示自定义覆盖物的开箱方法。这里作者用es6的class稍微改写了一下写法,道理都一样的,官方案例可以参考百度地图demo

自定义覆盖物实现分以下三步:

  • 定义构造函数并继承Overlay
  • 初始化自定义覆盖物
  • 绘制覆盖物

定义构造函数并继承Overlay

按照官网的说法是:“首先您需要定义自定义覆盖物的构造函数,通过构造函数参数可以传递一些自由的变量。设置自定义覆盖物对象的prototype属性为Overlay的实例,以便继承覆盖物基类”。

运用es6 class我们可以很快的实现:

其中point传递的是坐标位置,用于后续计算覆盖物在地图上的位置。

class RadarOverlay extends BMap.Overlay	{
 constructor(point) {
  super();
  this.point = point;
 }
}

初始化自定义覆盖物

官方的说法是:“实现initialize方法,当调用map.addOverlay方法时,API会调用此方法。当调用map.addOverlay方法添加自定义覆盖物时,API会调用该对象的initialize方法用来初始化覆盖物,在初始化过程中需要创建覆盖物所需要的DOM元素,并添加到地图相应的容器中。这里我们选择添加在容器markerPane上。”

其实意思大概就是说,因为百度地图在添加overLay时会调用自定义覆盖物构造函数中的initialize方法,这个initialize方法是用来初始化覆盖物的,他会在初始化过程中创建所需要的DOM,因此我们要在我们自己的构造函数(这里我们用的是类)中实现一个initialize。

百度地图官网的方法:

如何在vue中使用百度地图添加自定义覆盖物(水波纹)

那么我们就按照官网的要求,在类中定义一个initialize方法。其中template存的是我们初始化中所需要的DOM元素,这里的dom节点会比上文中实现水波纹的环节多了一个className为rader-box的父节点,因为在官网中我们也可以看到官方实例在创建DOM元素时给DOM节点添加了position:absolute的样式,但由于我们的radar节点的position为relative,所以我们需要在最外层多嵌套一层dom节点以确保整个dom相对于地图定位。当然啦该父节点的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>`;
  // 创建文档碎片
  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添加到覆盖物容器中官网的也有如下说明:

大概就是说百度地图里面已经给我们提供了若干的覆盖物展示方法,我们自定义的覆盖物其实是保存在我们选择的其中某个覆盖物容器之下,有兴趣的小伙伴可以去了解一下各种覆盖物容器。。。

绘制覆盖物

这里作者继续抛砖引玉阿,官方的说法是:“到目前为止,我们仅仅把覆盖物添加到了地图上,但是并没有将它放置在正确的位置上。您需要在draw方法中设置覆盖物的位置,每当地图状态发生变化(比如:位置移动、级别变化)时,API都会调用覆盖物的draw方法,用于重新计算覆盖物的位置。通过map.pointToOverlayPixel方法可以将地理坐标转换到覆盖物的所需要的像素坐标。”

简单来讲就是比如地图缩放比例之后,会重新调用覆盖物中的draw方法,用于重新鸡算覆盖物的位置。

那么问题来了,draw方法哪里来的?

所以官方的意思是我们在自定义覆盖物中的构造函数定义一个draw方法,方法中我们利用百度地图的map.pointToOverlayPixel方法(用来将地理坐标转换为像素坐标)可以将地理坐标转换到覆盖物的所需要的像素坐标。
那么我们只需要在类中加入draw方法即可:

其中this.point就是我们构造函数中的point坐标点,40表示的是我们整个水波纹的初始宽高,读者其实可以将40改为可以传参的形式比如this.size,这样会方便后续代码的维护,这里为了直观的让读者理解就不讲太复杂了。

draw() {
  // 根据地理坐标转换为像素坐标,并设置给容器
  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`;
 }

到此,我们整个自定义覆盖物的类就已经实现了,整体代码图下(这里把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() {
  // 根据地理坐标转换为像素坐标,并设置给容器
  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`;
 }
}

自定义覆盖物的使用

那既然我们都已经实现了自定义的覆盖物,第一件事当然就是把它给使用上,具体如下:

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);   
	// 实例化自定义覆盖物,将坐标点和水波纹的尺寸传进构造函数中
   const radar = new RadarOverlay(point, 40);  
   // 添加自定义覆盖物
   map.addOverlay(radar);
  }

效果如图:

如何在vue中使用百度地图添加自定义覆盖物(水波纹)

结语

至于构造自定义覆盖物的其他内容,大佬们如果要深入的话可以参考百度地图的文档,里面讲的肯定要比作者更加详细(狗头)。如果文章的内容有问题话的欢迎留言点出,希望能与各路大佬们交流交流,喜欢作者的文章的话也别忘了给我点个赞,这对我来说很重要。

源码地址:https://gitee.com/zhao_jiahao/baidu-map-custom-cover

到此这篇关于如何在vue中使用百度地图添加自定义覆盖物(水波纹)的文章就介绍到这了,更多相关vue用百度地图添加自定义覆盖物内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JQuery 操作select标签实现代码
May 14 Javascript
javascript中字符串替换函数replace()方法与c# 、vb 替换有一点不同
Jun 25 Javascript
浅析LigerUi开发中谨慎载入common.css文件
Jul 09 Javascript
再谈Jquery Ajax方法传递到action(补充)
May 12 Javascript
jquery学习总结(超级详细)
Sep 04 Javascript
node.js中实现同步操作的3种实现方法
Dec 05 Javascript
javascript数据类型示例分享
Jan 19 Javascript
js实现为a标签添加事件的方法(使用闭包循环)
Aug 02 Javascript
JavaScript你不知道的一些数组方法
Aug 18 Javascript
JS获取当前地理位置的方法
Oct 25 Javascript
详解如何在项目中使用jest测试react native组件
Feb 09 Javascript
Vue使用mixin分发组件的可复用功能
Sep 01 Javascript
JavaScript语法约定和程序调试原理解析
Nov 03 #Javascript
解决vux 中popup 组件Mask 遮罩在最上层的问题
Nov 03 #Javascript
React Native登录之指纹登录篇的示例代码
Nov 03 #Javascript
解决VantUI popup 弹窗不弹出或无蒙层的问题
Nov 03 #Javascript
wepy--用vantUI 实现上弹列表并选择相应的值操作
Nov 03 #Javascript
使用vant的地域控件追加全部选项
Nov 03 #Javascript
vue vant中picker组件的使用
Nov 03 #Javascript
You might like
打造计数器DIY三步曲(下)
2006/10/09 PHP
PHP+XML 制作简单的留言本 图文教程
2009/11/02 PHP
PHP中的array数组类型分析说明
2010/07/27 PHP
php格式化日期实例分析
2014/11/12 PHP
PHP实现的ID混淆算法类与用法示例
2018/08/10 PHP
关于二级域名下使用一级域名下的COOKIE的问题
2011/11/07 Javascript
Prototype源码浅析 String部分(四)之补充
2012/01/16 Javascript
jQuery-Tools-overlay 使用介绍
2012/07/14 Javascript
js操作iframe兼容各种主流浏览器示例代码
2013/07/22 Javascript
jQuery+CSS3文字跑马灯特效的简单实现
2016/06/25 Javascript
JS给swf传参数的实现方法
2016/09/13 Javascript
w3c编程挑战_初级脚本算法实战篇
2017/06/23 Javascript
微信小程序下拉刷新PullDownRefresh的使用方法
2018/11/29 Javascript
原生js实现公告滚动效果
2021/01/10 Javascript
postman自定义函数实现 时间函数的思路详解
2019/04/17 Javascript
layui 关闭open弹出框 刷新table表格页面的方法
2019/09/16 Javascript
详解JavaScript 中的批处理和缓存
2020/11/19 Javascript
微信小程序实现分页加载效果
2020/11/19 Javascript
vue中配置scss全局变量的步骤
2020/12/28 Vue.js
[33:19]完美世界DOTA2联赛PWL S2 PXG vs InkIce 第一场 11.26
2020/11/30 DOTA
详解Python if-elif-else知识点
2018/06/11 Python
详解python中的装饰器
2018/07/10 Python
Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例
2018/07/27 Python
python爬虫爬取微博评论案例详解
2019/03/27 Python
python sqlite的Row对象操作示例
2019/09/11 Python
Python搭建代理IP池实现获取IP的方法
2019/10/27 Python
Python如何避免文件同名产生覆盖
2020/06/09 Python
Python 的 __str__ 和 __repr__ 方法对比
2020/09/02 Python
美国最好的葡萄酒网上商店:Wine Library
2019/11/02 全球购物
计算机个人求职信范例
2014/01/24 职场文书
巾帼标兵事迹材料
2014/12/26 职场文书
幼儿园教师工作总结2015
2015/04/02 职场文书
董事长秘书工作总结
2015/08/14 职场文书
2015年度考核个人工作总结
2015/10/24 职场文书
导游词之鲁迅祖居
2019/10/17 职场文书
Python3接口性能测试实例代码
2021/06/20 Python