基于vue+Cesium实现交互式攻击箭头绘制

引言

在地理信息系统(GIS)和军事模拟领域,箭头绘制是一项基础且重要的功能。本文将介绍如何使用Cesium.js结合Vue框架实现交互式攻击箭头绘制功能,支持鼠标点击采集关键点、动态更新箭头形状、右键结束绘制等核心交互,并对实现过程中的关键技术点进行深入解析。

功能概述

本组件实现了以下核心功能:

  • 地图初始化与基础配置
  • 鼠标左键点击采集箭头关键点
  • 鼠标移动实时更新箭头形状
  • 右键点击结束绘制并输出结果
  • 动态渲染箭头多边形与轮廓线
  • 坐标转换与数据处理
  • 资源释放与内存管理

核心代码解析

1. 项目结构与依赖引入

// 导入地图初始化函数
import initMap from '@/config/initMap.js';
// 导入地图配置项(包含高德地图服务地址等)
import { mapConfig } from '@/config/mapConfig';
// 导入算法工具库(包含攻击箭头绘制算法)
import xp from '@/utils/algorithm.js';
// 导入标记点图片资源
import boardimg from '@/assets/images/captain-01.png';

2. 数据初始化

data() {
  return {
    viewer: null, // Cesium地图实例对象
    gatherPosition: [], // 采集的点坐标数组(Cartesian3格式)
    floatingPoint: null, // 鼠标移动时的动态浮动点实体
    drawHandler: null, // 屏幕空间事件处理器
    layerId: 'attackArrowLayer', // 自定义图层ID
  };
}

3. 地图初始化

mounted() {
  // 初始化Cesium地图,使用高德地图服务
  this.viewer = initMap(mapConfig.gaode.url3, false);
  // 延迟1秒执行箭头采集函数,确保地图资源加载完成
  setTimeout(() => {
    this.gatherAttackArrow();
  }, 1000);
}

4. 核心交互逻辑实现

4.1 事件绑定与交互流程
/**
 * 开始采集攻击箭头的坐标点
 * 绑定鼠标事件:左键点击采集点,鼠标移动更新浮动点,右键点击结束采集
 */
