从零实战!使用 Mars3D 快速构建水利监测 WebGIS 系统

前言

在智慧水利、数字孪生流域等项目的建设中,一个直观、高效的地理信息可视化平台至关重要。传统的 GIS 开发往往门槛较高,而 Mars3D 作为一个基于 CesiumJS 的国产开源 WebGL 地图引擎,极大地简化了三维地球应用的开发流程。

本文将手把手带你,利用 Mars3D 插件,快速搭建一个功能丰富的水利监测 WebGIS 系统。我们将实现以下核心功能:

  1. 加载天地图作为底图
  2. 动态加载并标记多种类型的水利站点(大坝、水文站、雨量站等)
  3. 为关键区域(如水库)添加描边和逼真的水面水纹特效
  4. 实现站点搜索与定位
  5. 集成图例筛选功能

通过本文,你将掌握 Mars3D 在实际项目中的基本用法,并能快速复用到自己的项目中。


一、环境准备与 Mars3D 安装

我们的项目基于 Vue3 + Vite 构建。

  1. 创建 Vue3 项目

    复制代码
    npm create vue@latest my-water-gis
    cd my-water-gis
    npm install
  2. 安装 Mars3D 及其依赖 根据 Mars3D 官方文档,我们需要安装核心库和 Cesium。

    复制代码
    # 安装 Mars3D 核心库
    npm install mars3d
    
    # 安装 Mars3D 封装的 Cesium(推荐,已处理好路径等问题)
    npm install mars3d-cesium
  3. 配置 Vite(可选但推荐) 为了优化打包体积和解决潜在的路径问题,可以在 vite.config.js 中添加别名:

    复制代码
    // vite.config.js
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    
    export default defineConfig({
      plugins: [vue()],
      resolve: {
        alias: {
          // Mars3D 推荐配置
          cesium: "mars3d-cesium/Build/Cesium",
        },
      },
    })

二、初始化 Mars3D 地图

我们创建一个 MapContainer.vue 组件来承载地图。核心在于 infoMars3d 方法。

复制代码
// MapContainer.vue (script部分)
import * as mars3d from "mars3d";
import * as Cesium from "mars3d-cesium";

export default {
  data() {
    return {
      map: null, // 地图实例
      graphicLayer: null, // 图形图层,用于管理所有标记点
    };
  },
  async mounted() {
    await this.initMap();
  },
  methods: {
    async initMap() {
      // 1. 配置地图选项
      const mapOptions = {
        scene: {
          // 初始视角
          center: { lat: 33.119017, lng: 117.901056, alt: 786.8, heading: 117.2, pitch: -16.1 },
          sceneMode: 3, // 3D模式
        },
        control: {
          // 显示控件
          baseLayerPicker: true, // 底图切换
          homeButton: true, // 复位
          fullscreenButton: true, // 全屏
        },
        // 2. 配置底图(天地图)
        basemaps: [
          {
            name: "天地图影像",
            type: "group",
            show: true,
            layers: [
              { name: "底图", type: "tdt", layer: "img_d", crs: "EPSG:4326" },
              { name: "注记", type: "tdt", layer: "img_z", crs: "EPSG:4326" },
            ],
          },
          // ...可以添加更多底图
        ],
      };

      // 3. 创建地图实例
      this.map = new mars3d.Map("mapContainer", mapOptions);

      // 4. 创建一个图形图层,用于后续添加所有标记点
      this.graphicLayer = new mars3d.layer.GraphicLayer();
      this.map.addLayer(this.graphicLayer);
    }
  }
}

对应的模板非常简单:

复制代码
<!-- MapContainer.vue (template部分) -->
<template>
  <div id="mapContainer" style="width: 100vw; height: 100vh;"></div>
</template>

至此,一个带有天地图底图的 3D 地球就成功加载了!


三、动态加载并标记水利站点

假设我们有一个后端 API /api/points,返回如下格式的站点数据:

复制代码
[
  { "id": 1, "pointName": "主坝", "pointType": "PSK", "lng": 117.9, "lat": 33.12, "warnSatus": false },
  { "id": 2, "pointName": "五河站", "pointType": "PSW", "lng": 117.91, "lat": 33.13, "warnSatus": true },
  // ...
]

我们需要根据 pointType 显示不同的图标,并处理报警状态。

