Table sharing and coordination system for managing perspective Tables across multiple viewers within the workspace.
Core functionality for adding, retrieving, and managing perspective Tables.
/**
* Table management operations available on both custom element and workspace
*/
interface TableManager {
/** Add a table by name for sharing across multiple viewers */
addTable(name: string, table: Promise<psp.Table>): Promise<void>;
/** Retrieve table by name */
getTable(name: string): psp.Table | Promise<psp.Table>;
/** Replace an existing table with a new one */
replaceTable(name: string, table: Promise<psp.Table>): Promise<void>;
/** Remove table by name from the workspace */
removeTable(name: string): boolean;
/** Observable map of all tables in the workspace */
readonly tables: ObservableMap<string, psp.Table | Promise<psp.Table>>;
}Usage Examples:
import { HTMLPerspectiveWorkspaceElement } from "@finos/perspective-workspace";
import * as perspective from "@finos/perspective";
const workspace = document.createElement("perspective-workspace") as HTMLPerspectiveWorkspaceElement;
// Add tables from different data sources
const salesData = await perspective.table([
{ product: "Widget", sales: 100, region: "North" },
{ product: "Gadget", sales: 200, region: "South" }
]);
const userStats = await perspective.table([
{ user: "Alice", sessions: 45, country: "US" },
{ user: "Bob", sessions: 32, country: "UK" }
]);
// Add tables to workspace
await workspace.addTable("sales", Promise.resolve(salesData));
await workspace.addTable("users", Promise.resolve(userStats));
// Retrieve and use tables
const sales = workspace.getTable("sales");
if (sales) {
console.log("Sales table available");
}
// Replace a table with updated data
const updatedSales = await perspective.table([
{ product: "Widget", sales: 150, region: "North" },
{ product: "Gadget", sales: 250, region: "South" },
{ product: "Tool", sales: 75, region: "East" }
]);
await workspace.replaceTable("sales", Promise.resolve(updatedSales));
// Remove table when no longer needed
const removed = workspace.removeTable("sales");
console.log("Table removed:", removed);Enhanced Map implementation that provides notifications when tables are added or removed.
/**
* Observable Map class extending native Map with listener support
* Provides notifications when tables are set or deleted
*/
class ObservableMap<K, V> extends Map<K, V> {
/** Set value with listener notification */
set(name: K, item: V): this;
/** Get value by key */
get(name: K): V | undefined;
/** Delete value with listener notification */
delete(name: K): boolean;
/** Add listener for set operations */
addSetListener(listener: (name: K, val: V) => void): void;
/** Add listener for delete operations */
addDeleteListener(listener: (name: K) => void): void;
}Usage Examples:
import { ObservableMap } from "@finos/perspective-workspace";
const tableMap = new ObservableMap<string, psp.Table>();
// Listen for table additions
tableMap.addSetListener((name, table) => {
console.log(`Table "${name}" added to workspace`);
});
// Listen for table removals
tableMap.addDeleteListener((name) => {
console.log(`Table "${name}" removed from workspace`);
});
// These operations will trigger listeners
tableMap.set("myTable", table);
tableMap.delete("myTable");Tables added to the workspace can be referenced by name in viewer configurations, enabling multiple viewers to share the same data source efficiently.
Usage Examples:
// Add a shared table
workspace.addTable("stockPrices", stockTable);
// Multiple viewers can reference the same table
workspace.addViewer({
table: "stockPrices",
columns: ["symbol", "price"],
group_by: ["sector"]
});
workspace.addViewer({
table: "stockPrices", // Same table, different view
plugin: "d3_candlestick",
columns: ["open", "high", "low", "close"]
});
workspace.addViewer({
table: "stockPrices", // Same table, aggregated view
plugin: "d3_bar",
columns: ["price"],
group_by: ["sector"],
aggregates: { price: "avg" }
});The system supports both synchronous and asynchronous table loading patterns.
Usage Examples:
// Asynchronous table loading
const loadDataAsync = async () => {
// Table loads in background while workspace is being set up
workspace.addTable("asyncData",
fetch("/api/data")
.then(response => response.json())
.then(data => perspective.table(data))
);
// Viewer can be added immediately, will connect when table loads
workspace.addViewer({
table: "asyncData",
columns: ["name", "value"]
});
};
// Synchronous table loading
const loadDataSync = async () => {
const data = await fetch("/api/data").then(r => r.json());
const table = await perspective.table(data);
workspace.addTable("syncData", Promise.resolve(table));
workspace.addViewer({
table: "syncData",
columns: ["name", "value"]
});
};