最近因为业务需求接触了mapbox这个插件,过程中踩了超多坑,现在就我接触到的一些资料与踩过的坑,总结一下,希望看到这篇文章的码友们能帮助到你们。
官方文档:
英文版:https://docs.mapbox.com/mapbox-gl-js/
中文版:https://www.mapbox.cn/mapbox-gl-js/overview/
辅助文档:
数据交换格式: https://zh.wikipedia.org/wiki/GeoJSON
距离计算: https://turfjs.org/docs/
具体的用法官方文档写的很清楚,请多读文档,这里只讨论页面引入js的写法。
上面代码运行之后,会发现所有的资源加载的是mapbox网站的资源,这样导致我们页面打开速度慢,偶尔mapbox网站崩了,我们页面也打不开,所以就需要资源加载本地化。
如上图,即mapbox://styles/mapbox/streets-v11的具体内容,先把我们的代码修改之后如下:
/**
*{fontstack}请求字形时,此标记将替换text-font为符号图层属性中指定的字体堆栈中以逗号分隔的字体列表。
*{range}请求字形时,此标记将替换为256个Unicode代码点。
*例如,要为Unicode Basic Latin和Basic Latin-1 Supplement块加载字形,范围将为0-255。
*根据需要显示的文本,在运行时确定加载的实际范围。
*/
到此,资源本地化就完成了。但是我们现在渲染的地图是空白的,这是因为layers中什么都没,所以我们现在要结合**天地图**
来渲染中文地图。
pbf
pbf全称Protocal Buffers,是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。简单来说就是结构简单、速度快,我们前面讲到的矢量切片也使用了这种格式。
我们常见的字体库例如微软雅黑的.ttf字体文件大约有15M,一次请求加载15M并且还要解析,对服务端和客户端的压力都大,所以Mapbox使用了.pbf的格式进行分批请求,下面是两种格式的对比。.pbf格式大大的减少了请求压力。
关于pbf的详细可以看看这篇文章:https://www.cnblogs.com/ATtuing/p/9217029.html
除了天地图还可以使用百度地图,谷歌地图,高德等地图都可以,这里选择了天地图。
天地图官网:http://www.tianditu.gov.cn/
GeoGlobe JavaScript: http://jiangsu.tianditu.gov.cn/xuzhou/geomap-api/apidoc/jsNewApiDoc/index.html
GeoGlobe JavaScript API依赖GeoGlobe Server服务管理提供的OGC标准服务和应用服务,主要实现地理信息资源的共享和应用;
GeoGlobe开发中心网站通过对GeoGlobe JS API的方法调用,进行二次开发示例的集中展现,主要实现Web浏览器端的空间信息应用的示例表现。
页面引入GeoGlobeJS.min.js
var simple = {
version: 8,
name: "myMap",
sources: {},
layers: [],
sprite: "http://localhost:3000/map/sprite", //此处sprite的地址必须是url的地址
glyphs: "/map/font/{fontstack}/{range}.pbf", //fontstack 是字体的名字,也是文件名,range 是pbf的命名
visibility: "public",
created: "2020-04-01T00:00:00.000Z",
modified: "2020-04-01T00:00:00.000Z",
owner: "mapbox",
id: "blankMap",
draft: false,
};
var map = new GeoGlobe.Map({
style: simple,
container: 'map',
zoom: 4,
center: [0, 0],
isAttributionControl: false
});
map.on("load", function(e){
var layer_vtc = new GeoGlobe.TDTLayer("vec_w");
var layer_cva = new GeoGlobe.TDTLayer("cva_w");
map.addLayer(layer_vtc);
map.addLayer(layer_cva);
});
构造地图对象实例,并添加到id为map的div容器中,map加载中会添加两个图层,至此,一个中文版的地图就渲染完成。
地图底图渲染完成后,就是具体的页面逻辑操作了,此时重点就看mapbox的api了。
map.addSource('route', {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[-122.48369693756104, 37.83381888486939],[-122.48348236083984, 37.83317489144141],
[-122.48339653015138, 37.83270036637107],[-122.48356819152832, 37.832056363179625],
[-122.48404026031496, 37.83114119107971],[-122.48404026031496, 37.83049717427869],
]
}
}
});
map.addLayer({
'id': 'route',
'type': 'line',
'source': 'route',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#888',
'line-width': 8
}
});
map.removeLayer('route');
map.removeSource('route');
这一块的难点有3处:
1. GeoJSON
GeoJSON是一种基于JSON的地理空间数据交换格式,它定义了几种类型JSON对象以及它们组合在一起的方法,以表示有关地理要素、属性和它们的空间范围的数据。
GeoJSON使用唯一地理坐标参考系统WGS1984和十进制度单位,一个GeoJSON对象可以是Geometry, Feature或者FeatureCollection.
其几何对象包括有点(表示地理位置)、线(表示街道、公路、边界)、多边形(表示国家、省、领土),以及由以上类型组合成的复合几何图形。
具体详细信息请参考:https://zh.wikipedia.org/wiki/GeoJSON
如果你在地图上绘制图形的时候,没有报错,但是图形不显示,那一定是GeoJSON的格式问题!
2. 图层的类型
图层的类型由"type"属性指定,并且必须是One of"fill","line","symbol","circle","heatmap","fill-extrusion","raster","hillshade","background".
每个type属性,layout和paint也不尽相同。
具体请参照:
英文: https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#background
中文: https://www.mapbox.cn/mapbox-gl-js/style-spec/#sources-geojson
3. 表达式
表达式这一块对于js基础不扎实的同学来说可能会很吃力,不过多看看,多找些资料慢慢熟悉就好了。
mapbox的文档上用法写的也蛮清楚的,这里我就不多解释了。
var popup = new GeoGlobe.Popup({className: 'my-class'})
.setLngLat(e.lngLat)
.setHTML("Hello World!
")
.setMaxWidth("300px")
.addTo(map);
//详情请具体查看官网文档
var marker = new GeoGlobe.Marker()
.setLngLat([30.5, 50.5])
.addTo(map);
//创建多个marker,并清除:
var markers=[];
data.forEach((item,index)=>{
var el=document.createElement('div');
el.className = 'marker_button';
let marker_name = `marker_${index}`;
marker_name = new GeoGlobe.Marker(el)
.setLngLat([30.5, 50.5])
.addTo(map);
markers.push(marker_name);
})
//判断marker是否存在,如果存在,就删除
if (markers.length != 0) {
markers.map(item => {
item.remove();
})
}
//更多详情请具体查看官网文档
到此,mapbox的基本用法就讲完了,但是有一个重点–raster图层没有讲到,关于这个我会单独放到一篇文章中说,下篇文章见吧。
文章中如果有讲错的地方,请小伙伴们多指教,我也是第一次接触mapbox,要学习的东西还很多,欢迎小伙伴们多多留言交流。
有些mapbox的版本在map.getLayer(‘xx’), map.removeLayer(‘xx’)的时候会报错, 此时试试map.style.getLayer(‘xx’), map.style.removeLayer(‘xx’).
地图上展示某地的标记有三种方法:
symbol
LngLat
和LngLatBounds
表示地理世界中的点和面 坐标。Point
表示屏幕坐标系中的点。
两个坐标的转换可用map.project()来实现