Search code examples
javascriptcesiumjs

Loading updated data with GeoJsonDataSource in Cesium.js


I'm trying to integrate Cesium 1.11 with an existing backend sending GeoJSON. I'm able to load data onto the view successfully from the first message, however subsequent calls to load() do not update the display.

I've simplified the problem to the following, also available as a fiddle.

  • I expect the second load call to update the display to move the marker to New York, however it stays on London.
  • Feature window still shows the "foo" property as 123, I expect 456.

Code

var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
viewer.dataSources.add(source);

source.load({
    type: "FeatureCollection",
    crs: {
        type: "name",
        properties: {
            name: "urn:ogc:def:crs:OGC:1.3:CRS84"
        }
    },
    features: [{
        type: "Feature",
        properties: {
            foo: 123,
        },
        geometry: {
            type: "Point",
            coordinates: [0.1275, 51.5072] // London
        },
        id: "123"
    }]
});

// workaround, but has side effect of destroying feature window
// source.entities.removeAll();

// sometime later...
source.load({
    type: "FeatureCollection",
    crs: {
        type: "name",
        properties: {
            name: "urn:ogc:def:crs:OGC:1.3:CRS84"
        }
    },
    features: [{
        type: "Feature",
        properties: {
            foo: 456,
        },
        geometry: {
            type: "Point",
            coordinates: [-75.1890, 42.3482] // New York
        },
        id: "123"
    }]
});

What I've tried

  • "forced" an update by calling source.entities.removeAll() however this has the side effect of closing the feature window if it is open during the the update. I'm receiving messages every second so this is not desirable.

  • Yes, I'm aware of the proprietary CZML system, however I'd like to stick to GeoJSON for this relatively simple system.

Update: further debugging. The problem appears to be a design feature...

  • load() helper method in GeoJsonDataSource calls that._entityCollection.removeAll(). This is between a suspendEvents() and resumeEvents() so does not cause the feature window to close.
  • After the resumeEvents() "change" events are fired even though the entities have actually been recreated
  • The existing BillboardVisualizer created by Cesium.Viewer keeps a cached instances to the Entities it used the first time it rendered
  • BillboardVisualizer.update() keeps reading the first position from the 'stale' entity instances and therefore no update is seen.

Solution

  • This looks like a bug in Cesium I just submitted issue #2891 and will try and get a fix into the 1.12 release on August 3rd. In the meantime, you should be able to workaround the issue using your removeAll strategy combined with resetting the selected entity after the load (which should keep the InfoBox around, which is what I assume you mean by feature window.) Here's a complete example that you can based into Sandcastle to see it in action.

    var viewer = new Cesium.Viewer('cesiumContainer');
    var source = new Cesium.GeoJsonDataSource("name123");
    viewer.dataSources.add(source);
    
    Sandcastle.addToolbarButton('Load 1', function(){
        source.entities.removeAll();
        source.load({
            type: "FeatureCollection",
            crs: {
                type: "name",
                properties: {
                    name: "urn:ogc:def:crs:OGC:1.3:CRS84"
                }
            },
            features: [{
                type: "Feature",
                properties: {
                    foo: 123
                },
                geometry: {
                    type: "Point",
                    coordinates: [0.1275, 51.5072] // London
                },
                id: "123"
            }]
        }).then(function(){
            viewer.selectedEntity = source.entities.values[0];
        });
    });
    
    Sandcastle.addToolbarButton('Load 2', function() {
        source.entities.removeAll();
        source.load({
            type: "FeatureCollection",
            crs: {
                type: "name",
                properties: {
                    name: "urn:ogc:def:crs:OGC:1.3:CRS84"
                }
            },
            features: [{
                type: "Feature",
                properties: {
                    foo: 456
                },
                geometry: {
                    type: "Point",
                    coordinates: [-75.1890, 42.3482] // New York
                },
                id: "123"
            }]
        }).then(function(){
            viewer.selectedEntity = source.entities.values[0];
        });
    });