Saving and restoring UI state.

<perspective-viewer> is persistent, in that its entire state (sans the data itself) can be serialized or deserialized. This include all column, filter, pivot, expressions, etc. properties, as well as datagrid style settings, config panel visibility, and more. This overloaded feature covers a range of use cases:

  • Setting a <perspective-viewer>'s initial state after a load() call.
  • Updating a single or subset of properties, without modifying others.
  • Resetting some or all properties to their data-relative default.
  • Persisting a user's configuration to localStorage or a server.

Serializing and deserializing the viewer state

To retrieve the entire state as a JSON-ready JavaScript object, use the save() method. save() also supports a few other formats such as "arraybuffer" and "string" (base64, not JSON), which you may choose for size at the expense of easy migration/manual-editing.

const json_token = await elem.save();
const string_token = await elem.save("string");

For any format, the serialized token can be restored to any <perspective-viewer> with a Table of identical schema, via the restore() method. Note that while the data for a token returned from save() may differ, generally its schema may not, as many other settings depend on column names and types.

await elem.restore(json_token);
await elem.restore(string_token);

As restore() dispatches on the token's type, it is important to make sure that these types match! A common source of error occurs when passing a JSON-stringified token to restore(), which will assume base64-encoded msgpack when a string token is used.

// This will error!
await elem.restore(JSON.stringify(json_token));

Updating individual properties

Using the JSON format, every facet of a <perspective-viewer>'s configuration can be manipulated from JavaScript using the restore() method. The valid structure of properties is described via the ViewerConfig and embedded ViewConfig type declarations, and View chapter of the documentation which has several interactive examples for each ViewConfig property.

// Set the plugin (will also update `columns` to plugin-defaults)
await elem.restore({ plugin: "X Bar" });

// Update plugin and columns (only draws once)
await elem.restore({ plugin: "X Bar", columns: ["Sales"] });

// Open the config panel
await elem.restore({ settings: true });

// Create an expression
await elem.restore({
    columns: ['"Sales" + 100'],
    expressions: { "New Column": '"Sales" + 100' },
});

// ERROR if the column does not exist in the schema or expressions
// await elem.restore({columns: ["\"Sales\" + 100"], expressions: {}});

// Add a filter
await elem.restore({ filter: [["Sales", "<", 100]] });

// Add a sort, don't remove filter
await elem.restore({ sort: [["Prodit", "desc"]] });

// Reset just filter, preserve sort
await elem.restore({ filter: undefined });

// Reset all properties to default e.g. after `load()`
await elem.reset();

Another effective way to quickly create a token for a desired configuration is to simply copy the token returned from save() after settings the view manually in the browser. The JSON format is human-readable and should be quite easy to tweak once generated, as save() will return even the default settings for all properties. You can call save() in your application code, or e.g. through the Chrome developer console:

// Copy to clipboard
copy(await document.querySelector("perspective-viewer").save());