# Web符号库技术专题

# 概述

SuperMap iClient for MapboxGL 通过扩展 MapboxGL 的 API,实现了对 Web 符号库的支持,为用户提供了前后端一致的 Web 符号化制图能力,并且支持自定义 Web 符号,满足用户多样化的制图需求。

为了便于您在 SuperMap iClient(以下简称:iClient)中快速上手 Web 符号制图,本文主要从以下几个部分对 Web 符号库进行了介绍:

  • 支持情况:Web 符号库当前对桌面端产品 Supermap iDesktop/iDesktopX (以下简称:iDesktop/iDesktopX)中符号的覆盖情况;
  • 制图效果:Web 符号库与 iDesktop/iDesktopX 中的点、线、面符号样式以及制图效果的对比展示;
  • 使用说明:如何在 iClient 中为图层设置 Web 符号、进行数据驱动制图、自定义 Web 符号样式;
  • 制图流程:从新建页面文件开始,在 iClient 中使用 Web 符号的完整制图流程;
  • 参考示例:iClient for MapboxGL 提供的协助开发的参考示例,即 Web 符号库 和 Web 符号编辑器。

# 支持情况

iClient for MapboxGL 目前覆盖了桌面端产品 iDesktop/iDesktopX 中的大部分基础符号,下面列出了 Web 符号的覆盖情况:

表 Web符号支持情况
桌面端基础符号 Web符号库支持情况
点符号 城市
行政等级组符号
人口等级
居民地及设施
定位基础
天气预报
交通
水系
土地调查 -
防汛抗旱 -
地貌 -
管线 -
线符号 行政界线
交通
水系
道路方头
地铁
定位基础
居民地及设施
其他
土地调查 -
防汛抗旱 -
地貌 -
管线 -
面符号 HTML命名颜色
分类用地颜色
土地规划分类
常用区域颜色
网页安全色
蜡笔颜色
土地调查样式 -

# 制图效果

在 iClient 中使用 Web 符号,可快速制作出与桌面端产品 Supermap iDesktop/iDesktopX 符号一致的基础地图,下面对比展示了 Web 符号库与桌面端产品中的符号:

  • 点符号样式,以基础符号中的交通符号为例。
图 桌面端点符号与 Web 点符号对比
  • 线符号样式,以基础符号中的行政界线符号为例。
图 桌面端面符号与 Web 面符号对比
  • 面符号样式,以基础符号中的土地分类符号为例。
图 桌面端面符号与 Web 面符号对比

Web 端符号和桌面端符号制图效果对比:

图 长江三角洲发展结构图

查看更多 Web 符号制图示例:iClient for MapboxGL | 可视化 | Web符号 (opens new window)

# 使用方法

Web 符号是由 Mapbox 样式规范中 paint (opens new window), layout (opens new window)组成的符号对象,paintlayout 属性共同定义了符号的样式( layout 中的 visibility 属性除外)。Web 符号 API 的详细说明可见:iClient for MapboxGL | API | WebSymbol (opens new window)

本小节主要介绍了 Web 符号的入门用法,包括:设置图层符号、数据驱动制图以及自定义 Web 符号样式。详细使用方法可参考:iClient for MapboxGL 开发指南 | Web符号 (opens new window)

# 设置图层符号

iClient for MapboxGL 支持直接传入 Web 符号库中的符号 ID 来快速设置图层符号,主要步骤和代码如下:

(1)配置符号资源路径;

(2)获取 Web 符号 ID,可以是 Web符号库 (opens new window) 中提供的 Web 符号 ID,也可以是自定义 Web 符号的 ID;

(3)使用接口 loadSymboladdSymbol,加载 Web 符号并将符号添加至地图;

(4)使用接口 addLayer 添加图层,在 symbol 属性中填入符号 ID 或者 符号表达式 来设置指定图层的 Web 符号。

注:iClient for MapboxGL 通过扩展 MapboxGL 的 API,在 Mapbox Layers 原有属性的基础上新增了 symbol 属性。因此使用接口 addLayersetStyle 时,可以指定 符号ID 或者 符号表达式 来设置图层的符号样式。

