背景:Vue+Cesium加载GeoJSON并设置entity.billboard,在组件销毁/释放实体entity时报错:TypeError: Cannot read properties of undefined (reading '_textureAtlas') at Billboard.setImage (webpack-internal:///./node_modules/cesium/Source/Scene/Billboard.js:1268:98)
async estimate() {try {// 使用Promise.all来同时处理多个axios请求const [floodLayerResponse, alterLayerResponse] = await Promise.all([axios.get('/api' + this.featuresLayer.model.floodLayer),axios.get('/api' + this.featuresLayer.model.alterLayer)]);// 处理floodLayer数据const floodDs = await Cesium.GeoJsonDataSource.load(floodLayerResponse.data, {clampToGround: true});viewer.dataSources.add(floodDs);floodDs.entities.values.forEach(entity => {entity.polygon.outline = false;let properties = entity.properties;const score = properties['_degree']['_value'];let color;if (score === 1 || score === 2) {color = Cesium.Color.fromCssColorString("#fdfdfd");} else if (score === 3 || score === 4 || score === 5) {color = Cesium.Color.fromCssColorString("rgba(160,190,253,0.7)");} else {color = Cesium.Color.fromCssColorString("rgba(6,76,169,0.87)");}entity.polygon.material = color;});// 处理alterLayer数据alterDs = await Cesium.GeoJsonDataSource.load(alterLayerResponse.data);viewer.dataSources.add(alterDs);alterDs.entities.values.forEach(entity => {if(!entity.billboard){entity.billboard=new Cesium.BillboardGraphics();}entity.billboard = {image: picUrl, // 确保url已经被定义scale: 2,width: 16,height: 16,pixelOffset: new Cesium.Cartesian2(0, -20)};});this.descriptionVisi=true;} catch (error) {console.error('Error loading layers:', error);}},
释放资源报错: TypeError: Cannot read properties of undefined (reading '_textureAtlas') at Billboard.setImage)
viewer.entities.removeAll();viewer.scene.primitives.removeAll();
将设置了billborad的entities先释放,在释放所有primitives
//设置了billbord数据需单独先去除,否则报错:TypeError: Cannot read properties of undefined (reading '_textureAtlas')at Billboard.setImage (webpack-internal:///./node_modules/cesium/Source/Scene/Billboard.js:1268:98)alterDs.entities.removeAll();viewer.scene.primitives.removeAll();this
总结:
Cesium 中遇到 TypeError: Cannot read properties of undefined (reading '_textureAtlas')
这类错误通常与尝试访问未正确初始化或已被销毁的对象的属性有关。在你提到的场景中,这个错误发生在尝试设置 Billboard
的 image
属性时,而该 Billboard
或其相关的资源(如纹理图集 _textureAtlas
)可能已经不再有效或未正确加载。
这个问题可能由几个原因引起:
-
Billboard 已被销毁:在 Cesium 中,如果你移除了包含
Billboard
的Entity
或直接从PrimitiveCollection
中移除了Billboard
,然后尝试再次访问或修改它,就可能导致此类错误。 -
资源加载问题:如果
Billboard
使用的图像资源在尝试设置时没有正确加载,也可能导致内部状态不一致。 -
Cesium 内部状态问题:在某些极端情况下,Cesium 的内部状态可能因为错误的使用或与其他库的冲突而变得不一致。
解决步骤
-
检查 Billboard 的存在性:
在尝试修改Billboard
之前,确保它仍然存在且未被销毁。你可以通过检查其isDestroyed()
方法(如果 Cesium 版本支持)或使用简单的条件语句来验证。
if (billboard && !billboard.isDestroyed()) { billboard.image = 'new-image-url.png';
}
-
注意:
isDestroyed()
方法可能在某些 Cesium 版本中不可用。 -
确保资源已加载:
如果你正在动态更改Billboard
的图像,请确保新的图像 URL 是有效的,并且图像已经加载到 Cesium 中。你可以使用 Cesium 的Resource
类或监听图像加载事件来确保图像已准备好。 -
安全地移除 Entities:
当你需要移除所有 entities 时,确保你正确地从 Cesium 的viewer.entities
中移除了它们。你可以遍历并逐个移除,或者如果可能,直接清空整个集合(注意,直接清空可能会导致事件监听器等问题)。
viewer.entities.removeAll();
如果你需要更细致地控制移除过程,可以遍历 entities
集合并逐个调用 destroy()
方法(尽管 removeAll()
通常已经足够)。
-
检查 Cesium 版本:
确保你使用的 Cesium 版本没有已知的此类问题的 bug。有时,升级到最新版本可以解决这类问题。 -
查看控制台和网络请求:
使用浏览器的开发者工具查看控制台输出和网络请求,看是否有与图像加载或 Cesium 内部错误相关的更多信息。 -
考虑错误处理和日志记录:
在你的应用中增加错误处理和日志记录,以帮助诊断何时何地发生了此类问题。