The `<perspective-viewer>` Custom Element, frontend for Perspective.js, providing interactive analytics and data visualization.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Complete configuration interface for managing viewer state, including view settings, plugin configuration, and column styling.
The main configuration interface that encompasses all viewer settings.
/**
* Complete viewer configuration including plugin, theme, and view settings
*/
interface ViewerConfigUpdate {
/** Configuration version for compatibility */
version?: string | null;
/** Active plugin name */
plugin?: string | null;
/** Viewer title */
title?: string | null;
/** Active theme name */
theme?: string | null;
/** Whether settings panel is open */
settings?: boolean | null;
/** Plugin-specific configuration */
plugin_config?: any | null;
/** Column styling and formatting configuration */
columns_config?: Record<string, ColumnConfigValues> | null;
// ViewConfig properties (flattened from core Perspective)
/** Columns to group by */
group_by?: Array<string> | null;
/** Columns to split by */
split_by?: Array<string> | null;
/** Visible columns (null = show all) */
columns?: Array<string | null> | null;
/** Applied filters */
filter?: Array<Filter> | null;
/** Sort configuration */
sort?: Array<Sort> | null;
/** Custom expression columns */
expressions?: Record<string, string> | null;
/** Aggregation functions by column */
aggregates?: Record<string, Aggregate> | null;
/** Group by depth limit */
group_by_depth?: number | null;
/** Filter combination operator */
filter_op?: FilterReducer | null;
}Configuration for individual column styling and formatting.
/**
* Column-specific styling and configuration values
*/
interface ColumnConfigValues {
/** Symbol mappings for categorical data visualization */
symbols?: Record<string, string>;
/** Number column styling configuration */
datagrid_number_style?: NumberColumnStyleConfig;
/** String column styling configuration */
datagrid_string_style?: StringColumnStyleConfig;
/** Datetime column styling configuration */
datagrid_datetime_style?: DatetimeColumnStyleConfig;
/** Custom number formatting */
number_format?: CustomNumberFormatConfig | null;
/** Aggregation depth for hierarchical data */
aggregate_depth?: number;
}
interface NumberColumnStyleConfig {
color?: string;
gradient?: number;
pos_color?: string;
neg_color?: string;
format?: string;
}
interface StringColumnStyleConfig {
color?: string;
format?: string;
}
interface DatetimeColumnStyleConfig {
color?: string;
format?: string;
datetime_format?: string;
}
interface CustomNumberFormatConfig {
style?: "decimal" | "currency" | "percent";
currency?: string;
minimumFractionDigits?: number;
maximumFractionDigits?: number;
}Define data filtering rules and operators.
/**
* Filter definition as [column, operator, value]
*/
type Filter = [string, string, FilterTerm];
/**
* Filter value - can be single value or array of values
*/
type FilterTerm = Array<Scalar> | Scalar;
/**
* Basic data types supported in filters
*/
type Scalar = number | string | boolean | null;
/**
* Filter combination operator
*/
type FilterReducer = "and" | "or";Define sorting rules for data columns.
/**
* Sort configuration as [column, direction]
*/
type Sort = [string, "asc" | "desc"];Define aggregation functions for grouped data.
/**
* Aggregation function types
*/
type Aggregate =
| "sum"
| "mean"
| "count"
| "distinct count"
| "min"
| "max"
| "median"
| "first"
| "last"
| "std"
| "var";import "@finos/perspective-viewer";
const viewer = document.createElement("perspective-viewer");
// Configure basic view settings
await viewer.restore({
plugin: "d3_y_bar",
columns: ["sales", "profit"],
group_by: ["region"],
sort: [["sales", "desc"]],
theme: "Pro Dark"
});// Complex configuration with filtering and multiple grouping levels
await viewer.restore({
plugin: "d3_treemap",
group_by: ["category", "subcategory"],
columns: ["sales"],
filter: [
["date", ">=", "2023-01-01"],
["region", "in", ["North", "South", "East"]],
["sales", ">", 1000]
],
filter_op: "and",
sort: [["sales", "desc"]],
group_by_depth: 2
});// Configure column-specific styling
await viewer.restore({
plugin: "datagrid",
columns: ["product", "sales", "profit", "date"],
columns_config: {
sales: {
datagrid_number_style: {
color: "#1f77b4",
format: "currency",
pos_color: "#2ca02c",
neg_color: "#d62728"
},
number_format: {
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}
},
profit: {
datagrid_number_style: {
gradient: 1,
pos_color: "#2ca02c",
neg_color: "#d62728"
}
},
date: {
datagrid_datetime_style: {
format: "YYYY-MM-DD",
color: "#666666"
}
}
}
});// Add computed columns with expressions
await viewer.restore({
plugin: "d3_xy_scatter",
columns: ["sales", "profit", "profit_margin"],
expressions: {
"profit_margin": '"profit" / "sales" * 100',
"total_value": '"quantity" * "unit_price"',
"growth_rate": '("current_sales" - "previous_sales") / "previous_sales" * 100'
},
group_by: ["region"]
});// Configuration with plugin-specific settings
await viewer.restore({
plugin: "d3_candlestick",
columns: ["open", "high", "low", "close"],
group_by: ["date"],
plugin_config: {
// Plugin-specific configuration
colorScheme: "viridis",
showVolume: true,
candleWidth: 0.8,
showMovingAverage: true,
movingAveragePeriod: 20
}
});// Configure theme and UI state
await viewer.restore({
theme: "Material Dark",
settings: true, // Show settings panel
title: "Sales Dashboard",
plugin: "d3_y_line",
columns: ["date", "sales"],
group_by: ["date"]
});// Save current configuration
const config = await viewer.save("json");
// Save as different formats
const configString = await viewer.save("string");
const configBuffer = await viewer.save("arraybuffer");
// Store configuration
localStorage.setItem("viewerConfig", JSON.stringify(config));// Restore from saved configuration
const savedConfig = JSON.parse(localStorage.getItem("viewerConfig"));
await viewer.restore(savedConfig);
// Partial configuration updates
await viewer.restore({
plugin: "d3_y_bar", // Only change the plugin
theme: "Pro Light" // And theme
});// Validate configuration before applying
function validateConfig(config: ViewerConfigUpdate): boolean {
// Check required fields
if (config.plugin && typeof config.plugin !== 'string') {
return false;
}
// Validate filter format
if (config.filter) {
for (const filter of config.filter) {
if (!Array.isArray(filter) || filter.length !== 3) {
return false;
}
}
}
// Validate sort format
if (config.sort) {
for (const sort of config.sort) {
if (!Array.isArray(sort) || sort.length !== 2) {
return false;
}
if (!["asc", "desc"].includes(sort[1])) {
return false;
}
}
}
return true;
}
// Use validation before restore
if (validateConfig(userConfig)) {
await viewer.restore(userConfig);
} else {
console.error("Invalid configuration");
}// Listen for configuration changes
viewer.addEventListener("perspective-config-update", (event) => {
const config: ViewerConfigUpdate = event.detail;
console.log("Configuration updated:", config);
// Save configuration on changes
localStorage.setItem("autoSaveConfig", JSON.stringify(config));
});
// Apply configuration updates dynamically
async function updateVisualization(newSettings: Partial<ViewerConfigUpdate>) {
const currentConfig = await viewer.save();
const updatedConfig = { ...currentConfig, ...newSettings };
await viewer.restore(updatedConfig);
}
// Example: Switch to different view
await updateVisualization({
plugin: "d3_heatmap",
group_by: ["row_category"],
split_by: ["col_category"],
columns: ["value"]
});// Reset to defaults
await viewer.reset();
// Reset including expressions and column settings
await viewer.reset(true);
// Reset specific aspects
await viewer.restore({
plugin: undefined, // Reset to default plugin
group_by: [], // Clear grouping
filter: [], // Clear filters
sort: [] // Clear sorting
});