// 配置符号资源路径
new mapboxgl.supermap.WebSymbol().init({basePath:"./resources/symbols"});
// Web符号ID
const symbolId = "line-962613";
// 加载Web符号
map.loadSymbol(symbolId, (error, symbol) => {
    if (error) throw error;

    // 添加Web符号到地图
    map.addSymbol(symbolId, symbol);
    // 给指定图层设置Web符号
    map.addLayer({
        "id": "pl@landuse(0_24)",
        "source": "landuse",
        "source-layer": "pl@landuse",
        "type": "line",
        "symbol": symbolId
    });
});

# 数据驱动制图

使用接口 addLayersetSymbol 为图层设置 Web 符号时,除了通过符号 ID 为单个图层指定统一的符号,还可以采用符号支持的 MapboxGL 表达式,以数据驱动的方式为图层中不同属性的要素指定不同的符号。

  • 使用接口 setSymbol 以及 Match 表达式,进行线符号数据驱动制图。
map.setSymbol("layerId", [
    "match",
    ["get", "DLBM"],
    "011", "line-964458", //公路用地
    "013", "line-964462", //农村道路
    "021", "line-962613", //河流水面
    "023", "line-962613", //河流水面
    "line-962613"
  ]);
  • 使用接口 addLayer 以及 Case 表达式,进行面符号数据驱动制图。
map.addLayer({
    "id": "PopDensity_R@Population",
    "source": "全国人口密度空间分布图",
    "source-layer": "PopDensity_R@Population",
    "type": "fill",
    "symbol": [
      "case",
      ["all", ["<=", ["get", "dMaxZValue"], 70]], "PoPdensity_R_MAX70",
      ["all", [">", ["get", "dMaxZValue"], 70],["<=", ["get", "dMaxZValue"], 140]], "PoPdensity_R_MAX140",
      ["all", [">", ["get", "dMaxZValue"], 210],["<=", ["get", "dMaxZValue"], 280]], "PoPdensity_R_MAX280",
      ["all", [">", ["get", "dMaxZValue"], 350],["<=", ["get", "dMaxZValue"], 420]], "PoPdensity_R_MAX420",
      ["all", [">", ["get", "dMaxZValue"], 490],["<=", ["get", "dMaxZValue"], 560]], "PoPdensity_R_MAX560",
      ["all", [">", ["get", "dMaxZValue"], 640],["<=", ["get", "dMaxZValue"], 700]], "PoPdensity_R_MAX700",
      ["all", [">", ["get", "dMaxZValue"], 770],["<=", ["get", "dMaxZValue"], 1000]], "PoPdensity_R_MAX1000",
      ["all", [">", ["get", "dMaxZValue"], 1000]], "PoPdensity_R_Exceed1000",
      "Country_R"
    ]
  });

# 自定义符号

支持用户根据符号规范自定义 Web 符号样式,可以创建全新的 Web 符号,也可以对原有 Web 符号的 paintlayout 属性进行更改(暂不支持设置符号 layout 中的 visibility 属性)。需要为自定义 Web 符号指定唯一 ID,然后可参考普通 Web 符号的使用方式,通过指定符号 ID 来为图层设置自定义符号。

  • 创建自定义点符号

支持设置点符号的图片、大小、偏移、透明度等样式,可参考:Mapbox GL JS | STYLE SPECIFICATION | layers | symbol (opens new window)

// 加载自定义点符号图片                            
map.loadImage("../img/cirecleRed.png", (error, image) => {
    if (error) throw error;
    // 自定义点符号图片
    const imageId = "cityPoint";
    // 添加点符号图片到地图
    map.addImage(imageId, image); 
    // 自定义Web点符号
    const customPointSymbol = {
        "paint": {
            "icon-translate": [0, 4]
        },
        "layout": {
            "icon-image": imageId,
            "icon-size": 0.1
        }
    };

    // 自定义Web点符号ID
    const pointSymbolId = "Province_P";
    // 添加Web点符号到地图
    map.addSymbol(pointSymbolId, customPointSymbol);
  }
);
  • 创建自定义线符号

支持设置线符号的线宽、颜色,端点样式、连接等样式,可参考:Mapbox GL JS | STYLE SPECIFICATION | layers | line (opens new window)

