Cesium 连线方案对比及选择
发布时间: 2026-04-17
我是一个Cesium的初学者,最近开始在项目中开始使用Cesium开发一些基础功能,其中有个功能是连线,第一版是大模型生成的,后来我发现性能明显感觉有点不正常,渲染慢、而且每次绘制新的点network中会产生一堆重复的worker,每次绘制新的点都会产生,我意识到这里是有性能问题的,经过深入细致的查看代码,结合跟大模型学习的结论,现在使用的不断追加 polyline 到entities中对于线段数量上来之后就会有性能问题,于是我弄了个最小复现示例来最终问题。
方案
第一种entities.add
第一种的核心代码是:
function syncIssueEntityLines(viewer: Viewer, waypoints: Waypoint[]) {
if (waypoints.length < 2) {
return;
}
const index = waypoints.length - 2;
const id = `${issueLinePrefix}${index}`;
// 始终连线最后两个点
const positions = [toCartesian(waypoints[index]), toCartesian(waypoints[index + 1])];
viewer.entities.add({
id,
polyline: {
positions,
width: 4,
material: Color.fromCssColorString('#ff9f43'),
},
});
}它的特点是:
- 每次点击只处理最新形成的一段线
- 每一段线都是一个独立的
Entity polyline - 点越多,页面里的
Entity折线对象就越多
也就是说,第一种不是维护一条总线,而是:
每次点击就新增一个新的 Entity polyline 线段对象。
第二种 CallbackProperty
第二种的核心代码是 CallbackProperty,它是被动调用的,调用时机有些多,第二个参数设置为false表示动态模式,每帧调用一次,当调用触发时拿到最新的点坐标数组就去更新这个线实体。
function syncCallbackEntityLine(viewer: Viewer, waypointsRef: React.MutableRefObject<Waypoint[]>) {
if (viewer.entities.getById(callbackLineId)) {
return;
}
// 只创建一次polyline对象
viewer.entities.add({
id: callbackLineId,
polyline: {
// polyline的连线坐标是动态的,Callback会在
positions: new CallbackProperty(() => {
if (waypointsRef.current.length < 2) {
return [];
}
return waypointsRef.current.map(toCartesian);
}, false),
width: 4,
material: Color.fromCssColorString('#f25f5c'),
},
});
}它的特点是:
- 整个生命周期只创建一条
Entity polyline - 点击地图时不会再新增新的线对象
- 线的位置通过
CallbackProperty动态读取最新点位
也就是说,第二种不是“每次点击新增一条线”,而是:
第三种 primitive
第三种的核心代码是:
function syncPrimitiveLines(
polylineCollection: PolylineCollection,
polylinesRef: React.MutableRefObject<Polyline[]>,
waypoints: Waypoint[],
) {
if (waypoints.length < 2) {
return;
}
const index = waypoints.length - 2;
const positions = [toCartesian(waypoints[index]), toCartesian(waypoints[index + 1])];
polylinesRef.current[index] = polylineCollection.add({
positions,
width: 4,
material: Material.fromType('Color', {
color: Color.fromCssColorString('#3ddc97'),
}),
});
}它的特点是:
- 每次点击也只处理最新形成的一段线
- 但新增的不是
Entity polyline - 而是
PolylineCollection里的 primitive 折线
也就是说,第三种和第一种表面上都像“每次点击新增一段线”,但本质差异是:
- 第一种新增的是
Entity polyline - 第三种新增的是
PolylineCollectionprimitive
性能的差异
第一种的性能特征
第一种每次点击都会新增一个新的 Entity polyline:
viewer.entities.add({
id,
polyline: {
positions,
width: 4,
material: Color.fromCssColorString('#ff9f43'),
},
});它每一次新增一条线都会重复产生一堆worker的创建:

它的性能特点是:
- 新增点位后,会新增一个新的 Entity 线对象
- 点越多,Entity 线对象越多
- Cesium 需要持续处理新增 Entity 对应的几何准备工作
所以第一种通常是这 3 种里最敏感的,也就是为什么每多一根线都会创建很多worker,肉眼可见的绘制延迟卡顿。新的 Entity polyline 被不断创建,导致 Cesium 更频繁地调度和使用 Worker 处理相关几何任务
第二种的性能特征
第二种只创建一次:
viewer.entities.add({
id: callbackLineId,
polyline: {
positions: new CallbackProperty(...),
},
});之后点击地图时,不再新增线对象,只是更新 waypointsRef.current,让 CallbackProperty 在渲染时读取最新点位。
只会在页面初始化时产生一堆workder调用,后期增加线渲染快
它的性能特点是:
- 整个页面里只有一条
Entity polyline - 不会随着点击次数增加而不断创建新的 Entity 线对象
- 更适合“只维护一条总线”的场景
所以第二种通常会比第一种稳定很多。
第二种尤其适合这种场景:
- 你只关心最后是一条连续折线
- 点位会持续追加
- 你是按“点集合”管理这条线,而不是按“线段对象”管理
第二种不太适合这些场景:
- 只高亮某一段线
- 只删除某一段线
- 只隐藏某一段线
- 只给某一段线改颜色或改宽度
- 给每一段线绑定独立业务 id、状态、提示信息
- 需要把每一段线当成独立对象选中、编辑、管理
原因很简单:
第二种始终只有一条总线,没有独立的“第 1 段线对象”“第 2 段线对象”。
所以第二种更适合“按点管理整条线”,不适合“按段管理线”。
第三种的性能特征
第三种每次点击也会新增新的线段,但新增的是 primitive:
polylineCollection.add({
positions,
width: 4,
material: Material.fromType('Color', ...),
});同第二种,只有初始化会产生worker创建,后期不存在
它的性能特点是:
- 每次点击新增的是 primitive 层对象
- 不走
Entity polyline那层高层封装 - 对高频交互绘制通常更友好
所以第三种通常适合绘制态、编辑态、交互密集型场景。
第三种更适合这种需求:
- 每一段线都希望作为独立对象存在
- 后续可能要单独操作某一段线
- 某一段线可能需要单独高亮、删除、修改样式
- 线段本身就是业务对象,而不是仅仅服务于一条整体折线
也可以把第二种和第三种的差异简单理解成:
- 第二种更偏“我有一组点,这些点组成一条线”
- 第三种更偏“我有很多段线,这些线段共同组成一条路径”
总结
少量点连线可以使用 entities.add ,但是还是不太建议,如果只要一根线,不对这些线中间某一段做特别处理选择使用 CallbackProperty ,如果要对中间的一些线做更换颜色、选中,线由比较多使用 Primitive 的方式。
