Expand description
The JavaScript language bindings for<perspective-viewer>
Custom Element, the
main UI for Perspective.
perspective
docs for the Rust API.
§<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.
If you are using esbuild
or another bundler which supports ES6 modules, you
only need to import the perspective-viewer
libraries somewhere in your
application - these modules export nothing, but rather register the components
for use within your site’s regular HTML:
import "@finos/perspective-viewer";
import "@finos/perspective-viewer-datagrid";
import "@finos/perspective-viewer-d3fc";
Once imported, the <perspective-viewer>
Web Component will be available in any
standard HTML on your site. A simple example:
<perspective-viewer id="view1"></perspective-viewer>
or
const viewer = document.createElement("perspective-viewer");
§Theming
Theming is supported in perspective-viewer
and its accompanying plugins. A
number of themes come bundled with perspective-viewer
; you can import any of
these themes directly into your app, and the perspective-viewer
s will be
themed accordingly:
// Themes based on Thought Merchants's Prospective design
import "@finos/perspective-viewer/dist/css/pro.css";
import "@finos/perspective-viewer/dist/css/pro-dark.css";
// Other themes
import "@finos/perspective-viewer/dist/css/solarized.css";
import "@finos/perspective-viewer/dist/css/solarized-dark.css";
import "@finos/perspective-viewer/dist/css/monokai.css";
import "@finos/perspective-viewer/dist/css/vaporwave.css";
Alternatively, you may use themes.css
, which bundles all default themes
import "@finos/perspective-viewer/dist/css/themes.css";
If you choose not to bundle the themes yourself, they are available through CDN. These can be directly linked in your HTML file:
<link
rel="stylesheet"
crossorigin="anonymous"
href="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/css/pro.css"
/>
Note the crossorigin="anonymous"
attribute. When including a theme from a
cross-origin context, this attribute may be required to allow
<perspective-viewer>
to detect the theme. If this fails, additional themes are
added to the document
after <perspective-viewer>
init, or for any other
reason theme auto-detection fails, you may manually inform
<perspective-viewer>
of the available theme names with the .resetThemes()
method.
// re-auto-detect themes
viewer.resetThemes();
// Set available themes explicitly (they still must be imported as CSS!)
viewer.resetThemes(["Pro Light", "Pro Dark"]);
<perspective-viewer>
will default to the first loaded theme when initialized.
You may override this via .restore()
, or provide an initial theme by setting
the theme
attribute:
<perspective-viewer theme="Pro Light"></perspective-viewer>
or
const viewer = document.querySelector("perspective-viewer");
await viewer.restore({ theme: "Pro Dark" });
§Loading data into <perspective-viewer>
Data can be loaded into <perspective-viewer>
in the form of a Table()
or a
Promise<Table>
via the load()
method.
// Create a new worker, then a new table promise on that worker.
const worker = await perspective.worker();
const table = await worker.table(data);
// Bind a viewer element to this table.
await viewer.load(table);
§Sharing a table()
between multiple perspective-viewer
s
Multiple perspective-viewer
s can share a table()
by passing the table()
into the load()
method of each viewer. Each perspective-viewer
will update
when the underlying table()
is updated, but table.delete()
will fail until
all perspective-viewer
instances referencing it are also deleted:
const viewer1 = document.getElementById("viewer1");
const viewer2 = document.getElementById("viewer2");
// Create a new WebWorker
const worker = await perspective.worker();
// Create a table in this worker
const table = await worker.table(data);
// Load the same table in 2 different <perspective-viewer> elements
await viewer1.load(table);
await viewer2.load(table);
// Both `viewer1` and `viewer2` will reflect this update
await table.update([{ x: 5, y: "e", z: true }]);
§Server-only via WebSocketServer()
and Node.js
Loading a virtual (server-only) [Table
] works just like loading a local/Web
Worker [Table
] - just pass the virtual [Table
] to viewer.load()
:
In the browser:
const elem = document.getElementsByTagName("perspective-viewer")[0];
// Bind to the server's worker instead of instantiating a Web Worker.
const websocket = await perspective.websocket(
window.location.origin.replace("http", "ws")
);
// Bind the viewer to the preloaded data source. `table` and `view` objects
// live on the server.
const server_table = await websocket.open_table("table_one");
await elem.load(server_table);
// Or load data from a table using a view. The browser now also has a copy of
// this view in its own `table`, as well as its updates transferred to the
// browser using Apache Arrow.
const worker = await perspective.worker();
const server_view = await server_table.view();
const client_table = worker.table(server_view);
await elem.load(client_table);
<perspective-viewer>
instances bound in this way are otherwise no different
than <perspective-viewer>
s which rely on a Web Worker, and can even share a
host application with Web Worker-bound table()
s. The same promise
-based API
is used to communicate with the server-instantiated view()
, only in this case
it is over a websocket.
§Persistent <perspective-viewer>
configuration via save()
/restore()
.
<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 aload()
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());
§Update events
Whenever a <perspective-viewer>
s underlying table()
is changed via the
load()
or update()
methods, a perspective-view-update
DOM event is fired.
Similarly, view()
updates instigated either through the Attribute API or
through user interaction will fire a perspective-config-update
event:
elem.addEventListener("perspective-config-update", function (event) {
var config = elem.save();
console.log("The view() config has changed to " + JSON.stringify(config));
});
§Click events
Whenever a <perspective-viewer>
’s grid or chart is clicked, a
perspective-click
DOM event is fired containing a detail object with config
,
column_names
, and row
.
The config
object contains an array of filters
that can be applied to a
<perspective-viewer>
through the use of restore()
updating it to show the
filtered subset of data.
The column_names
property contains an array of matching columns, and the row
property returns the associated row data.
elem.addEventListener("perspective-click", function (event) {
var config = event.detail.config;
elem.restore(config);
});
Modules§
components
contains all YewComponent
types, but only exports the 4 necessary for public Custom Elements. The rest are internal components of these 4.- A collection of (de-)serializable structs which capture the application state, suitable for persistence, history, etc. features.
- A catch all for project-wide macros and general-purpose functions that are not directly related to Perspective.
Macros§
- A macro for implementing the
wasm_bindgen
boilerplate for types which implementserde::{Serialize, Deserialize}
. - A macro which set a property called
weak_link
on the containerProperties
whencfg(test)
, such that unit tests may send messages to a component. - A macro which derives a
yew::Component
for an arbitrary HTML snippet and mounts it, for testing.
Functions§
- Register Web Components with the global registry, given a Perspective module.
- Export all ExprTK commands, for use in generating documentation. Register this crate’s Custom Elements in the browser’s current session.
- Register a plugin globally.