// 自定义Web线符号
const customLineSymbol = {
    "paint": {
        "line-width": 0.38,
        "line-dasharray": [
            2.5,
            2
        ],
        "line-color": "#AE10FC"
    }
};
// 自定义线符号ID
const lineSymbolId = "Province_L";
// 添加Web线符号到地图
map.addSymbol(lineSymbolId, customLineSymbol);
  • 创建自定义面符号

支持设置纯色面符号的颜色、透明度,外轮廓线颜色、是否反走样等属性,可参考:Mapbox GL JS | STYLE SPECIFICATION | layers | fill (opens new window)

map.addSymbol("custom_fill_ID", {
        paint: {
          "fill-color": "rgba(246,229,255,1.00)",
          "fill-opacity": 0.5,
          "fill-outline-color": "rgba(145,223,158,1.00)",
          "fill-antialias": true
        }
      });
  • 修改原有 Web 符号

首先通过接口 loadSymbol 加载出需要修改的 Web 符号,然后修改符号的 paintlayout 属性。为了与修改前的 Web 符号进行区别,将使用一个新的 ID 来标识修改后的 Web 符号。

const loadPreSymbol = async (preSymbolInfo) => {
        const { symbolId, style ={} } = preSymbolInfo;
        const id = uniqueId();
        await map.loadSymbol("point-1", (err, symbol) => {
              if (!err) return;
              symbol.paint["icon-color"] = "red";
              map.addSymbol("start", symbol);
            });
        return { id, symbolId };
    }

# 制图流程

我们在上一个章节中对 Web 符号的使用方法进行了详细的介绍,接下来我们将从创建一个基本的 HTML 文件开始,为您介绍如何在 iClient 中采用 Web 符号进行制图,具体的操作步骤如下:

# 1.准备HTML文件

新建一个 HTML 文件,设置类似于如下格式的基本 HTML 文档。

<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
    <title>土地利用</title>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
    </style>
  </head>
</html>

# 2.引入

开发时需要以 文件方式npm 方式引入 MapboxGL v1SuperMap iClient for MapboxGL,并且为了使用 Web 符号资源,需要指定符号资源的路径。引入方式可参考:iClient for MapboxGL | 开发指南 | Web符号 | 引入 (opens new window)

# 3.添加地图

(1)在<body>标签中添加如下代码,创建地图容器。

<div id="map"></div>

(2)在<script>标签中添加以下代码,创建地图对象。其中,地图数据来源于 SuperMap iServer 站点提供的土地利用图的矢量瓦片, container 属性指定的是上一步骤中创建的地图容器。

var serverUrl = "https://iserver.supermap.io/iserver/services/map-mvt-landuse2/rest/maps/landuse";
var map = new mapboxgl.Map({
      container: "map",
      style: {
        "sources": {
          "landuse": {
            "tiles": [
              serverUrl + "/tileFeature.mvt?z={z}&x={x}&y={y}"
            ],
            "type": "vector"
          }
        },
        "name": "landuse",
        "layers": [],
        "version": 8
      },
      minZoom: 11,
      maxZoom: 15,
      zoom: 13,
      center: [
        108.9131713726414,
        23.82622655814832
      ]
    });

# 4.使用符号

采用数据驱动的方式为不同的土地利用类型的指定不同的 Web 符号。首先创建添加图层的方法,在方法中指定图层所采用的 Web 符号,然后在地图加载事件中,将图层添加至地图。

(1)创建方法 createLineLayer,实现功能:以数据驱动的方式指定线图层使用的 Web 符号,并将线图层添加至地图中。

var createLineLayer = function () {
  map.addLayer({
    "id": "pl@landuse(0_24)",
    "source": "landuse",
    "source-layer": "pl@landuse",
    "type": "line",
    "symbol": [
      "match",
      ["get", "DLBM"],
      "011", "line-962543", //公路用地
      "013", "line-962524", //农村道路
      "021", "line-962613", //河流水面
      "023", "line-962613", //河流水面
      "line-964935"
    ]
  });
};

(2)创建方法 createPolygonLayer,实现功能:以数据驱动的方式指定面图层使用的 Web 符号,并将面图层添加至地图中。

