Cesium快速入门到精通系列教程十二:Cesium1.74中环绕地球生成经线环
使用Cesium1.74来实现环绕地球的经线环,效果如下:
一、普通实现:
// 初始化Cesium Viewerconst viewer = new Cesium.Viewer("cesiumContainer", {terrainProvider: Cesium.createWorldTerrain(),shouldAnimate: true,});const drawSpaceLine = spaceLineArr => {const positions = Cesium.Cartesian3.fromDegreesArrayHeights(spaceLineArr);viewer.entities.add({polyline: {positions,width: 2,material: new Cesium.PolylineGlowMaterialProperty({glowPower: 0.1,color: Cesium.Color.CYAN,arcTYPE: Cesium.ArcType.GEODESIC,}),},});};drawSpaceLine([116.2330, -90, 1000000, 116.2330, 90, 1000000]);drawSpaceLine([296.2330, -90, 1000000, 296.2330, 90, 1000000]);
二、优化:通过检查 spaceLineEntity 是否存在来避免重复创建实体
// 初始化Cesium Viewerconst viewer = new Cesium.Viewer("cesiumContainer", {terrainProvider: Cesium.createWorldTerrain(),shouldAnimate: true,});// 初始化一个线条实体let spaceLineEntity = null;/*** 绘制或更新空间线* @param {Array} spaceLineArr - 线条的经度、纬度和高度数组*/const drawOrUpdateSpaceLine = (spaceLineArr) => {// 如果实体不存在,则创建一个新的if (!spaceLineEntity) {const positions = Cesium.Cartesian3.fromDegreesArrayHeights(spaceLineArr);spaceLineEntity = viewer.entities.add({polyline: {positions: positions,width: 2,arcType: Cesium.ArcType.GEODESIC,material: new Cesium.PolylineGlowMaterialProperty({glowPower: 0.1,color: Cesium.Color.CYAN,}),},});} else {// 如果实体已存在,更新其positionsconst positions = Cesium.Cartesian3.fromDegreesArrayHeights(spaceLineArr);spaceLineEntity.polyline.positions = positions;}};// 示例:绘制一条线条drawOrUpdateSpaceLine([116.233, -90, 1000000, 116.233, 90, 1000000]);// 如果需要不断更新线条,可以这样调用:setInterval(() => {const newSpaceLineArr1 = [116.233 + Math.random() * 10,-90,1000000,116.233 + Math.random() * 10,90,1000000,];drawOrUpdateSpaceLine(newSpaceLineArr1);}, 2000);
三、进一步优化:只有当传入的数据(spaceLineArr)发生变化时才更新线条的位置,否则不进行重绘。
如何判断数据是否变化?
由于 spaceLineArr 是一个数组,直接比较 spaceLineArr 是否变化不能简单地用 === 或 ==,因为 JavaScript 中数组是引用类型,即使内容相同,只要不是同一个引用,=== 也会返回 false。
解决方案
缓存上一次的 spaceLineArr,每次调用 drawOrUpdateSpaceLine 时,先比较当前传入的 spaceLineArr 和缓存的 spaceLineArr 是否深度相等(即每个元素都相同)。
如果数据相同,则不更新;如果不同,则更新 positions 并缓存新的 spaceLineArr。
// 初始化Cesium Viewer
const viewer = new Cesium.Viewer("cesiumContainer", {terrainProvider: Cesium.createWorldTerrain(),shouldAnimate: true,
});// 初始化一个线条实体
let spaceLineEntity = null;// 缓存上一次的 spaceLineArr
let lastSpaceLineArr = null;/*** 绘制或更新空间线* @param {Array} spaceLineArr - 线条的经度、纬度和高度数组*/
const drawOrUpdateSpaceLine = (spaceLineArr) => {// 如果数据没有变化,则直接返回,不进行重绘if (arraysAreEqual(lastSpaceLineArr, spaceLineArr)) {return;}// 更新缓存的 spaceLineArrlastSpaceLineArr = [...spaceLineArr]; // 使用展开运算符复制数组,避免引用问题// 如果实体不存在,则创建一个新的if (!spaceLineEntity) {const positions = Cesium.Cartesian3.fromDegreesArrayHeights(spaceLineArr);spaceLineEntity = viewer.entities.add({polyline: {positions: positions,width: 2,arcType: Cesium.ArcType.GEODESIC,material: new Cesium.PolylineGlowMaterialProperty({glowPower: 0.1,color: Cesium.Color.CYAN,}),},});} else {// 如果实体已存在,更新其positionsconst positions = Cesium.Cartesian3.fromDegreesArrayHeights(spaceLineArr);spaceLineEntity.polyline.positions = positions;}
};/*** 深度比较两个数组是否相等* @param {Array} arr1 * @param {Array} arr2 * @returns {Boolean}*/
function arraysAreEqual(arr1, arr2) {// 如果两个数组都是 null 或 undefined,认为相等if (arr1 === arr2) return true;if (arr1 == null || arr2 == null) return false;if (arr1.length !== arr2.length) return false;// 逐个比较数组元素for (let i = 0; i < arr1.length; i++) {if (arr1[i] !== arr2[i]) {return false;}}return true;
}// 示例:绘制一条线条
drawOrUpdateSpaceLine([116.233, -90, 1000000, 116.233, 90, 1000000]);// 如果需要不断更新线条,可以这样调用:
setInterval(() => {const newSpaceLineArr1 = [116.233 + Math.random() * 10,-90,1000000,116.233 + Math.random() * 10,90,1000000,];drawOrUpdateSpaceLine(newSpaceLineArr1);
}, 2000);
优化点
- arraysAreEqual 函数:用于深度比较两个数组是否相等,避免不必要的重绘。
- lastSpaceLineArr 缓存:存储上一次传入的 spaceLineArr,每次调用时先比较是否变化。
- [...spaceLineArr] 复制数组:避免直接引用传入的数组,防止外部修改影响缓存判断。
最终效果
数据变化时:更新线条位置。
数据不变时:跳过重绘,减少 Cesium 的计算开销,提高性能。