Extending CZML

In the documentation it says that it is possible to extend CZML with custom properties. What I would like to be able to do is to make a DynamicObjectCollection with CZML input, and later get the extended properties with the DynamicObject from the getObject function. As far as I can tell, the extended properties are not available in the DynamicObject. Is there some other way to get the extended data?

Yes, though right now it’s a bit cumbersome. Currently, CZML properties are dealt with in an “opt-in” kind of way: there’s specific hookup that looks for the current standard set of properties, but in the long run, I think we want to change the DynamicScene code to automatically detect and process any simple property it finds in the document. I think certain data types, possibly cartesian/cartographic, will require specific knowledge of the schema, but simple string or number properties ought to be made to work out of the box.

The NORAD Tracks Santa application from last December used custom CZML properties extensively, though, so I can pull some example code out of there to demonstrate how to achieve this with the current code. In summary, you need to define “updater”, “merger” and “cleaner” functions that handle your custom properties. Then, you can either add those functions to CzmlDefaults, or provide them to processCzml and CompositeDynamicObjectCollection.

Here’s some code from the Santa app. Throughout the night, each location Santa visited had, in addition to the normal billboard and position properties, custom CZML properties for “wikipedia” and “video” which contained Wikipedia page names for the location, and YouTube video IDs if the Santa Cams were lucky enough to spot him flying around near that location.

// this is just a convenience function that will probably be built into Cesium eventually when we refactor DynamicScene

// the signature of a “processor” / “updater” (terms are inconsistent in the current code) function is:

// * @param {DynamicObject} dynamicObject The DynamicObject which will contain the properties.

// * @param {Object} packet The CZML packet to process.

// * @returns {Boolean} true if any new properties were created while processing the packet, false otherwise.

function createProcessor(propertyName, type) {

return function(dynamicObject, packet) {

var packetData = packet[propertyName];

if (typeof packetData === ‘undefined’) {

return false;

}

var property = dynamicObject[propertyName];

var propertyCreated = typeof property === ‘undefined’;

if (propertyCreated) {

dynamicObject[propertyName] = property = new DynamicProperty(type);

}

property.processCzmlIntervals(packetData);

return propertyCreated;

};

}

// This object is just here for organizational purposes. updaters/mergers/cleaners are really just free functions.

var DynamicLocation = {

processCzmlPacketVideo : createProcessor(‘video’, CzmlString),

processCzmlPacketWikipedia : createProcessor(‘wikipedia’, CzmlString),

mergeProperties : function(targetObject, objectToMerge) {

targetObject.video = defaultValue(targetObject.video, objectToMerge.video);

targetObject.wikipedia = defaultValue(targetObject.wikipedia, objectToMerge.wikipedia);

},

undefineProperties : function(dynamicObject) {

dynamicObject.video = undefined;

dynamicObject.wikipedia = undefined;

}

};

// If you want to install your custom property globally, you can just add them to the CzmlDefaults arrays.

// Or, this shows how you can build a local array and give that array to the objects that use them.

var updaters = CzmlDefaults.updaters.concat([

DynamicLocation.processCzmlPacketVideo,

DynamicLocation.processCzmlPacketWikipedia

// others…

]);

var mergers = CzmlDefaults.mergers.concat([DynamicLocation.mergeProperties]);

var cleaners = CzmlDefault.cleaners.concat([DynamicLocation.undefineProperties]);

// This will handle all standard CZML properties too. The Santa app didn’t use the defaults and instead was more selective about only using the ones necessary in order to reduce the size of the custom built files, e.g. excluding sensors completely, etc.

// processCzml uses updaters

processCzml(json, czmlCollection, url, updaters);

// CompositeDynamicObjectCollection uses mergers and cleaners

var compositeCollection = new CompositeDynamicObjectCollection([czmlCollection, clientCollection], mergers, cleaners);

// Given all that, then we end up with wikipedia and video properties on the dynamic objects, as you’d expect.

var videoID;

var wikipedia;

if (typeof dynamicObject.video !== ‘undefined’) {

videoID = dynamicObject.video.getValue(currentTime);

}

if (typeof dynamicObject.wikipedia !== ‘undefined’) {

wikipedia = dynamicObject.wikipedia.getValue(currentTime);

}

//both videoID and wikipedia are strings, if defined.

Thanks for the detailed reply!

I was actually thinking of something a little different. I was hoping to be able to have all of the properties show up in the object, without writing custom functions for each property.

Basically, I would like to be able to have something like this:

var czml = {
    "id": "AIRCRAFT_DATA-1608",
    "availability": "2012-08-04T16:00:00Z/2012-08-04T16:05:00Z",
    /* .... */
    "extendedData": {
        "course": "271.724",
        "mission": "00465",
        "mission_type": "AIRLIFT",
        "side": "G_SIDE_1"
    }
}

And then use a function like DynamicObject.getCZML(), which would just return a copy of the raw CZML that was passed when the object was created.

This is similar to what the d3 library does. They add a __data__ property to every object that lets you access the raw data that was used to create it originally.

Eventually, the plan is to have them show up on the object automatically, without needing to write custom updaters. It just hasn’t happened yet. If anyone wants to work on this, we’d be happy for the help. I don’t think keeping the original CZML around is a good idea, mainly because I think the memory footprint would get huge.

If you can point me in the right direction, I'd like to start working on it.

Sorry for the slow reply. It would be awesome if you want to take a shot at it. I’ll try and write up some details about what I think needs to be done and post it to the mailing list tomorrow. Thanks.