从零实战!使用 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平台

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


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

相关推荐
wuhen_n2 小时前
类型断言:as vs <> vs ! 的使用边界与陷阱
前端·javascript·typescript
海鸥_2 小时前
三种典型的3D空间编码方法
3d
⑩-2 小时前
VUE3-组件通信
前端·javascript·vue.js
哆啦A梦15882 小时前
Vue3魔法手册 作者 张天禹 02
前端·vue.js·typescript
老前端的功夫2 小时前
抛弃 `!important`,让 CSS 优先级变大
前端·javascript·css·npm·node.js
熊文豪2 小时前
Tomcat+cpolar 让 Java Web 应用随时随地可访问
java·前端·tomcat·cpolar
衫水2 小时前
如何在离线情况下部署项目(前端VUE + 后端Python)
前端·vue.js·python
南棱笑笑生2 小时前
20260123让天启AIO-3576Q38开发板在天启Buildroot下适配摄像头模块8ms1m【预览】
java·前端·数据库·rockchip
Sylvia33.2 小时前
如何获取足球数据统计数据API
java·前端·python·websocket·数据挖掘