<perspective-viewer> Custom Element library
<perspective-viewer> provides a complete graphical UI for configuring the
perspective library and formatting its output to the provided visualization
plugins.
Once imported and initialized in JavaScript, the <perspective-viewer> Web
Component will be available in any standard HTML on your site. A simple example:
<perspective-viewer id="view1"></perspective-viewer>
<script type="module">
import perspective from "@perspective-dev/client";
import "@perspective-dev/viewer";
const viewer = document.getElementById("view1");
const worker = await perspective.worker();
await worker.table(data, { name: "my_table" });
await viewer.load(worker);
await viewer.restore({ table: "my_table" });
</script>
load() binds the viewer to a Client, and restore() selects which of that
client’s Tables to show via the table field. Because load() alone
selects no table, it does not render — the pair guarantees exactly one atomic
render.
Passing a Table directly is still supported as a legacy shorthand,
await viewer.load(table);
… which is internally equivalent to:
await viewer.load(await table.get_client());
await viewer.restore({ table: await table.get_name() });
Table a name.
When name is omitted a random one is assigned, so the
table field in a token from save() will not match
the table after a page reload, and restore() will fail.Attributes
<perspective-viewer> reads one HTML attribute, theme, which selects the
initial theme by the --psp-theme-name a loaded stylesheet declares. Every
other setting is applied through the JavaScript API, typically restore(),
and the viewer reflects the active theme back onto the same attribute when the
user picks one:
<perspective-viewer theme="Pro Dark"></perspective-viewer>
await viewer.restore({ columns: ["Sales", "Profit"], group_by: ["Region"] });
Editor and tooling support
@perspective-dev/viewer ships a
Custom Elements Manifest
at dist/custom-elements.json, advertised by the customElements field of its
package.json. It enumerates the element’s methods, static methods, events,
the theme attribute, slots, the tab shadow part and every theme CSS custom
property, so editors, Storybook and documentation generators that read the
manifest can offer completion and reference tables without any further setup.
UI Features
The viewer provides an interactive side panel with:
- Column list - drag and drop columns to configure
group_by,split_by,sort, andfilterfields. - New Column button - opens an expression editor for creating computed columns via the expression language.
- Plugin selector - switch between the visualization plugins registered on
the page.
@perspective-dev/viewer-datagridprovidesDatagrid;@perspective-dev/viewer-chartsprovidesX Bar,Y Bar,Y Line,Y Scatter,Y Area,X/Y Scatter,X/Y Line,Density,Treemap,Sunburst,Heatmap,Candlestick,OHLC,Map Scatter,Map LineandMap Density. - Theme selector - toggle between available themes.
- Export - download the current view as CSV or Arrow.
- Copy - copy the current view to the clipboard.
- Reset - restore the viewer to its default configuration.
Methods
A <perspective-viewer> hosts one or more panels. Methods which address a
single panel take an options-dict with an optional panel id, defaulting to
the active panel — e.g. await viewer.save({ panel: "PANEL_ID_0" }).
Binding
| Method | Description |
|---|---|
load(client) | Bind a Client (or, legacy, a Table) to the viewer |
eject(options?) | Remove a Client and dispose every panel bound to it |
delete() | Release the element’s resources |
getClient(options?) | Get a bound Client |
getTable(options?) | Get a panel’s Table |
getView(options?) | Get a panel’s View — mode selects "live" (default), "clone" or "auto" |
getViewConfig(options?) | Get a panel’s ViewConfig |
View lifecycle
By default getView() returns the panel’s own live View. The viewer owns
it: every config change replaces it, and auto-pause (the element scrolled out
of view, display: none, or a backgrounded tab) or delete() deletes it. Any
call on a live View can therefore fail with “View already deleted”, even one
already in flight, and it must never be delete()d by the caller. While a
panel is auto-paused or has not rendered yet it has no live View, and
getView() rejects with No View for panel "<name>"; setAutoPause(false)
forces one to exist for every panel, at the cost of a live subscription each.
A reference that has to outlive the render lifecycle should not borrow the
viewer’s View at all. mode: "clone" builds a new View from the panel’s
effective config (the element’s global filter included) which is independent
of rendering and pause, and which the caller owns and must delete():
for (const panel of viewer.getPanelNames()) {
const view = await viewer.getView({ panel, mode: "clone" });
const arrow = await view.to_arrow();
await view.delete();
}
mode: "auto" returns the live View when one exists and a clone otherwise.
Ownership follows whichever was returned, so use it only where the caller
never deletes the result.
Configuration
| Method | Description |
|---|---|
save(options?) | Serialize one panel’s configuration |
restore(config, options?) | Apply a configuration to one panel |
saveWorkspace() | Serialize the whole element — every panel, plus layout and global filters |
restoreWorkspace(config) | Apply a workspace config update; absent fields are left unchanged |
reset(all?, options?) | Reset configuration (pass true to also reset expressions) |
resetError() | Clear the error overlay |
Panels
| Method | Description |
|---|---|
addPanel(config) | Add a panel, returning its generated id |
removePanel(id) | Remove a panel |
getPanelNames() | List panel ids |
getActivePanel() / setActivePanel(id) | Get or set the active panel |
Output
| Method | Description |
|---|---|
export(options?) | Export a panel — see the export methods below |
download(options?) | Export and download as a file |
copy(options?) | Copy a panel to the clipboard |
export(), download() and copy() all take a method, one of "csv",
"json", "ndjson", "arrow", "arrow-lz4" or "arrow-zstd" — each with
-all and -selected variants (e.g. "csv-selected", "arrow-zstd-all") —
plus "html", "json-config", and "plugin". The "arrow-lz4" and
"arrow-zstd" methods write the Arrow IPC stream with LZ4 or ZSTD body
compression.
The "plugin" method asks the plugin to render itself, which produces a PNG
for charts and text for the datagrid.
| getSelection(options?) / setSelection(...) | Get or set the selected region |
| getEditPort(options?) | Get a panel’s edit port |
| getRenderStats(options?) | Get render timing statistics |
Rendering and chrome
| Method | Description |
|---|---|
flush() | Wait for any pending UI updates to complete |
resize(options?) | Redraw, optionally at a {dimensions: {width, height}} size hint |
setAutoSize(bool) / setAutoPause(bool) / setThrottle(ms) | Render policy |
toggleConfig(force?) | Toggle the settings sidebar |
toggleColumnSettings(...) | Toggle the column settings sidebar |
resetThemes(themes?) | Re-detect or explicitly set available themes |
restyleElement() | Re-read CSS and repaint |
getPlugin(name?) / getAllPlugins() | Look up registered plugins |
The element class also has page-wide static methods:
| Method | Description |
|---|---|
registerPlugin(name) | Register a plugin custom element |
setPluginConfigDefaults(defaults, options?) / setColumnConfigDefaults(defaults, options?) | Replace plugins’ plugin_config / columns_config defaults |
getPluginConfigDefaults() / getColumnConfigDefaults() | Read the replaced defaults |
See Saving and restoring UI state for the save/restore
formats and the panel selector,
Plugin render limits for getPlugin, and
Configuration defaults for the defaults methods.