// 添加面图层
var createPolygonLayer = function () {
  map.addLayer({
    "id": "landuse@landuse(0_24)",
    "source": "landuse",
    "source-layer": "landuse@landuse",
    "type": "fill",
    "symbol": [
      "match",
      ["get", "DLBM"],
      "011", "polygon-955880", //水田
      "013", "polygon-955464", //旱地
      "021", "polygon-955519", //果园
      "023", "polygon-955879", //其他园地
      "031", "polygon-955483", //有林地
      "032", "polygon-955537", //灌木林地
      "033", "polygon-955878", //其他林地
      "043", "polygon-955398", //其他草地
      "127", "polygon-955385", //裸地
      "201", "polygon-955872", //城市
      "203", "polygon-955527", //村庄
      "101", "polygon-955452", //铁路用地
      "102", "polygon-955550", //公路用地
      "104", "polygon-955550", //农村道路
      "117", "polygon-955400", //沟渠
      "118", "polygon-955545", //水工建筑
      "122", "polygon-955529", //设施农用地
      "204", "polygon-955532", //采矿用地
      "205", "polygon-955433", //风景名胜及特殊用地
      "111", "polygon-955871", //河流水面
      "112", "polygon-955871", //湖泊水面
      "113", "polygon-955875", //水库水面
      "114", "polygon-955525", //坑塘水面
      "116", "polygon-955508", //内陆滩涂
      "polygon-0"
    ]
  });
};

(3)在地图加载事件中,配置 Web 符号资源的基础路径,然后使用方法 map.loadSymbol 批量加载土地利用图中用到的 Web 符号,同时使用方法createLineLayercreatePolygonLayer 将指定了 Web 符号的线图层和面图层添加至地图中。

map.on("load", function () {
  // 配置 Web 符号资源的基础路径
  new mapboxgl.supermap.WebSymbol().init({basePath: window.exampleWebSymbolBasePath});
  // 批量加载 Web 符号
  var symbolIds = [
    "polygon-955452",
    "polygon-955550",
    "polygon-955871",
    "polygon-955875",
    "polygon-955525",
    "polygon-955508",
    "polygon-955400",
    "polygon-955545",
    "polygon-955529",
    "polygon-955385",
    "polygon-955872",
    "polygon-955527",
    "polygon-955532",
    "polygon-955433",
    "polygon-955880",
    "polygon-955464",
    "polygon-955519",
    "polygon-955879",
    "polygon-955878",
    "polygon-955483",
    "polygon-955537",
    "polygon-955398",
    "polygon-0"
  ];
  map.loadSymbol(symbolIds, function (_error, symbols) {
      symbols.forEach((symbol, index) => {
        symbol && map.addSymbol(symbolIds[index], symbol);
      });
      createPolygonLayer();//添加面图层至地图
      createLineLayer();//添加线图层至地图
    });
}); 

# 5.可视化效果

至此,已成功采用 Web 符号进行制图,在浏览器中打开 HTML 页面后可查看如下图所示的土地利用图制图效果。相关示例及完整代码可参考:iClient for MapboxGL | examples | 土地利用图 (opens new window)

图 土地利用图制图效果

# 参考示例

iClient for MapboxGL 在 iClient for MapboxGL | 可视化 | Web符号 (opens new window) 中提供了一系列 Web 符号示例,以便您快速上手 Web 符号制图,其中包括:Web 符号库、Web 符号编辑器以及若干 Web 符号制图成果,本小节将对 Web 符号库示例和 Web 符号编辑器示例进行介绍。

# Web符号库

为了便于用户了解 Web 符号库所支持符号的实现方式,iClient for MapboxGL 在 Web符号库 (opens new window) 示例中罗列了目前所有支持的 Web 符号,并提供了 Web 符号的名称、上图效果和 ID,点击符号可查看实现当前符号样式的代码。

图 示例-Web符号库

# Web符号编辑器

为了便于用户了解在 iClient 中自定义 Web 符号的功能,在 Web符号编辑器 (opens new window) 示例中,可以对 Web 符号库中提供符号进行在线样式编辑,并在地图中显示自定义 Web 符号的效果。支持编辑的符号样式如下:

  • 点符号:颜色、大小、透明度、相对偏移值、旋转角;
  • 线符号:颜色、透明度、线宽、偏移量、模糊度、线段连接方式、线段端点样式、相对偏移值;
  • 面符号:颜色、透明度。
图 示例-Web符号编辑器