最近在单位着手开发一个新项目,需要用到MapboxGL,于是开一篇新的博客,做一些开发阶段的笔记。这里只记录开发的常用示例以及所遇到的问题,不会对基础API进行赘述。
一.去除 accessToken 验证
因为该项目是内网使用,不访问互联网,不使用 mapbox 在线地图,所以需要去除 Mapbox 的 accessToken 验证,进行离线本地化。
具体步骤是修改 mapbox-gl.js,搜索 if(t&&(t.message===e.AUTH_ERR_MSG||401===t.status)),将这段代码替换成 if(t&&false)就可以了。另外使用官网的调用示例来初始化地图时,把 style 属性也删掉,否则还是会触发 accessToken 验证。
二.字体本地化部署
渲染文字标注时,遇到报错:use of “text-field” requires a style “glyphs” property。这是因为 mapbox 使用的字体是 pbf 格式,由于使用的是 mapbox 离线版本,所以需要字体本地化部署。
具体步骤:将 mapbox 的在线字文件引入到本地,放到 public 文件夹下,并在初始化地图时加入以下声明:
1 | glyphs: './glyphs/mapbox/{fontstack}/{range}.pbf'; |
刚开始我还遇到报错:Uncaught Error: Unimplemented type: 4,折腾了好一阵子,最后对比控制台的字体请求,发现是字体文件名没有对应上,将文件名改成和控制台请求的一致即可。
PS:如果需要用到 mapbox 图标,也需要进行图标的本地化部署。
参考链接:
MapBoxGL message: “Unimplemented type: 4“
三.初始化地图
1 | const map = new mapboxgl.Map({ |
注意:
geoserver自带EPSG:4326和EPSG:900913,而mapbox只支持EPSG:3857坐标系,如果对接geoserver的wmts地图,需要对接EPSG:900913的地图,因为3857和900913的参数是一致的。
如果需要在mapbox使用4326地图,可以使用cgcs2000提供的4490坐标系版本的mapbox。默认GridSet4326比GridSet4490少一个等级,初始化地图图层就要添加zoomOffset:-1的配置。不过这个是基于mapbox2.3.0的,不能使用较新版本的API。参考链接:mapbox添加4326/4490底图瓦片/WMS
四.渲染 marker
1.单个 marker(使用默认图标)
此时marker在地图上是以div标签进行渲染的,性能较差,不适合海量点渲染
1 | new mapboxgl.Marker().setLngLat([120.143, 30.236]).addTo(map); |
2.单个marker(使用自定义图标)
此时marker在地图上是以img标签进行渲染的,性能较差,不适合海量点渲染
1 | const el = document.createElement('img'); //自定义标记点图片 |
3.多个marker(使用图标库或者自定义图标均可以)
此时所有marker都会渲染在symbol layer中,支持icon标记点和label文字标记点同时渲染,而且可以开启碰撞检测,适合海量点渲染
1 | map.on('load', () => { |
五.渲染popup
1.渲染简单popup
setHTML可以传递html字符串,渲染时会解析成html内容
1 | const popup = new mapboxgl.Popup({ className: 'my-class' }).setHTML('<div>测试popup</div>'); |
2.将自定义组件挂载到popup中
当popup中需要展示复杂组件时,特别是需要列表渲染或需要监听popup中内容的事件的情况下,使用法1的html字符串插入会使代码变得臃肿而且难以维护,这时可以使用vue创建虚拟节点,再挂载到popup中。
1 | <!-- MyCom.vue --> |
1 | import { nextTick, onMounted, h, render } from 'vue'; |
参考链接:
vue.js 在Mapbox GL JS中添加自定义html弹出点击事件
Vue3 学习笔记 —— 函数式编程、createVNode、render、h 函数
mapbox popup挂载自定义组件 (vue2的方式)
3.去除popup关闭按钮的黑色边框
1 | .mapboxgl-popup-close-button { |
六.渲染圆形区域
1.半径为固定像素的圆形区域
1 | map.addLayer({ |
2.半径为米或千米的圆形区域
首先安装@turf/circle
1 | npm install @turf/circle |
渲染区域
1 | import turf_circle from '@turf/circle'; |
3.注意事项
初始化地图后不要立刻加载圆形图层,否则会报错 Style is not done loading。可以监听地图加载完成后再加载图层
1 | map.on('load', () => { |
七.渲染区域掩膜
1 | map.addLayer({ |
参考链接:
八.清除图层及注意事项
map.addLayer往地图添加layer,使用map.removeLayer可以移除图层。当直接使用map.Layer添加图层,示例代码:
1 | map.addLayer({ |
而后根据id移除该图层
1 | map.removeLayer('layer1'); |
此时会发现,如果再次添加图层layer1,会报错:There is already a source with this ID。这是因为在添加图层layer1时,会默认添加sourceId为layer1的source,相当于map,addSource(‘layer1’, {…}),使用removeLayer清除时,由于没有清除对应的source,就会报错。解决办法是在removeLayer的同时,调用removeSource。
1 | map.removeSource('layer1'); |
九.绘制工具
使用的是mapbox-gl-draw,功能挺多样,英文文档地址:docs/API.md。