复制代码
// 在 MapContainer.vue 中添加方法
methods: {
  // ... initMap

  // 加载并渲染站点
  async loadAndRenderPoints(pointList) {
    // 清空旧的标记
    this.graphicLayer.clear();

    pointList.forEach((item) => {
      // 1. 根据类型选择图标
      const getImageByType = (type) => {
        const iconMap = {
          PSK: "@/assets/img/map/icon-dam.png",
          PSW: "@/assets/img/map/icon-sw.png",
          PYL: "@/assets/img/map/icon-yl.png",
          // ...其他类型映射
        };
        return require(iconMap[type] || "@/assets/img/map/default.png");
      };

      // 2. 创建标记点实体 (BillboardEntity)
      const billboardEntity = new mars3d.graphic.BillboardEntity({
        position: [item.lng, item.lat],
        style: {
          image: getImageByType(item.pointType),
          scale: 1,
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          // 3. 添加站点名称标签
          label: {
            text: item.pointName,
            font_size: 20,
            color: "#ffffff",
            outline: true,
            outlineColor: Cesium.Color.BLACK,
            // ...其他样式
          },
        },
      });

      // 4. 如果是报警状态,启动弹跳动画
      if (item.warnSatus) {
        billboardEntity.startBounce({ autoStop: false, step: 0.3, maxHeight: 20 });
      }

      // 5. 绑定鼠标事件
      billboardEntity.on("mouseOver", () => {
        if (item.warnSatus) billboardEntity.stopBounce(); // 悬停停止弹跳
        // 这里可以绑定自定义信息弹窗
      });

      billboardEntity.on("mouseOut", () => {
        if (item.warnSatus) billboardEntity.startBounce(); // 移出恢复弹跳
      });

      // 6. 绑定点击事件,打开详情
      billboardEntity.on("click", () => {
        // 根据 pointType 打开不同的详情弹窗组件
        if (item.pointType === "PYL") {
          this.openRainfallDialog(item);
        } else if (item.pointType === "PSK") {
          this.showReservoirDamView(item); // 切换到大坝平面图视图
        }
        // ...其他类型处理
      });

      // 7. 将实体添加到图层
      this.graphicLayer.addGraphic(billboardEntity);
    });
  }
}

通过这个方法,我们就能将从 API 获取的数据动态渲染到地图上,并赋予丰富的交互能力。


四、为水库添加描边与水纹特效

这是 Mars3D 的亮点之一,可以轻松实现非常酷炫的效果。通常,水库的范围会以 GeoJSON 格式提供。

  1. 准备 GeoJSON 文件 假设我们有一个 qzj.json 文件,描述了"樵子涧水库"的边界。

  2. 加载 GeoJSON 并应用水纹材质initMap 方法中或单独封装一个方法:

    // 在 MapContainer.vue 中添加方法
    addReservoirWaterEffect() {
    const geoJsonLayer = new mars3d.layer.GeoJsonLayer({
    url: "/public/qzj.json", // 确保文件放在 public 目录下
    symbol: {
    type: "waterC", // 关键!指定为水面材质
    styleOptions: {
    height: 17, // 水面高度(相对于地形)
    normalMap: require("@/assets/img/reservoir/waterNormals.jpg"), // 水波法线贴图
    frequency: 8000.0,
    animationSpeed: 0.02,
    amplitude: 5.0, // 波浪幅度
    baseWaterColor: "#006ab4", // 水的颜色
    opacity: 0.4, // 透明度
    clampToGround: true, // 贴地
    // 添加描边
    outline: true,
    outlineStyle: {
    color: "#067cd3",
    width: 3,
    opacity: 1,
    },
    },
    },
    tooltip: "樵子涧水库", // 鼠标悬停提示
    flyTo: true, // 自动飞向该区域
    });
    this.map.addLayer(geoJsonLayer);
    }

调用 this.addReservoirWaterEffect() 后,地图上就会出现一个带有动态水纹和蓝色描边的水库,效果非常直观和专业。


五、其他实用功能

您的代码中还包含了几个非常实用的功能点:

  • 站点搜索 :通过 searchByName 方法,遍历 pointList,使用 this.map.flyToPoint([lng, lat, height]) 实现快速定位。
  • 图例筛选 :通过 layerPop 弹窗获取用户选择的 pointType,然后调用 loadAndRenderPoints 重新渲染筛选后的点位。
  • 视图切换toOneMap 方法实现了从"大坝详情平面图"视图切换回"全局地图"视图,通过销毁和重建地图实例完成。

总结

通过以上步骤,我们利用 Mars3D 成功构建了一个功能完备的水利监测 WebGIS 基础框架。Mars3D 的优势在于其对 CesiumJS 的深度封装和大量开箱即用的组件(如 BillboardEntity, GeoJsonLayer),让我们能够用更少的代码实现更强大的 GIS 功能。

Mars3D平台

国家地理信息公共服务平台


希望这篇文章对你有帮助!

相关推荐
Ticnix11 分钟前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人14 分钟前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl18 分钟前
OpenClaw 深度技术解析
前端
崔庆才丨静觅21 分钟前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人29 分钟前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼33 分钟前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空36 分钟前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust
Mr Xu_41 分钟前
Vue 3 中计算属性的最佳实践:提升可读性、可维护性与性能
前端·javascript
jerrywus1 小时前
我写了个 Claude Code Skill,再也不用手动切图传 COS 了
前端·agent·claude
玖月晴空1 小时前
探索关于Spec 和Skills 的一些实战运用-Kiro篇
前端·aigc·代码规范