基于MapboxGL的样式文件自动生成图例

来源:互联网 发布:视频点播php源码 编辑:程序博客网 时间:2024/05/01 06:43

MapboxGL是一个基于WebGL的地图绘制引擎,其地图样式采用一个json格式的文件进行描述,但是对于渲染的地图,Mapbox并没有提供图例的生成方法,因此需要自己根据这个样式描述文件来生成地图图例。
MapboxGL中数据与样式是分开的,地图的所有样式都是由这个唯一的样式描述文件来描述。并不是地图中的所有样式都需要图例,例如简单的文字注记就不需要生成图例,而且MapboxGL的样式中对同一个数据源(例如:铁路)会有多个样式图层(style layer)描述其样式(例如:灰色的实线图层加白色的虚线图层)。因此基于该样式文件绘制图例至少要先解决两个难题:
1. 从众多的样式中筛选出哪些样式需要绘制图例;
2. 从筛选出的样式中提取哪些样式描述的是同一个数据源。

一、 筛选需要绘制图例的图层

首先我们需要将所有的样式图层进行分类,按照要素类型分为点、线、面三类,分别为pointLayerslineLayerspolygonLayers
其次分别从中筛选出需要绘制图例的图层,删掉不需要绘制图例的图层。筛选规则很简单,对于所有要素都需要满足以下条件:
1、当前地图的级别必须在样式图层的可见级别范围之内。例如当前地图为第8级,而某一个样式的可见范围是9-12,那么这个样式是可以被忽略的。
2、图层的visibility属性设置的为“visible”,即必须可见。
理论上来说只要满足以上两个条件,那么这个图层在当前地图级别就是可见的,但是对于点状要素来说还有一个条件:
3、如果为点状要素的样式,则该样式必须具有“icon-image”属性。即该点状符号具有图标,而不是纯文字。

二、 合并同一数据源的图层

经过以上筛选后,上下的样式都是需要绘制图例的,但是有些样式可能描述的是同一个数据源,对于这些样式应该属于一个要素,因此需要合并。怎样判断哪些样式是属于统一数据源呢,基本原则如下:
1、type必须相同,都是线状或都是面状。
2、source属性必须相同,即同一数据源。
3、source-layer属性必须相同,即同一数据图层。
4、filter必须相同,具有相同的数据过滤条件。
满足以上要求被认为是描述的同一个数据要素。

三、 绘制图例

经过以上步骤得到的应该就是所有需要绘制图例的样式了,而要对图例进行可视化就需要选择对应的渲染引擎对图例进行渲染,目前我使用过的有两种渲染方法:
1、采用WebGL渲染
考虑到MapboxGL本身就是基于WebGL渲染的,而现在筛选后的图例的样式正好与地图的样式具有相同的格式,可以考虑直接用MapboxGL渲染到地图上,这时就需要创建geojson数据源。根据点线面三种类型分别创建三种geojson的模板,然后根据筛选出的图例样式的类型,分别获取对应的geojson,并利用图例样式对其进行符号化。
2、采用svg渲染
采用WebGL的方法渲染缺点是不方便编辑,而且采用的经纬度的坐标,相当于重新建立一个map。而svg则更加轻量,并且可以缩放和编辑。
但是svg的样式描述采用的dom属性的方式,因此与不能直接使用筛选的图例样式,而要转换成svg支持的属性。
附件(图例自动生成实例):
① 一个完整的Style Json文件如下:

{  "name": "新闻",  "version": 8,  "sources": {    "data2012": {      "type": "vector",      "url":"http://192.9.105.205:8090/api/v1/tilesets/foxgis/admin"    }  },  "sprite": "http://192.9.105.205:8090/api/v1/sprites/foxgis/Hk6NFtw8/sprite",  "glyphs": "http://192.9.105.205:8090/api/v1/fonts/foxgis/{fontstack}/{range}.pbf",  "layers": [    {      "id": "背景",      "type": "background",      "paint": {        "background-color": "#87c2e4"      }    },    {      "id": "亚洲面",      "type": "fill",      "source": "data2012",      "source-layer": "asia_a",      "paint": {        "fill-color": "#ebecec",        "fill-opacity": 1,        "fill-outline-color": "#ebecec"      }    },    {      "id": "国界",      "type": "line",      "source": "data2012",      "source-layer": "china_l",      "maxzoom": 11,      "paint": {        "line-color": "#e8ae59",        "line-width": 5      }    },    {      "id":"国界光晕",      "type":"line",      "source":"data2012",      "source-layer":"china_l",      "minzoom":3,      "maxzoom": 11,      "paint":{        "line-offset":-3,        "line-color":"rgba(255, 214, 211, 0.98)",        "line-width":{          "stops":[[3,4],[4,6],[6,8]]        }      }    },    {      "id": "省界线",      "type": "line",      "source": "data2012",      "source-layer": "boua_prov",      "minzoom": 4,      "maxzoom": 9,      "layout": {        "line-cap": "round",        "line-join": "round"      },      "paint": {        "line-color": "rgb(150,150,150)",        "line-width": 1,        "line-dasharray": [1.5,3]      }    },    {      "id": "县界",      "source": "data2012",      "source-layer": "boua",      "metadata": {        "replaceLayer": true      },      "minzoom": 7,      "maxzoom": 11,      "type": "line",      "filter": ["==","pac",320111],      "layout": {        "line-join": "round",        "line-cap": "round"      },      "paint": {        "line-color": "rgb(0,0,255)",        "line-width": 2,        "line-dasharray": [3,3]      }    },    {      "id":"铁路(实线)",      "source":"data2012",      "source-layer":"lrrl",      "minzoom":7,      "maxzoom":11,      "filter":["any",        ["==","gb",410101],        ["==","gb",410102],        ["==","gb",410103],        ["==","gb",410200]      ],      "type":"line",      "paint":{        "line-width": 2.4,        "line-color":"#949494"      }    },    {      "id":"铁路(虚线)",      "source":"data2012",      "source-layer":"lrrl",      "minzoom":7,      "maxzoom":11,      "filter":["any",        ["==","gb",410101],        ["==","gb",410102],        ["==","gb",410103],        ["==","gb",410200]      ],      "type":"line",      "paint":{        "line-width":1.2,        "line-color":"#fff",        "line-dasharray":[10,10]      }    },    {      "id": "省名注记",      "source": "data2012",      "source-layer": "prov_label",      "type": "symbol",      "minzoom": 4,      "maxzoom": 5,      "layout": {        "text-size": 12,        "text-font": [          "STXinwei Regular"        ],        "symbol-placement": "point",        "text-field": "{name}",        "text-max-width": 8      },      "paint": {        "text-color": "rgb(250,0,0)",        "text-halo-color": "rgb(255,255,255)",        "text-halo-width": 1.5,        "text-halo-blur": 1      }    },    {      "id": "首都注记",      "type": "symbol",      "source": "data2012",      "source-layer": "agnp",      "filter": ["==","capname","北京"],      "minzoom": 3,      "maxzoom": 11,      "layout": {        "text-size": 14,        "icon-image": "star-15",        "text-font": ["SimHei Regular"],        "symbol-placement": "point",        "text-allow-overlap": false,        "text-offset": [0,1],        "text-anchor": "top",        "text-field": "{capname}",        "text-letter-spacing": 0.02,        "text-max-width": 8      },      "paint": {        "text-color": "rgb(255,0,0)",        "text-halo-color": "rgb(255,255,255)",        "text-halo-width": 1.5,        "text-halo-blur": 1      }    },    {      "id": "省会城市注记",      "type": "symbol",      "source": "data2012",      "source-layer": "agnp",      "filter": ["==","class","AB"],      "minzoom": 5,      "maxzoom": 8,      "layout": {        "text-size": 15,        "icon-image": "circle-11",        "text-font": [          "SimHei Regular"        ],        "symbol-placement": "point",        "text-offset": [0,0.7],        "text-anchor": "top",        "text-field": "{capname}",        "text-letter-spacing": 0.02,        "text-max-width": 8      },      "paint": {        "icon-color": "#ff0000",        "text-color": "rgb(20,20,20)",        "text-halo-color": "rgb(255,255,255)",        "text-halo-width": 1.5,        "text-halo-blur": 1      }    },    {      "id": "地级市注记",      "type": "symbol",      "source": "data2012",      "source-layer": "agnp",      "minzoom": 7,      "maxzoom": 11,      "layout": {        "text-line-height": 1.2,        "text-size": 13,        "symbol-avoid-edges": true,        "icon-image": "circle-11",        "text-ignore-placement": false,        "text-max-angle": 38,        "text-font": [          "SimHei Regular"        ],        "symbol-placement": "point",        "visibility": "visible",        "text-offset": [0,0.7],        "icon-optional": false,        "text-rotation-alignment": "viewport",        "text-anchor": "top",        "text-field": "{name}",        "text-letter-spacing": 0.02,        "text-max-width": 8      },      "paint": {        "icon-color": "#ff0000",        "text-color": "#fe001f",        "text-halo-color": "rgb(255,255,255)",        "text-halo-width": 1.5,        "text-halo-blur": 1      }    },    {      "id": "县注记",      "source": "data2012",      "source-layer": "agnp",      "filter": ["any",["==","class","AE"],["==","class","AF"]],      "minzoom": 8,      "maxzoom": 11,      "type": "symbol",      "layout": {        "text-size": 13,        "icon-image": "circle-stroked-11",        "text-max-angle": 38,        "text-font": ["SimHei Regular"],        "symbol-placement": "point",        "text-anchor": "top",        "text-field": "{name}",        "text-letter-spacing": 0.02,        "text-max-width": 7      },      "paint": {        "text-color": "rgb(60,60,60)",        "text-halo-color": "rgb(255,255,255)",        "text-halo-width": 1.5,        "text-halo-blur": 1      }    }  ]}

② 经过第一步筛选后
从中筛选出需要绘制图例的图层,例如其中的“县注记”、“省名注记”等纯文字注记就被剔除掉了,得到的结果如下图,共有10个图层:
共有10个图层
这里我是打算采用svg的绘制方式,所以对其样式进行了转换,只保留了svg需要用到的样式:
这里写图片描述

③ 经过第一步筛选后
以上得到的图例样式有些样式描述的是同一要素,例如铁路有虚线和实线两个图层,国界有边线和光晕两个图层,因此需要进行合并。合并后的结果如下图所示:
这里写图片描述
可以发现合并后剩下8个图层,铁路和国界的两个样式合并到一个数组。

④ SVG绘制

剩下的就是根据这个图例数组绘制svg了,绘制效果如下图:
这里写图片描述

这些图例只是地图上可能需要展示的所有图例,考虑到在实际制图中,可能有些不太重要的要素并不一定需要绘制在地图上,因此我在自动生成图例的基础上加入了人工控制,用户可以自行选择显示哪些图例,并且可以设置图例的列数、顺序、文字内容、字体、字号等属性。
这里写图片描述

这里写图片描述

0 0
原创粉丝点击