javascriptcesiumjsczml

Cloning and modifiying CZML Packets


I wish to spawn a certain number of copies of shape1 and shape2 in different positions that shall only be known at runtime, and be able to programmatically alter their other properties as well.

What is the preferred methodology for referring to, cloning, and modifying CZML Packets?

var czml = [{
"id" : "document",
    "name" : "CZML Geometries: Cones and Cylinders",
    "version" : "1.0"
}, {
    "id" : "shape1",
    "name" : "Green cylinder with black outline",
    "position" : {
        "cartographicDegrees" : [-100.0, 40.0, 200000.0]
    },
    "cylinder" : {
        "length" : 400000.0,
        "topRadius" : 200000.0,
        "bottomRadius" : 200000.0,
        "material" : {
            "solidColor" : {
                "color" : {
                    "rgba" : [0, 255, 0, 128]
                }
            }
        },
        "outline" : true,
        "outlineColor" : {
            "rgba" : [0, 0, 0, 255]
        }
    }
}, {
    "id" : "shape2",
    "name" : "Red cone",
    "position" : {
        "cartographicDegrees" : [-105.0, 40.0, 200000.0]
    },
    "cylinder" : {
        "length" : 400000.0,
        "topRadius" : 0.0,
        "bottomRadius" : 200000.0,
        "material" : {
            "solidColor" : {
                "color" : {
                    "rgba" : [255, 0, 0, 255]
                }
            }
        }
    }
}];

var dataSource = Cesium.CzmlDataSource.load(czml);
viewer.dataSources.add(dataSource);

Solution

  • Cesium turns CZML into an EntityCollection full of Entities when the CzmlDataSource is loaded.

    But before I explain further, some clarification on that dataSource. If you scroll to the bottom of the example you posted, you see these two lines. They come from official sample code, but unfortunately they've misled a few folks:

    var dataSource = Cesium.CzmlDataSource.load(czml);
    viewer.dataSources.add(dataSource);
    

    The variable name is a misnomer. load is asynchronous and returns a Promise to a dataSource, not an actual dataSource. To get a reference to the actual dataSource, you have to get a callback when the promise resolves:

    Cesium.CzmlDataSource.load(czml).then(function(dataSource) {
        viewer.dataSources.add(dataSource);
        // do more things with dataSource...
    });
    

    Now that you have a real dataSource (inside the async callback), you can find properties like dataSource.entities which is your EntityCollection.

    You can't directly clone an Entity, but you can add new Entity({ options... }) to an EntityCollection from a generic options object that can be saved and re-used multiple times. You can also live-edit most of the properties on an Entity to reflect changes at runtime. Editing entity properties is of course much more performant than destroying and recreating an Entity.

    CZML packets are discarded after the EntityCollection is built, but the Entity ID values remain. You can use dataSource.entities.getById('...') to find the Entity that was built from a particular CZML packet.