_onDataSourceAdded undefined after removing a data source

Hi,

I’ve been stuck on the problem for days and hoping someone could help.
I have an application that loads a data source, then I want to remove and destroy it and then add another. Here is my code:

// Get some dataSource1

// Add the dataSource1
 viewer.dataSources.add(dataSource1);

// Remove and destroy all data sources
viewer.dataSources.removeAll(true);

// Add in another the dataSource2
 viewer.dataSources.add(dataSource2);

// Also fails if I just try to readd the same dataSource1

I have tried setting viewer.dataSources = new Cesium.DataSourceCollection() right after destroying the dataSources and a few other things, but no luck.

Is this a known issue or am I just doing something obviously wrong.

Here is the exact error I get:

Cesium.js:80 An error occurred while rendering. Rendering has stopped.
TypeError: Cannot read properties of undefined (reading ‘length’)
TypeError: Cannot read properties of undefined (reading ‘length’)
at DataSourceDisplay.update (https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js:72:2165906)
at Viewer._onTick (https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js:80:269272)
at Event.raiseEvent (https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js:63:36277)
at Clock.tick (https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js:65:314944)
at CesiumWidget.render (https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js:80:166311)
at n (https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js:80:152059)
CesiumWidget.showErrorPanel @ Cesium.js:80
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
requestAnimationFrame (async)
requestAnimationFramePolyFill @ Cesium.js:72
n @ Cesium.js:80
Cesium.js:72 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘add’)
at DataSourceDisplay._onDataSourceAdded (Cesium.js:72:2167623)
at Event.raiseEvent (Cesium.js:63:36277)
at Cesium.js:72:2018300

I think it has something to do with my viewer.scene.primitives.destroy() call.

Here is an example error in Sandcastle if you comment out the primitives.destroy() call.

But I run into memory issues if I just call viewer.DataSources.removeAll(true)

I was able to make some progress with a work around as suggested in other threads. Instead of adding and removing multiple data sources, I just keep track of the number of entities and keep adding to the same data source. And use the running entity count as the entity id.

So the logic looks like:

  1. Create an empty custom data source that will store all entities

  2. Loop through each entity in anew data source and get or create the entity based on a running count of the number of entities.

Repeat when adding another data source, just keep incrementing and adding to the main data source.

And for removing, I simply turn show to false for all entities and reset the entity counter back to 0, instead of actually removing the entities or data source

I found my issue.

scene.primitives is a default primitives collections with another primitive collection inside it. I should not be calling removeall on it, instead I should get the id of the the polyline collection that I added and destroy it and then remove it.

I still see a memory leak, so if I could do something similar to the entities where I just reuse the polyline primitives that would be ideal. But it isn’t and issue for now. Hopefully this helps someone.

Hello there,

I agree with your assessment. Data sources are tied to the Entity API, which is a higher level API than the Primitives API, and I would not recommend mixing the two. Sticking with the Entity API, have you tried calling entities.suspendEvents() before add and remove operations, followed by entities.resumeEvents() when you’re done?

Yes, I am calling suspendEvents() and resumeEvents(). I have gotten to a good spot with my project.

One somewhat related question. I have 10k+ polylines, that cause a crash if I add them as entities so I have to add them as primitives. Is there a way to add availability intervals to the polylines in a Polylines collection? Where each line would have different availabilities. I couldn’t find a way, So I will have to load fewer polylines to just load then statically. I have this working for points and that is probably good enough for my usecase.

Is there a way to add availability intervals to the polylines in a Polylines collection? Where each line would have different availabilities.

Availability is a higher-level Entity API level property. It is not an option in the lower-level Primitive API. There’s generally trade off between here between user-friendliness and performance.

I can recommend that for best performance, group polylines in few collections so that polylines with the same update frequency are together. Also don’t destroy and create new geometries, prefer re-using a set of polylines as much as possible.