gatherAttackArrow() {
  console.log('开始采集攻击箭头');
  this.gatherPosition = []; // 清空历史采集点数组
  this.floatingPoint = null; // 重置浮动点实体
  this.clearPlot(); // 清除已有绘制内容

  // 创建屏幕空间事件处理器,用于监听鼠标交互
  this.drawHandler = new Cesium.ScreenSpaceEventHandler(
    this.viewer.scene.canvas
  );

  // 左键点击事件 - 采集坐标点
  this.drawHandler.setInputAction((event) => {
    // 坐标点采集逻辑...
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  // 鼠标移动事件 - 更新浮动点位置
  this.drawHandler.setInputAction((event) => {
    // 浮动点更新逻辑...
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

  // 右键点击事件 - 停止采集并处理结果
  this.drawHandler.setInputAction((movement) => {
    // 结束采集逻辑...
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
4.2 关键点标记创建
/**
 * 创建地图上的关键点标记
 * @param {Cesium.Cartesian3} cartesian - 点的笛卡尔坐标
 * @param {number} oid - 点的唯一标识
 * @returns {Cesium.Entity} 创建的点实体对象
 */
createPoint(cartesian, oid) {
  const point = this.viewer.entities.add({
    position: cartesian,
    billboard: {
      image: boardimg, // 使用导入的图片作为标记
      eyeOffset: new Cesium.Cartesian3(0, 0, -100), // 视线偏移
      heightReference: Cesium.HeightReference.NONE, // 不贴地
      scale: 1.0, // 缩放比例
      width: 32, // 固定宽度
      height: 32, // 固定高度
    },
  });
  // 自定义属性,用于后续识别和管理
  point.oid = oid;
  point.layerId = this.layerId;
  point.flag = 'keypoint';
  return point;
}

5. 动态图形绘制

5.1 攻击箭头动态渲染
/**
 * 在地图上动态显示攻击箭头区域
 * 通过CallbackProperty实现多边形和轮廓线的动态更新
 */
showRegion2Map() {
  // 定义多边形填充材质(黄色半透明)
  const material = Cesium.Color.fromCssColorString('#ff0').withAlpha(0.5);
  // 定义轮廓线材质(红色虚线)
  const outlineMaterial = new Cesium.PolylineDashMaterialProperty({
    dashLength: 16,
    color: Cesium.Color.fromCssColorString('#f00').withAlpha(0.7),
  });

  // 动态更新多边形层级(攻击箭头形状)
  const dynamicHierarchy = new Cesium.CallbackProperty(() => {
    if (this.gatherPosition.length > 1) {
      const lonLats = this.getLonLatArr(this.gatherPosition);
      // 使用算法库生成带尾翼的攻击箭头
      const doubleArrow = xp.algorithm.tailedAttackArrow(lonLats);
      const positions = doubleArrow.polygonalPoint;
      
      if (!positions || positions.length < 3) return null;
      positions.splice(positions.length - 2, 1); // 移除燕尾部分
      
      const pHierarchy = new Cesium.PolygonHierarchy(positions);
      pHierarchy.keyPoints = lonLats; // 存储原始关键点
      return pHierarchy;
    }
    return null;
  }, false);

  // 动态更新轮廓线坐标
  const outlineDynamicPositions = new Cesium.CallbackProperty(() => {
    // 轮廓线更新逻辑...
  }, false);

  // 添加多边形和轮廓线实体到地图
  const entity = this.viewer.entities.add({
    polygon: new Cesium.PolygonGraphics({
      hierarchy: dynamicHierarchy,
      material: material,
      show: true,
    }),
    polyline: new Cesium.PolylineGraphics({
      positions: outlineDynamicPositions,
      clampToGround: true,
      width: 2,
      material: outlineMaterial,
      show: true,
    }),
  });
  entity.layerId = this.layerId;
  entity.valueFlag = 'value';
}

6. 坐标转换与数据处理

/**
 * 将笛卡尔坐标数组转换为经纬度数组
 * @param {Array} positions - 笛卡尔坐标数组
 * @returns {Array>} 经纬度数组 [[lon, lat], ...]
 */
getLonLatArr(positions) {
  const arr = [];
  for (let i = 0; i < positions.length; i++) {
    const p = this.getLonLat(positions[i]);
    if (p) {
      arr.push([p.lon, p.lat]);
    }
  }
  return arr;
}

/**
 * 将笛卡尔坐标转换为经纬度坐标
 * @param {Cesium.Cartesian3} cartesian - 笛卡尔坐标
 * @returns {Object} 包含lon, lat, alt的经纬度对象
 */
getLonLat(cartesian) {
  const cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
  cartographic.height = this.viewer.scene.globe.getHeight(cartographic);
  return {
    lon: Cesium.Math.toDegrees(cartographic.longitude),
    lat: Cesium.Math.toDegrees(cartographic.latitude),
    alt: cartographic.height,
  };
}

7. 资源释放与内存管理

beforeDestroy() {
  // 组件销毁时释放资源,避免内存泄漏
  if (this.viewer) {
    this.viewer.destroy(); // 销毁地图实例
  }
  if (this.drawHandler) {
    this.drawHandler.destroy(); // 销毁事件处理器
  }
}

关键技术点解析

1. CallbackProperty动态更新机制

Cesium中的CallbackProperty是实现动态图形的核心,它允许我们定义一个回调函数,该函数会在每一帧渲染时被调用,返回最新的属性值。在攻击箭头绘制中,我们利用这一特性实现了箭头形状的实时更新:

const dynamicHierarchy = new Cesium.CallbackProperty(() => {
  // 根据当前采集的点动态生成箭头形状
  // ...
}, false);

第二个参数false表示该属性不会引发视图更新,适合用于频繁更新的场景。

2. 事件处理器管理

Cesium的ScreenSpaceEventHandler用于处理用户交互事件,使用时需要注意:

  • 使用后必须调用destroy()方法释放资源
  • 避免重复创建事件处理器导致内存泄漏
  • 合理管理事件优先级和冲突

3. 坐标系统转换

Cesium中存在多种坐标系统,本项目中主要涉及:

  • Cartesian3:三维笛卡尔坐标(世界坐标)
  • Cartographic:地理坐标(弧度表示的经纬度)
  • Degrees:角度表示的经纬度

通过ellipsoid.cartesianToCartographicMath.toDegrees实现坐标转换。

4. 图层管理与实体标识

通过自定义属性(如layerIdflag)对Cesium实体进行分类管理,便于批量操作和清理:

// 清除当前图层上的所有绘制内容
clearPlot() {
  const entityList = this.viewer.entities.values;
  if (!entityList || entityList.length < 1) return;
  
  for (let i = 0; i < entityList.length; i++) {
    const entity = entityList[i];
    if (entity.layerId === this.layerId) {
      this.viewer.entities.remove(entity);
      i--; // 移除后索引调整
    }
  }
}

使用方法

  1. 安装依赖:确保项目中已引入Cesium.js和Vue框架
  2. 配置地图服务:在mapConfig.js中配置高德或其他地图服务地址
  3. 引入组件:在需要使用箭头绘制功能的页面引入该组件
  4. 初始化调用:通过mounted钩子自动初始化或手动调用gatherAttackArrow方法

完整代码






总结与展望

本文实现了一个功能完整的交互式攻击箭头绘制组件,核心亮点包括:

  • 流畅的鼠标交互体验
  • 高效的动态图形渲染
  • 完善的资源管理机制
  • 清晰的代码结构和注释

未来可以进一步优化的方向:

  • 添加箭头样式自定义功能(颜色、线宽、箭头大小等)
  • 实现箭头的编辑和修改功能
  • 增加撤销/重做功能
  • 优化移动端交互体验

通过本文的实现,不仅掌握了Cesium的核心交互和绘图API,也学习了大型前端GIS应用中的性能优化和内存管理技巧,为构建更复杂的地理信息应用奠定了基础。

点点关注不迷路,代码中使用到的 algorithm.js与 plotUtil.js 有需要的留言。

你可能感兴趣的:(基于vue+Cesium实现交互式攻击箭头绘制)