Cesium 绘制箭头、符号等标记
Cesium 是一个用于 3D 地理可视化的开源引擎,可以在浏览器里展示地球、卫星影像、三维地形等。
很多 GIS 项目都需要在 3D 场景中绘制各种标记、符号、箭头等,来表达地理标注或态势信息,比如用于军事标绘中的部队前进、攻击方向等。
Cesium 本身就可以实现这些效果,最直接的方式就是手动绘制。接下来我们先来看一个最基础的示例:通过写死点位来绘制一个红色箭头。
手动绘制一个红色箭头
这里的核心思路是:
- 把箭头的轮廓坐标(经纬度)一一枚举出来;
- 转换为 Cesium 的笛卡尔坐标;
- 新建一个
polygon
实体并设置外边框、颜色、透明度等;
下面是一个简单的实现:
const viewer = new Cesium.Viewer(container);
// 定义一个“写死”的箭头多边形 - 直接列出顶点经纬度
const arrowShape = Cesium.Cartesian3.fromDegreesArray([
115.8,
39.91, // 箭身左下角
115.8,
39.89, // 箭身右下角
115.9,
39.89, // 箭头底部右
115.9,
39.88, // 箭头右侧
116.0,
39.9, // 箭头尖端
115.9,
39.92, // 箭头左侧
115.9,
39.91, // 箭头底部左
]);
// 4. 创建一个实体(Entity),并用 polygon 绘制箭头
const arrowEntity = viewer.entities.add({
name: "红色箭头",
polygon: {
// 轮廓点
hierarchy: new Cesium.PolygonHierarchy(arrowShape),
// 填充材质:带点透明度的红色
material: Cesium.Color.RED.withAlpha(0.8),
// 加边框
outline: true,
outlineWidth: 2,
// 高程设置(可选)
height: 0,
extrudedHeight: 1000, // 如果想让箭头“拔高”成一个立体多边形,可设置 extrudedHeight
},
});
这种方式确实简单直接,适合绘制一些固定形状的箭头或标记。但问题也很明显:
- 所有顶点坐标都得自己手动写或计算;
- 如果箭头带有弧度、曲线、钩子等复杂几何,就非常难手动算清楚;
- 更不用说如果要支持用户自己在地图上画,这种方法就完全不适用了。
用 cesium-plot-js 进行符号绘制
为了解决上述问题,我们可以使用社区的开源库 —— cesium-plot-js
(opens in a new tab)。
这是一个基于 Cesium 封装的轻量级绘图工具,支持鼠标交互式绘制各种军事符号和地图图形。
cesium-plot-js 是什么?
cesium-plot-js
支持在 Cesium 地图上交互式绘制各种态势标注、箭头、多边形等。
它的特点是:
- 支持 19 种常见符号,包括:自由箭头、进攻箭头、钳形箭头、双箭头、曲线等;
- 允许用户通过 鼠标点击、拖动 在地图上交互式生成复杂图形;
- 支持编辑图形、获取点位数据、加载已有图形等功能;
- 支持绘制和只读展示两种模式。
地址: https://github.com/ethan-zf/cesium-plot-js?tab=readme-ov-file (opens in a new tab)
依赖安装
npm i cesium-plot-js
引入
import CesiumPlot from "cesium-plot-js";
绘制进攻箭头
比如,我们要创建一个进攻箭头的效果
const geometry = new CesiumPlot.AttackArrow(Cesium, viewer, {
material: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
outlineMaterial: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
outlineWidth: 3,
});
AttackArrow 就是对应上图的攻击箭头的类名,现在我们在地图上进行点击就可以绘制出想要的箭头了,并且能够指定方向。
同时它有五个事件,便于开发者控制流程:
- drawStart:绘制开始
- drawUpdate:绘制过程中点位更新,回调事件返回更新的 Cartesian3 点位
- drawEnd:绘制结束,回调事件返回图形的关键点位```
- editStart:编辑开始
- editEnd:编辑结束,回调事件返回图形的关键点位
例如,我们监听绘制完成事件以获取图形数据:
geometry.on("drawEnd", (data) => {
console.log(data);
});
当双击结束绘制后,控制台将输出箭头的关键点坐标:
绘制完成后,可通过点击图形来拖动整体,或调整各个顶点位置:
若想绘制双箭头,只需将 AttackArrow
替换为 DoubleArrow
:
const geometry2 = new CesiumPlot.DoubleArrow(Cesium, viewer, {
material: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
outlineMaterial: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
outlineWidth: 3,
});
对应效果如下:
根据已有坐标数据创建图形
我们也可以不使用鼠标绘制,而是基于已有点位数据直接生成图形。例如,以下是一组笛卡尔坐标点:
const cartesianPoints = [
{
x: -2133835.4252435253,
y: 4417894.642531558,
z: 4061821.4828650053,
},
{
x: -2137181.2256785277,
y: 4417579.261006469,
z: 4060414.659839411,
},
{
x: -2139410.4770342503,
y: 4412744.708073081,
z: 4064468.266519916,
},
];
基于这些数据创建进攻箭头图形:
const geometry3 = CesiumPlot.createGeometryFromData(Cesium, viewer, {
type: "AttackArrow",
cartesianPoints: cartesianPoints,
style: {
material: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
outlineMaterial: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
},
});
效果如下所示:
优势总结
使用 cesium-plot-js 进行符号绘制,有以下优势:
- 无需手动计算复杂图形的顶点;
- 多种常见符号可直接绘制,支持箭头、圆弧、钩状标记等;
- 交互友好、代码简洁、功能丰富;
- 支持数据导出与还原,便于集成与持久化。
代码
文章中的案例代码,可以访问 https://github.com/calmound/cesium-demo/tree/main/src/demos/arrow-symbol (opens in a new tab)