背景
最近公司准备开发一款大屏可视化应用,主要想用来展示公司客户的一些数据情况以及用户区域分布情况。大体就是左右两边放置一些数据图表,中间放置一张科技感很强的地图。数据图表开发我想对于一般前端来说肯定都是很简单的需求了,但是中间地图,需要做到自定义。从目前团队来说,大家都比较缺乏
gis
开发经验,接到需求的那一刻大家也是对地图开发做了一番调研。
可视化地图开发调研
集合众人之力,一开始预定了几个方案:
百度地图
:可定制样式,但是可自定义样式比较少,不能满足目前需求高德地图
:可定制样式,和百度地图类似Echarts
: 貌似效果还不错,自定义能力也挺强的Leaflet
: 自定义能力强,但是只支持2D地图Cesium
: 自定义能力强,可以加载第三方图层等,效果也比较好,但是上手难度大,支持3DMapbox
: 自定义能力强,样式效果比较好看,上手简单,有很强的自定义样式的工具,支持3D- ...
经过比较,最终选择 Mapbox
Mapbox
MapBox 提供了多个平台的
SDK
以及开放式的api
,可以在Android
ios
web
React Native
Qt
Unity
使用以及多种的Rest Api
. 由于项目主要是 web 端的,运行在浏览器
直接查看 Map GL JS
在使用之前记得先注册账号获取 Token
:
Mapbox GL JS 基本原理
让我们一起来快速了解一下 Mapbox GL JS
。本指南包括 Web
地图 API
中的主要功能和常见模式,主要说明 Mapbox GL JS
与其它地图库的不同之处。用过 Leaflet
, Mapbox.js
,或者 OpenLayers
的用户可以在该文件了解到 Mapbox GL JS
与这几种地图库的差异。
Mapbox GL JS 的核心差异
客户端渲染
Mapbox GL JS
的核心特点是客户端渲染。在 Mapbox GL JS
中创建 Web
应用时,通过 JavaScript
和 WebGL
把地图作为 vector tiles 进行渲染。相比将服务器的一系列切片图片组合起来后再显示,通过 Mapbox GL JS
渲染可以快速改变样式,使得地图的呈现更加多样化。
Camera
这里的 Camera
指的是地图视角。Leaflet
或 Mapbox.js
库中的地图视角由中心点(centerpoint)和缩放级别(zoom level)决定,缩放级别通常为 0
到 22
之间的整数。Mapbox GL JS
也提供调整地图视角的参数。
- 中心点:按经度、纬度顺序排列.
- 缩放级别:可以是缩放范围内的任何数值。即使带有小数点,如 1.5 或 6.2,系统也可以正确渲染。
- 方位角(bearing):地图的旋转度。地图可以旋转,右边向上旋转的时候文本标注等详细内容也会正确显示。
- 倾斜度(tilt):地图视角倾斜时的度数。
图层(layers)
传统的 JavaScript 地图库有两种完全不同的 图层
:
- 基础图层(baselayers):构成地图基础的图像切片。通常包含大量数据——街道地图包括标注、建筑、图标等细节,在浏览器上渲染的话效果不会太好。可参考
Mapbox.js
中的L.mapbox.tileLayer
和Leaflet
中的L.TileLayer
。 - 叠加图层(overlays):通常包括
GeoJSON
之类的矢量数据,参考Mapbox.js
中的L.mapbox.featureLayer
和Leaflet
中的L.geoJson
。和基础图层相比,叠加图层包含的信息更少,但交互性更强:可在JavaScript
中进行修改,并且点击的时候会触发弹窗。
Mapbox GL JS
中的图层是对矢量数据或者 raster data
的风格化呈现。每个图层都将规定特定数据在浏览器中该如何绘制,渲染器(renderer)会通过这些图层把地图渲染到屏幕上。
如下图所示,随着缩放级别的改变,地图细节也会变化。地形、建筑、公共交通站台和位置信息都作为其相应的图层来渲染。由于通过Mapbox GL JS
,浏览器中的所有地图内容均以矢量数据的形式加载,Mapbox GL JS
对基础图层和叠加图层不作区分。因此标签、图标等地图要素节都可以通过 JavaScript
进行修改,与以前的地图库中的叠加图层类似。当然,这也意味着更改图层样式的函数和方法会更细化一点,接下来我们会详细说明。
添加地图
每一个 Mapbox GL JS
项目的基础为mapboxgl.Map
类。
var map = new mapboxgl.Map({ // container id container:'map', // style location style:'mapbox://styles/mapbox/streets-', // starting position center:[-74.50, 40], zoom:9 });
它与 Leaflet
的L.Map
类或 Mapbox.js
的 L.mapbox.map
相似,但有几个核心的差异:
坐标
Mapbox GL JS
将坐标处理为数组形式(如[-74.50, 40]),按照 longitude
, latitude
的顺序排列(而不是 Leaflet 和 Mapbox.js
中latitude
, longitude
的顺序)。这一顺序与 GeoJSON
中的坐标、其他地理空间格式以及数学中的 X,Y
顺序一致。
地图样式(style)
地图通过 URL mapbox://styles/mapbox/streets-v
加载样式。该 URL 链接到一个远程文件,地图将其载入后,会用其确定tilesets以及如何为终端客户呈现样式。Mapbox GL JS 在某些地方只允许使用 URLs,不允许字符数据(literal data),包括数据源。
同 JavaScript
库中的其它远程数据源一样,这些数据源是异步的。因此相关代码会使用事件绑定来保证地图在正确的时候做出改变。例如:
map.on('load', function() { map.addLayer({ id:'terrain-data', type:'line', source:{ type:'vector', url:'mapbox://mapbox.mapbox-terrain-v2' }, 'source-layer':'contour' }); });
当且仅当地图数据源加载之后(包括地图样式),上述代码会使用map.on('load', function()
{ 来运行map.addLayer。立即运行map.addLayer会导致错误,因为addLayer将在样式上添加一个图层,而目标样式尚未加载成功。
另外还有两种不同的方法改变地图位置:jumpTo
和 easeTo.jumpTo
和老式的地图导航工具类似:能够即刻显示另一个位置。easeTo很棒
:能够智能地显示缩放
、方位角
、倾斜度等
数值,方便记录地图的详细移动情况。
给地图添加数据
可使用addLayer()
方法将数据作为图层添加到地图中。addLayer
将对象视作包括id
(由用户创建)和type
属性的参数。添加图层时,需要提供source
,令渲染器能够使用数据去绘图,可以选择指定layout
和 paint
属性,告诉渲染器如何进行绘制。
添加图层数据源(source)
可以使用 Mapbox GL JS
的addSource()
方法添加数据源。该备选方法可以达到同样的地图性能,但是有些时候我们更推荐保持代码的可读性。
添加新图层时需要添加数据源。图层数据源包括type和url,意味着所有的图层类型(type)都可以作为远程数据源获取(像 Map 中的style一样)。总共有五种图层类型,每种都有自己的properties:
vector tiles
raster tiles
GeoJSON
image
video
矢量数据源同样需要包含一个source-layer
,需使用来自矢量文件数据源的图层名称(一般是初始文件的名称)。示例:
map.on('load', function() { map.addLayer({ id:'rpd_parks', type:'fill', source:{ type:'vector', url:'mapbox://mapbox.3o7ubwm8' }, 'source-layer':'RPD_Parks' }); });
Layout 和 paint 属性设置
图层包含两个子属性来完成数据样式的添加:Paint
和 layout
.用于明确如何渲染地图数据。Layout属性指渲染位置和可见性
,应用于渲染过程的早期阶段。paint指更精细的渲染样式
,如不透明度、颜色和翻译。不需要大量处理,在后期阶段进行渲染。
下列代码展示了如何往地图中添加图层,将公园部分填充为绿色。
此外,如果使用addSource()
方法添加数据源的话需要包括 id
,如 addLayer()中的source一样。
map.on('load', function() { map.addLayer({ id:'rpd_parks', type:'fill', source:{ type:'vector', url:'mapbox://mapbox.3o7ubwm8' }, 'source-layer':'RPD_Parks', layout:{ visibility:'visible' }, paint:{ 'fill-color':'rgba(61,153,80,0.55)' } }); });
成品:缩放显示 San Francisco,和将公园填充为绿色的图层。该图层以该城市公园土地数据的矢量数据源为基础而绘制。