作者:dominating
###前言
随着SuperMap iServer 9D的发布,iServer增加了许多的新功能,其中之一就是地图服务模块,矢量切片(tileFeature)资源增加了支持 mvt的表述。mvt矢量切片格式是mapbox标准的矢量切片,而我们的SuperMap iClient 9D 加入了MapboxGL框架,所以我们就可以通过SuperMap iClient 9D来对接SuperMap iServer 9D发布的矢量切片服务,制作出精美的矢量地图。
今天就简单为大家介绍下如何使用SuperMap iClient 9D for MapboxGL来修改地图风格。
###定义MapboxGL的map对象
var map = new mapboxgl.Map({
container: 'map', // container id
style: {
"version": 8,
"sources": {
"vector-tiles": {
"attribution": attribution,
"type": "vector",
"tiles": [host + "/iserver/services/map-beijing/rest/maps/beijingMap/tileFeature.mvt?returnAttributes=true&compressTolerance=-1&width=512&height=512&viewBounds={bbox-epsg-3857}&expands=0:0_2,132_128,138_64,141_32,143_16,145_8,147_4"]
},
},
"sprite": "http://iclient.supermapol.com/web/styles/osm/sprite",
"glyphs": host + "/iserver/services/map-beijing/rest/maps/beijingMap/tileFeature/sdffonts/{fontstack}/{range}.pbf",
"layers": []
},
center: [116.4, 39.9],
minZoom: 10,
zoom: 11
});
tiles,矢量切片的服务地址
sprite,用于渲染背景图案,填充图片,线条图案,点图标的图片url地址(由两个文件组成,索引文件和图片文件,可以使用iClient官网的资源,具体可以参考mapboxGL官方说明)
glyphs,字体库,字体样式资源url地址。 如果任意图层使用了text-field布局属性,此属性不能为空。(下面的symbol图层文字样式将会用到)
layers,需要绘制的图层,将按照顺序进行绘制
"layers": [
{
"id": " 四级道路L@北京", //唯一的图层名称
"type": "line", //图层类型
"source": "vector-tiles",
"source-layer": "四级道路L@北京",
"layout": { //布局样式
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": { //绘制样式
"line-color": "hsl(224, 22%, 45%)",
"line-width": {
"base": 1.55,
"stops": [
[13,1.8],
[20,20]
]
},
"line-opacity": 0.9
}
}
]
咱们主要围绕layers来介绍。layers属性列出了可用的所有图层,图层的类型由type属性指定,并且必须是background, fill, line, symbol, raster, circle, fill-extrusion中的一种。
除了背景类型的图层,每个图层都需要引用source。 图层将从source中获取数据,可选地过滤要素,然后定义这些要素的样式。
图层拥有两个子属性,用于确定如何渲染该图层的数据:layout和paint属性。
本篇文章主要介绍我们常用的几种图层类型
###图层类型
####background 背景图层
顾名思义也就是作为地图背景的图层,不需要指定source
map.addLayer({
"id": "background",
"type": "background",
"layout": {
"visibility":"visible"
},
"paint": {
"background-color": "hsl(55, 1%, 20%)" //背景颜色
}
});
可以设置不同颜色的背景图层。注意,MapboxGL中颜色以各种允许的格式写成JSON字符串,HTML格式的十六进制,rgb,rgba,hsl和hsla,也可以使用预定义的HTML颜色名称,如"blue","yellow
{
"line-color": "#ff0",
"line-color": "#ffff00",
"line-color": "rgb(255, 255, 0)",
"line-color": "rgba(255, 255, 0, 1)",
"line-color": "hsl(100, 50%, 50%)",
"line-color": "hsla(100, 50%, 50%, 1)",
"line-color": "yellow"
}
####fill 填充图层
可以理解为面图层
map.addLayer({ //绿地
"id": "绿地R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "绿地R@北京",
"paint": {
"fill-color": "hsl(100, 58%, 76%)", //填充色
"fill-opacity": { //填充透明度
"base": 1,
"stops": [ //线性变化
[
5,
0
],
[
7,
0.5
]
]
}
},
});
//湖泊、水库
map.addLayer({
"id": "湖泊、水库R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "湖泊、水库R@北京",
"paint": {
"fill-color": "hsl(196, 80%, 70%)"
}
});
可以对面的填充色,透明度,轮廓线颜色进行修改
fill-outline-color ,填充的轮廓颜色。默认为填充颜色
####stop属性
可以注意到代码中我们使用到了一个“stop”属性,这个值被指定为一个函数,该函数是根据输入和输出值进行定义,一组输入值和输出值被称为"stop"。该函数允许你通过使用缩放地图级别来改变地图要素的外观。
"fill-color": "hsl(100, 58%, 76%)",
"fill-opacity": {
"base": 1,
"stops": [
[5,0],
[7,0.5]
]
}
每个stop是由两个元素组成的数组,第一个是缩放级,第二个是函数输出值。以上例子中,当缩放级为5时,fill-opacity为0,当缩放级为7时,fill-opacity为0.5。fill-opacity的值将从第5级的0线性过渡到第七7级的0.5。"base"参数为内插曲线指数基数,将会影响到两个stop之间的线性变化。我们可以通过两张图来增加理解
当前我的缩放级为5.2,可以看出不同base值的曲线的值是不一样的。
####line 线图层
map.addLayer({
"id": " 三级道路L@北京",
"type": "line",
"source": "vector-tiles",
"source-layer": "三级道路L@北京",
"paint": {
"line-width": { //线宽
"base": 1.5,
"stops": [
[11,1],
[18,10]
]
},
"line-color": "hsl(0, 0%, 100%)", //线颜色
}
});
map.addLayer({
"id": " 二级道路L@北京",
"type": "line",
"source": "vector-tiles",
"source-layer": "二级道路L@北京",
"paint": {
"line-width": 4,
"line-color": "hsl(230, 24%, 87%)",
}
});
map.addLayer({
"id": "一级道路L@北京1",
"type": "line",
"source": "vector-tiles",
"source-layer": "一级道路L@北京",
"layout":{
"line-cap":"butt", //线段末端样式
"line-join":"miter" //线段交汇处样式
},
"paint": {
"line-width": {
"base": 1.5,
"stops": [
[11,6],
[18,26]
]
},
"line-color": "hsl(230, 24%, 87%)",
"line-opacity": { //线透明度
"base": 1,
"stops": [
[10.99,0],
[11,1]
]
},
}
});
以上例子的line图层,有三种不同样式的道路。我们可以对线的颜色,宽度,透明度,光晕效果进行修改,以及对线头,线交汇处等这样的细节作出调整
其他常用的线样式属性:
line-blur:线的模糊度,默认为0
line-gap-width:在一条线实际路径外画一条线壳。值表示内部间隙的宽度。
####symbol 符号图层
包括文字,图标。
//道路名称
map.addLayer({
"id": " 一级道路Name",
"type": "symbol", //类型为symbol
"source": "vector-tiles",
"source-layer": "一级道路L@北京",
"layout": {
"text-line-height": 1.1, //行高
"text-size": { //字体大小
"base": 1.5,
"stops": [
[13.99,12],
[20,24
]
},
"text-font": [ //字体类型
"DIN Offc Pro Italic",
"Arial Unicode MS Regular"
],
"symbol-placement": "line", //符号位置,默认为point,由于是道路名称所以设置为line
"text-field": "{道路名称}", //需要显示的字段名称
"text-letter-spacing": 0.1, //字间距
"text-max-width": 5 //文本换行最大行宽
},
"paint": {
"text-color": "hsl(0, 0%, 0%)", //字体颜色
"text-halo-color": "hsl(0, 0%, 100%)", //字体光晕颜色
"text-halo-width": 1.25, //光晕宽度
"text-opacity": { //文字透明度
"base": 1,
"stops": [
[13.99,0],
[14,1]
]
},
},
});
map.addLayer({
"id": "医疗卫生@北京",
"type": "symbol",
"source": "vector-tiles",
"source-layer": "医疗卫生@北京",
"layout": {
"icon-image": "hospital-11", //图标id
"text-offset": [0, -0.5], //文字偏移量
"text-anchor": "bottom", //文字锚点,支持center, left, right, top, bottom, top-left, top-right, bottom-left, bottom-right,默认center
"text-field": "{NAME}",
"text-size": 12
},
"paint": {
"text-color": "hsl(0, 0%, 78%)",
"text-halo-color": "#212121",
"text-halo-width": 1,
"text-halo-blur": 0
}
});
map.addLayer({
"id": "其它@北京2",
"type": "symbol",
"source": "vector-tiles",
"source-layer": "其它@北京",
"layout": {
"icon-image": "car-11",
"text-offset": [0, -0.5],
"text-anchor": "bottom",
"text-field": "{NAME}",
"text-size": 12
},
"filter": [ //过滤条件
"==",
"NAME",
"停车场"
],
"paint": {
"text-color": "hsl(0, 0%, 0%)",
"text-opacity": 1,
"text-halo-color": "hsl(0, 0%, 100%)",
"text-halo-width": 1,
"text-halo-blur": 1
}
});
以上例子可以看出来,我们可以通过symbol图层对点,线的标签以及点符号进行绘制。我们几乎可以对它们进行任意的操作。以下是我们在symbol图层中需要注意的地方:
layout中的symbol-placement,默认为point,如果要显示线标注,需要修改为line,这样就沿线标注了
text-field的值为需要显示的字段名称,用{fieldname}格式填写
text-anchor ,文字的锚点,包括有center, left, right, top, bottom, top-left, top-right, bottom-left, bottom-right,默认center
text-offset,文字偏移量,正值表示右和下,负值表示左和上
icon-image,用于绘制的图片在sprite中的图像名称,所以配文字图层的时候,我们需要知道sprite中有哪些图片和对应的名称
####filter过滤器
可以看出我们最后添加的图层上使用了过滤器filter,MapboxGL的过滤器可以说是非常强大的。过滤器支持以下形式的数组:
存在过滤(Existential Filters)
["has", key] feature[key] exists
["!has", key] feature[key] does not exist
比较过滤器(Comparison Filters)
["==", key, value] equality: feature[key] = value
["!=", key, value] inequality: feature[key] ≠ value
[">", key, value] greater than: feature[key] > value
[">=", key, value] greater than or equal: feature[key] ≥ value
["<", key, value] less than: feature[key] < value
["<=", key, value] less than or equal: feature[key] ≤ value
设置成员资格过滤器(Set Membership Filters)
["in", key, v0, ..., vn] set inclusion: feature[key] ∈ {v0, ..., vn}
["!in", key, v0, ..., vn] set exclusion: feature[key] ∉ {v0, ..., vn}
组合过滤(Combining Filters)
["all", f0, ..., fn] logical AND: f0 ∧ ... ∧ fn
["any", f0, ..., fn] logical OR: f0 ∨ ... ∨ fn
["none", f0, ..., fn] logical NOR: ¬f0 ∧ ... ∧ ¬fn
key必须是一个字符串,用来标识要素属性或者是下面的特殊键:
value必须是一个字符,数字或者布尔值才能用来比较属性值,如
["==", "NAME", "停车场"]
设置成员资格过滤器可以用来测试字段是否匹配多个值。这个过滤就是要求要素的class必须是"street_major", “street_minor”, "street_limited"中的一个。
["in", "class", "street_major", "street_minor", "street_limited"]
“all”,“any”,和"none"操作符用于创建复合过滤。值f0,…,fn必须是过滤表达式,比如以下的例子
[
"all",
["==", "class", "street_limited"],
[">=", "admin_level", 3],
["!in", "$type", "Polygon"]
]
这个组合过滤器由三个过滤表达式组成,要求此要素必须满足这三个条件,class需要是"street_limited",admin_level必须大于等于3,类型type不能是多边形。当然你也可以换成any,满足其中之一或者多个条件,或者使用none来取反。
###结语
以上的话就是MapboxGL地图风格中常用的几种图层类型以及相关函数的简单介绍。可以看出如果要配出一幅精美的地图的话是非常需要耐心和时间的。其实我们也可以借助Mapbox的mapbox studio可视化编辑工具来制作地图。我们可以在工具中将地图的风格配置好,然后导出风格文件,做相关修改后使用在我们自己的地图中。
Mapbox studio地址:https://www.mapbox.com/mapbox-studio/
更多详细请参考:https://www.mapbox.com/mapbox-gl-js/style-spec