前言
在国产化 GIS 项目中,我们经常需要加载 SuperMap iServer 发布的地图服务,并且通常要求使用 CGCS2000 (EPSG:4490) 坐标系。原生的 MapboxGL 默认只支持 Web Mercator (EPSG:3857),因此必须配合 SuperMap iClient for MapboxGL 进行扩展。
本文将总结在 Vite + Vue 3 + TypeScript 项目中,如何优雅地集成 MapboxGL v1,加载 SuperMap REST 地图服务,并实现自定义 DOM 标记。
一、 核心依赖与引入方式
在 Vite 项目中引入 MapboxGL 有两种常见方式: NPM 模块化引入 和 CDN/Script 脚本引入 。
本项目采用的是 Script 脚本引入 方式,这种方式可以由 SuperMap 提供的 include-mapboxgl.js 自动处理依赖和 CSS 样式,并挂载全局变量。
1. index.html 引入脚本
在 index.html 的 <head> 中添加如下代码。注意 include="mapbox-gl-enhance" 参数,它会加载增强版的 MapboxGL 以支持 EPSG:4490。
html
<!-- index.html -->
<head>
<!-- 引入 SuperMap iClient for MapboxGL -->
<!-- 注意:路径根据实际静态资源位置调整,通常位于 public 或 assets 下 -->
<script type="text/javascript" include="mapbox-gl-enhance"
src="./libs/superMapGl/dist/mapboxgl/include-mapboxgl.js">
</script>
</head>
2. TypeScript 类型声明
由于是通过 <script> 标签引入, mapboxgl 是一个全局变量。在 TypeScript 文件中直接使用会报错 Cannot find name 'mapboxgl' 。
我们可以在 src/types/global.d.ts 或组件内添加声明:
TypeScript
// 简单粗暴的方式
declare const mapboxgl: any;
// 或者安装类型定义包(推荐)
// npm install --save-dev @types/mapbox-gl
二、 地图初始化 (关键配置)
加载 SuperMap iServer 服务的核心在于配置 crs 和 rasterSource 。
javascript
// src/views/map/index.vue
const initMap = () => {
// 基础底图服务地址 (SuperMap iServer REST 地图服务)
const url = `http://your-iserver-host/iserver/services/map-dom/rest/maps/dom`;
// 初始化地图实例
const mapInstance = new mapboxgl.Map({
container: "map", // DOM 容器 ID
style: {
version: 8,
sources: {
"raster-tiles": {
type: "raster",
tileSize: 256,
// 核心配置:指定 tiles 地址模板
tiles: [`${url}?transparent=true`],
// 核心配置:告诉插件这是 iServer 服务,自动处理投影
rasterSource: "iserver",
},
},
layers: [
{
id: "simple-tiles",
type: "raster",
source: "raster-tiles",
minzoom: 0,
maxzoom: 22,
},
],
},
// 关键:指定坐标系为 CGCS2000
crs: "EPSG:4490",
center: [106.0, 30.3], // 中心点 [经度, 纬度]
zoom: 6.9, // 初始缩放层级
});
// 保存实例
map.value = mapInstance;
// 监听 load 事件,确保样式加载完成后再添加其他图层
mapInstance.on("load", () => {
addBusinessLayers(mapInstance);
});
};
三、 动态叠加业务图层
除了底图,我们通常还需要叠加管网、场站等业务图层。
TypeScript
// 动态添加 SuperMap REST 图层
const addBusinessLayers = (map: any) => {
const layerUrl = "http://your-iserver-host/iserver/services/map-pipe/rest/maps/pipe";
const sourceId = "source-pipe";
const layerId = "layer-pipe";
// 1. 添加源
if (!map.getSource(sourceId)) {
map.addSource(sourceId, {
type: "raster",
tiles: [`${layerUrl}?transparent=true`],
tileSize: 256,
rasterSource: "iserver", // 同样需要标记为 iServer 源
});
}
// 2. 添加图层
if (!map.getLayer(layerId)) {
map.addLayer({
id: layerId,
type: "raster",
source: sourceId,
paint: {
"raster-opacity": 1, // 图层透明度
},
});
}
};
四、 自定义 DOM Marker 标记
MapboxGL 的 Marker 支持使用自定义 HTML 元素,这比使用 Symbol Layer 更灵活,适合需要交互和复杂样式的点位。
TypeScript
const renderMarkers = (dataList: any[]) => {
dataList.forEach((item) => {
// 1. 创建自定义 DOM 元素
const el = document.createElement("div");
el.className = "custom-marker";
// 构建内部结构(图标 + 标签)
const label = document.createElement("div");
label.innerText = item.name;
label.className = "marker-label";
const icon = document.createElement("img");
icon.src = "/assets/icon.svg";
icon.className = "marker-icon";
el.appendChild(label);
el.appendChild(icon);
// 2. 绑定点击事件
el.addEventListener("click", () => {
console.log("点击了站点:", item.name);
// 路由跳转或其他逻辑
});
// 3. 添加到地图
new mapboxgl.Marker({
element: el,
anchor: "bottom", // 图标底部对齐坐标点
})
.setLngLat([parseFloat(item.lng), parseFloat(item.lat)])
.addTo(map.value);
});
};
五、 避坑指南与注意点
1. Vite 构建配置 (optimizeDeps)
如果你的项目中混用了 NPM 包引入(例如引入了 mapbox-gl 用于类型推导),Vite 在开发模式下可能会遇到 CommonJS 转换问题。建议在 vite.config.ts 中强制预构建:
TypeScript
// vite.config.ts
export default defineConfig({
optimizeDeps: {
include: ['mapbox-gl', '@supermapgis/iclient-mapboxgl'],
},
});
2. 坐标系问题 (EPSG:4490 vs EPSG:3857)
-
原生 MapboxGL 默认是 Web Mercator (3857)。
-
如果你的 iServer 服务是 CGCS2000 (4490), 必须 引入 SuperMap 插件并设置 crs: "EPSG:4490" 。
-
如果忘记设置,地图可能无法显示,或者坐标偏移巨大。
3. 样式丢失问题 -
使用 Script 引入方式时, include-mapboxgl.js 通常会自动加载 CSS。
-
如果发现地图控件错位或没有样式,请检查网络请求中 mapbox-gl.css 是否加载成功。
4.地图加载时机 -
务必在 onMounted 中初始化地图。
-
添加图层( addLayer )的操作必须在 map.on('load') 回调之后执行,否则会报错 Style is not done loading 。
5.资源销毁 -
在 Vue 组件卸载 ( onUnmounted ) 时,建议调用 map.remove() 销毁地图实例,防止内存泄漏。
总结
通过 SuperMap iClient for MapboxGL,我们可以轻松解决国产坐标系和 iServer 服务加载的问题。结合 Vue 3 的响应式特性和 MapboxGL 强大的渲染能力,可以构建出高性能的 WebGIS 应用。