Appearance
FenceEffect 电子围栏效果
在指定闭合折线区域上生成双层墙体纵向扫描的电子围栏,对齐源案例 SpecialEffects/Fence。 底层是静态全高渐变墙(栅栏本体),上层是墙高从地面涨到
height再回落到地面循环的 扫描带,直观表达「警戒 / 禁飞 / 缓冲区边界」。动画由时间驱动(duration为一次完整 扫描周期),修复源实现按帧累加fenceHeight * 0.004的帧率依赖问题。
能力定位
FenceEffect 适合:
- 电子围栏 / 警戒区:在重要目标、营区、禁飞区外围画一圈动态扫描边界;
- 边界高亮:用纵向扫描带强调某块区域的范围,配合
setPositions在运行时动态改形; - 多围栏叠加:不同
color/height/duration的围栏可并行使用,互不共享状态。
与 动态立体墙(材质流动)的区别:FenceEffect 的动画作用于墙高 (maximumHeights 锯齿扫描),而非上层材质流动;底层全高墙提供稳定的栅栏本体,扫描带 沿墙高方向从地面向上爬升后回落。
构造函数
ts
constructor(options: FenceEffectOptions)ts
interface FenceEffectOptions {
positions: Cartesian3[]; // 围栏顶点(世界坐标),至少 3 个点,必填
height?: number; // 围栏墙高(米),默认 30
color?: Color; // 围栏颜色,默认 Color.RED
duration?: number; // 一次完整扫描周期(毫秒),默认 3000
}| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
positions | Cartesian3[] | — | 围栏顶点,少于 3 个点构造抛错;墙会沿折线闭合 |
height | number | 30 | 围栏墙高(米),maximumHeights = 贴地高度 + height |
color | Color | Color.RED | 围栏颜色,同时作用于底层渐变墙与扫描墙 |
duration | number | 3000 | 扫描周期(毫秒):墙高从地面涨到 height 后回落,一次 duration 完成 |
生命周期
ts
on(viewer: Viewer): void // 启用效果:创建底层全高墙与扫描墙两个实体,记录扫描起点(幂等)
off(viewer: Viewer): void // 停用效果:移除本效果创建的两个实体(幂等)
destroy(viewer: Viewer): void // 销毁效果,委托 off 释放全部自有资源(可重复调用)
setPositions(positions: Cartesian3[]): void // 运行时更新围栏顶点并重算贴地高度(启用状态下同样生效)| 方法 | 参数 | 说明 |
|---|---|---|
on | viewer | 重复调用为 no-op,不会重复创建实体 |
off | viewer | 未启用时调用为 no-op |
destroy | viewer | 委托 off,重复调用安全 |
setPositions | positions | 少于 3 个点抛错;顶点与高度经 CallbackProperty 跟随最新状态,无需重建实体 |
基础示例
ts
import { FenceEffect } from '@nexa/gis-cesium'
import { Cartesian3, Color } from 'cesium'
// 扫描动画由时钟时间驱动:必须让时钟推进(shouldAnimate 或手动 tick),
// 否则 CallbackProperty 的 time 不变化,扫描墙会停在贴地高度看不到。
viewer.clock.shouldAnimate = true
const effect = new FenceEffect({
positions: [
Cartesian3.fromDegrees(106.455901, 29.505694),
Cartesian3.fromDegrees(106.457311, 29.506953),
Cartesian3.fromDegrees(106.458057, 29.506492),
Cartesian3.fromDegrees(106.456782, 29.504892),
Cartesian3.fromDegrees(106.455901, 29.505710),
],
height: 30,
color: Color.RED,
duration: 3000,
})
effect.on(viewer)
// 页面或场景退出时由创建方负责清理
effect.destroy(viewer)进阶示例
多围栏并行 + setPositions 运行时改形:
ts
import { FenceEffect } from '@nexa/gis-cesium'
import { Cartesian3, Color } from 'cesium'
// 红色 30 米高,慢速扫描
const redFence = new FenceEffect({
positions: redPositions, // 同基础示例
height: 30,
color: Color.RED,
duration: 3000,
})
redFence.on(viewer)
// 青色 20 米高,快速扫描(对齐源案例 addGreenFence)
const greenFence = new FenceEffect({
positions: greenPositions,
height: 20,
color: Color.fromCssColorString('#0BFF0D'),
duration: 1500,
})
greenFence.on(viewer)
// 8 秒后把红色围栏改造成矩形围界
setTimeout(() => {
redFence.setPositions([
Cartesian3.fromDegrees(106.4530, 29.5055),
Cartesian3.fromDegrees(106.4590, 29.5055),
Cartesian3.fromDegrees(106.4590, 29.5078),
Cartesian3.fromDegrees(106.4530, 29.5078),
])
}, 8000)
// 场景退出时统一清理
redFence.destroy(viewer)
greenFence.destroy(viewer)实现与性能说明
- 复用现有材质:底层墙使用
WallGradientsMaterialProperty,扫描墙使用WallTrailVerticalMaterialProperty,均为 SDK 既有材质,无新增 GLSL; - 动画依赖时钟推进:扫描墙高度回调的参数
time来自viewer.clock.currentTime,只有 时钟前进相位才会变化。SDK 的CesiumViewer默认不透传shouldAnimate(时钟静止), 启用前需viewer.clock.shouldAnimate = true,或自行驱动时钟(如viewer.clock.tick()),对齐源案例shouldAnimate: true; - 时间驱动扫描:扫描墙
maximumHeights用CallbackProperty(isConstant=false)按JulianDate.secondsDifference(now, startTime)取模计算锯齿相位:相位 0 → 贴地高度,相位 0.5 → 贴地高度 + height,相位 1 → 回落贴地高度。帧率无关, 修复源实现按帧累加fenceHeight * 0.004的帧率依赖(不同设备扫描速度不一致); - 顶点跟随:
positions/ 贴地高度 / 全高均经CallbackProperty返回当前引用,setPositions运行时重设后实体自动跟随,长度保持一致(回归:曾因ConstantProperty捕获旧数组引用导致positions与maximumHeights长度失配); - 高度来源:贴地高度由
Cartographic.fromCartesian(position).height计算,墙默认随 地形/地物高度贴底;minimumHeights与maximumHeights长度始终与顶点数一致; - 性能:每帧求值
positions/minimumHeights/maximumHeights三次回调(数组引用返回, 无拷贝),适合少量围栏;扫描墙高度随帧变化会触发墙几何更新(源实现同样行为)。
Cesium 版本限制
- 依赖
CallbackProperty/Cartographic/WallGraphics,为 Cesium 长期稳定 API; - 已验证目标版本:Cesium 1.133.1;
CallbackProperty回调签名以目标版本为准(time: JulianDate | undefined),按源码 JSDoc@example使用即可。
清理责任
on()创建的底层墙与扫描墙两个实体统一由destroy(viewer)(或off(viewer))释放;- 不调用
destroy会导致两个 wall 实体残留,务必在页面或场景退出时清理; destroy可重复调用,幂等安全;off后可再次on重新启用。
与原生 Cesium API 的组合方式
positions可直接复用viewer.entities.add()或绘制工具产出的Cartesian3[];- 可与
viewer.camera.flyTo(viewer.entities)组合,让相机自动框住全部围栏; - 需要显示围栏名称时,叠加一个 label/point 实体即可,
FenceEffect不占用命名空间。