Vue3 + Vite + MapboxGL 实战:集成 SuperMap iServer 加载 CGCS2000 地图服务与自定义标记

前言

在国产化 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 应用。

相关推荐
麦麦大数据2 小时前
F068 vue+flask 非遗文化遗产图谱可视化系统
前端·vue.js·flask·知识图谱·文化遗产·非遗文化
想要一只奶牛猫2 小时前
Spring Web MVC(四)
前端·spring·mvc
zpjing~.~2 小时前
iframe和父页面消息通信
开发语言·前端·javascript
老华带你飞2 小时前
电影购票|基于java+ vue电影购票系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
老华带你飞2 小时前
宠物管理|基于java+ vue宠物管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·宠物
释怀不想释怀4 小时前
Ajax,vue生命周期(自动加载页面发出请求)Axios
前端·javascript·ajax
一点晖光4 小时前
ios底部按钮被挡住
前端·ios·微信小程序
Light6010 小时前
CSS逻辑革命:原生if()函数如何重塑我们的样式编写思维
前端·css·响应式设计·组件化开发·css if函数·声明式ui·现代css
蜡笔小嘟11 小时前
宝塔安装dify,更新最新版本--代码版
前端·ai编程·dify