Skip to main content
Version: 2.x

Saving viewer state

Reveal supports saving the camera state and styled filters that have been applied to the loaded model(s). This functionality can help support sharing links and local storage of a given view. Internally the input to a given filter is stored and is replayed when restoring the view. This usually means that substantially less data needs to be serialized in order to share the given state of the viewer. The serialized JSON blob also keeps information about styling/filtering of the model by storing all styled sets.

Getting the viewer state

In the example below we apply some filter to our loaded model using the NodeCollectionBase type from Styling Cad models. Then we can call the viewer.getViewState() function which return a serialized JSON blob containing the view state. Depending on the application, the view state can be additionally transformed into e.g. a URL parameter and transferred through a link.

In the example below, we keep simply print it to the developer console.

Live Editor

Setting the viewer state

Restoring the viewer state is simply a matter of feeding back the JSON blob retrieved from const myState = viewer.getViewState() into viewer.setViewState(myState). In the example below, a previously stored state is applied which applies a red color to nodes that have an attribute 'PDMS.Type'.

note

Setting the viewer state assumes that model has already been loaded. An error will be thrown if a given state is loaded for a model which does not exist.

Live Editor

Serializing and deserializing custom node collections

When working with styled custom node collections, the Reveal viewer needs to know how to serialize and deserialize the set. Serialization is handled through the abstract method serialize which needs to be implemented when extending NodeCollectionBase. The output of serialize is of type SerializedNodeCollection and contains a token which is used to recreate the NodeCollectionBase during deserialization, and a state object which contains the data needed to restore the NodeCollectionBase. It is up to the application developer to fill this state object with any nessesary data needed to recreate the state of the NodeCollectionBase. An optional options object can also be supplied containing any metadata for loading data (e.g. the number of API calls to fetch the needed data in parallel). The contents returned from serialize is contained in the result of getViewState.

In addition to serialization, Reveal also needs to know how to recreate the custom NodeCollectionBase during deserialization. This is done by calling the free-function registerCustomNodeCollectionType with the same token defined by the custom NodeCollectionBase and a lambda function which instantiates and restore the state of the NodeCollectionBase. The lambda function has two parameters: the descriptor containing the state and options which should be applied to the NodeCollectionBase and the context containing an instance of the CogniteClient from the Cognite SDK and the Cognite3DModel which the NodeCollectionBase was originally applied to. It is up to the application developer how and if they want to use the context and/or descriptor, but it is provided as a convinience.

An example of a simple custom NodeCollectionBase can be seen below. For more information on creating a custom NodeCollectionBase, see create custom node collections.

// import { IndexSet, NodeCollectionBase, registerCustomNodeCollectionType } from '@cognite/reveal';

class MyNodeCollection extends NodeCollectionBase {

isLoading = false;
_indexSet = new IndexSet();

constructor(model) {
// token used for serialization / deserialization
super('MyNodeCollection');

for (let i = 0; i < model.nodeCount / 2; i++) {
this._indexSet.add(i);
}
}

getIndexSet() {
return this._indexSet;
}

serialize() {
return {
token: this.classToken,
state: this._indexSet.toRangeArray()
}
}

clear() {
this._indexSet.clear();
this.notifyChanged();
}
}

// Register deserializer for type
registerCustomNodeCollectionType(
'MyNodeCollection',
(descriptor, context) => {
return Promise.resolve(new MyNodeCollection(context.model));
}
);