赞
踩
首先准备好Vue项目,然后安装mapbox依赖:
npm install --save mapbox-gl
项目结构:
首先需要引用mapbox的css样式,虽然在index.html里面直接引用cdn也有效果,但是不建议直接修改index.html,后面会出现很多路径问题
推荐的方法是:首先将css样式下载到本地,然后再需要使用mapbox的组件里import样式:
@import "assets/css/mapboxgl.css";
@import "assets/css/mapboxgl2.css";
或者:
@import url('https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.2/mapbox-gl.css')
为了方便维护mapbox相关代码,推荐将绘图的代码单独封装在js文件中导出使用:
import * as mapdrawer from "../assets/js/drawMapFigure";
mapbox官网api文档:api文档
在mapbox的绘图js文件中,需要使用mapboxgl对象的时候,手动导入mapboxgl对象:
需要注意的是:在vue项目中,js配置文件中无法使用import语句来导入mapbox或者echarts之类的,原因是因为node文件中暂时还不支持import/export语法。正确方式是使用require语句进行引用。
然后再组件的mounted
方法里添加对地图的初始化,和相关的数据请求和绘图,就完成了地图的简单可视化:
在切换路由时通常需要清除地图的资源,由于mapbox的remove
方法是异步操作,所以在vue的beforeUnmounted
或者beforeDestroy
的生命周期函数中无法达到清除完资源再跳转的目的。解决的方法是使用beforeRouteLeave
函数,监听路由跳转,等到地图销毁执行完成后再跳转:
为了提升绘制效率,将网络图拆分成节点图层和边图层,绘制的时候首先添加边图层再添加节点图层。
边的绘制采用绘制geo路径的方法,但是只设置两个点。参考官网示例:添加 GeoJSON 线
官网的方式只能一次绘制一条线,为了批量绘制,这里我们将dataSource替换成FeatureCollection
然后再使用mapbox的addSource
方法添加数据源,addLayer
添加边图层,在自定义边的宽度等属性的时候,可以使用get
语法来获取原数据中的properties属性,例如:
"line-width": ["get", "link_width"],
绘制节点图层的方式和边类似,最终的效果如下:
捕获地图上的点击事件方法可以参考官网示例:点击弹窗
通过e.features
属性可以获取当前点击对象的数据属性,例如坐标和properties等。想要实现多选和双击取消效果,就必须要给每个节点设置一个状态属性,通过检测当前状态来决定是变色操作还是还原颜色。
为了记录节点的颜色状态同时保存节点的原始颜色,我们可以在节点数据的properties
里额外添加一个original_color
属性记录节点的原始颜色。通过比较当前颜色与原始颜色是否一致就能够判断当前节点的选中状态,从而决定点击事件的具体操作。
节点数据样例:
经过测试,mapbox的图层数据与图层不是动态绑定的,也就是说获取并修改当前节点的颜色并不能改变图层上节点的颜色,网上查阅了几篇博客发现可以使用setData
方法更新数据同时动态更新图层。
https://blog.csdn.net/qq_40696108/article/details/109765643
http://cn.voidcc.com/question/p-qbhkyoki-bma.html
其中,queryRenderedFeatures
方法获取到的数据对象其实和e.features
是相同的,不过e.features
只能获取到当前对象的部分数据。setData
方法传入的参数需要完整的geo类型的数据,也就是只能一次更新图层的全部数据。为了实现更新当前对象的同时保留其他节点的改变状态,理论上在每一次点击事件后,都应该去获取上一次被修改图层的数据,然后修改当前选中对象,再次更新数据。
我们知道设置图层的数据源方法是addSource
,对应的获取图层数据源的方法是getSource
,通过map.getSource("data_id")._options.data
获取到的数据就是相同格式的图层的数据源。每次修改数据前先获取图层数据,然后再更新。逻辑上是没有问题的,但是实际测试的时候发现使用setData更新数据后再使用getSource获取到的数据是没有经过修改的数据。官方文档没有详细的说明,个人猜测addSource
方法添加的数据是一次性的,setData
不能修改addSource
方法添加的数据。
不过有了思路换一种方式缓存数据就能实现,我们可以在data中缓存图层数据并在更新图层的时候同步修改数据,始终保持数据与图层的同步。
在做GIS可视化时,地图视图跳转快速定位以及路线的实时追踪是非常常见的业务需求。实现的核心方法是flyTo
,基本参数及案例参见官网。
https://docs.mapbox.com/mapbox-gl-js/example/flyto-options/
// This can be any easing function: it takes a number between
// 0 and 1 and returns another number between 0 and 1.
easing: (t) => t,
其中这个easing参数里的t
表示的是镜头飞行的进度,可以用于监听飞行事件以及触发自定义事件。不过有一点需要注意的是这个flyTo
是一个异步事件,在执行这个事件时地图的loaded
状态为false
,因此如果在这个事件之后写带有map.on("load",()=>{})
之类的事件时不会执行的。
为了实现飞行结束马上绘制相关的图形,就需要监听地图的事件执行状态,经过测试上述的easing函数不能完成这个功能,因为在easing中的t为1时,地图的loaded仍然为false。查阅了很多文章,发现地图还有一个idle
状态,可以通过监听该状态完成此项功能。
在渲染完地图最后一帧并进入“空闲(idle)”状态之后触发,“空闲(idle)”状态是指:
无运行中的相机转换
所有即时请求的切片已加载完毕
所有淡入淡出/过渡动画都已完成
用户在放大地图或者切换定位时很容易丢失地理位置的全局概念,这时就需要有一个鹰眼地图实时显示用户当前浏览的区域在全局地图的位置状况,同时也可以使用鹰眼地图控制浏览的地图窗口。
鹰眼地图的原理其实就是再次创建一个mapbox的地图实例,通过监听关联绑定的父地图上的缩放和窗口移动事件来同步小地图的状态。具体实现十分复杂,github上有成熟的实现就不造轮子了。
详情参见相关源码:
mapbox中添加鹰眼
minMap 源码
源代码中的Minmap是通过将构造函数绑定到mapbox对象上进行托管的,这样在使用时还要考虑mapbox的引用顺序,耦合性太强,为了便于在vue项目中使用,我把源码中的构造函数使用es6的模块化进行导出,然后在创建地图的时候再统一的导入和使用。
小地图二次封装源码
使用方法:
首先导入minmap:
import Minimap from "./mapboxgl-control-minimap"
const mapboxgl = require("mapbox-gl");
mapboxgl.Minimap = Minimap;
初始化创建地图后,再实例化小地图,同时将小地图的实例对象绑定到地图的实例对象上,便于统一访问,同步更新视图
// 绑定小地图
let min_map = initMapAndMinMap(map);
//将小地图的实例对象绑定到地图的实例对象上
map.min_map = min_map._miniMap;
初始化小地图工厂函数:
/**
* 初始化小地图
* map:小地图需要绑定的父地图实例对象
*/
function initMapAndMinMap(map) {
let m_map = new mapboxgl.Minimap({
center: [118.127193, 24.491097],
zoom: 10.6,
width: "370px",
height: "350px",
style: ""
})
// 将小地图绑定到父地图,同时指定位置
map.addControl(m_map, 'bottom-right');
return m_map;
}
小地图和原始地图的创建方式相同,都可以传入初始化参数控制样式和属性,可以覆盖的样式属性如下:
{
//小地图的div id
id: "mapboxgl-minimap",
// 小地图初始宽高
width: "320px",
height: "180px",
//地图风格
style: "mapbox://styles/mapbox/streets-v8",
//地图的初始展示经纬度中心
center: [0, 0],
//缩放等级
zoom: 6,
// should be a function; will be bound to Minimap
zoomAdjust: null,
// if parent map zoom >= 18 and minimap zoom >= 14, set minimap zoom to 16
zoomLevels: [
[18, 14, 16],
[16, 12, 14],
[14, 10, 12],
[12, 8, 10],
[10, 6, 8]
],
// 小地图边框样式
lineColor: "#08F",
lineWidth: 1,
lineOpacity: 1,
fillColor: "#F80",
fillOpacity: 0.25,
// 交互操作开关
dragPan: false,
scrollZoom: false,
boxZoom: false,
dragRotate: false,
keyboard: false,
doubleClickZoom: false,
touchZoomRotate: false
}
由于小地图也是mapbox的实例对象,因此我们可以通过获取小地图的实例对象,在小地图上调用和父地图相同的绘制函数,可以实现同步绘制网络或者轨迹等等。
原理和代码参见:绘制轨迹箭头
效果:
To be continued…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。