Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/md/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
- [Loading data from a virtual `Table`](./how_to/javascript/loading_virtual_data.md)
- [Saving and restoring UI state](./how_to/javascript/save_restore.md)
- [Listening for events](./how_to/javascript/events.md)
- [Plugin render limits](./how_to/javascript/events.md)
- [React Component](./how_to/javascript/react.md)
- [Python](./how_to/python.md)
- [Installation](./how_to/python/installation.md)
Expand Down
39 changes: 39 additions & 0 deletions docs/md/how_to/javascript/plugin_settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Plugin render limits

`<perspective-viewer>` plugins (especially charts) may in some cases generate
extremely large output which may lock up the browser. In order to prevent
accidents (which generally require a browser refresh to fix), each plugin has a
`max_cells` and `max_columns` heuristic which requires the user to opt-in to
fully rendering `View`s which exceed these limits. To over ride this behavior,
must set these values for each plugin type individually, _before_ calling
`HTMLPerspectiveViewerElement::restore` (with the respective `plugin` name).

If you have a `<perspective-viewer>` instance, you can set these properties via
iterating over the plugins returned by the
`HTMLPerspectiveViewerElement::getAllPlugins` method:

```javascript
const viewer = document.querySelector("perspective-viewer");
for (const plugin of await viewer.getAllPlugins()) {
if (plugin.name === "Treemap") {
// Sets all treemap `max_cells`, not just this instance!
plugin.max_cells = 1_000_000;
plugin.max_columns = 1000;
}
}
```

... Or alternatively, you can look up the Custom Element classes and set the
static variants if you know the element name (you can e.g. look this up in your
browser's DOM inspector):

```javascript
const plugin = customElements.get("perspective-viewer-d3fc-treemap");
plugin.max_cells = 1_000_000;
plugin.max_columns = 1000;
```

<div class="warning">
This distinction is just for syntax aesthetics - both methods will apply to all
instances, regardless of set via an instance, or the class itself.
</div>
1 change: 1 addition & 0 deletions examples/react-example/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const App: React.FC = () => {
<>
<PerspectiveViewer table={state.table} />
<PerspectiveViewer
className="my-perspective-viewer"
table={state.table}
config={state.config}
onClick={onClick}
Expand Down
23 changes: 22 additions & 1 deletion packages/perspective-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ export interface PerspectiveViewerProps {
onConfigUpdate?: (config: pspViewer.ViewerConfigUpdate) => void;
onClick?: (data: pspViewer.PerspectiveClickEventDetail) => void;
onSelect?: (data: pspViewer.PerspectiveSelectEventDetail) => void;

// Applicable props from `React.HTMLAttributes`, which we cannot extend
// directly because Perspective changes the signature of `onClick`.
className?: string | undefined;
hidden?: boolean | undefined;
id?: string | undefined;
slot?: string | undefined;
style?: React.CSSProperties | undefined;
tabIndex?: number | undefined;
title?: string | undefined;
}

function PerspectiveViewerImpl(props: PerspectiveViewerProps) {
Expand Down Expand Up @@ -64,7 +74,18 @@ function PerspectiveViewerImpl(props: PerspectiveViewerProps) {
usePspListener(viewer, "perspective-select", props.onSelect);
usePspListener(viewer, "perspective-config-update", props.onConfigUpdate);

return <perspective-viewer ref={setViewer} />;
return (
<perspective-viewer
ref={setViewer}
id={props.id}
className={props.className}
hidden={props.hidden}
slot={props.slot}
style={props.style}
tabIndex={props.tabIndex}
title={props.title}
/>
);
}

/**
Expand Down
35 changes: 20 additions & 15 deletions packages/perspective-viewer-d3fc/src/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,48 @@
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import type { IPerspectiveViewerPlugin } from "@finos/perspective-viewer";
import { register } from "./plugin/plugin";
register();
import { init } from "./plugin/d3fc_global_styles";

await init();

declare global {
interface CustomElementRegistry {
get(
tagName: "perspective-viewer-d3fc-area"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-xbar"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-candlestick"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-ybar"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-heatmap"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-yline"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-ohlc"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-sunburst"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-treemap"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-xyline"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-xyscatter"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;
get(
tagName: "perspective-viewer-d3fc-yscatter"
): HTMLPerspectiveViewerD3FCPluginElement;
): typeof HTMLPerspectiveViewerD3FCPluginElement;

whenDefined(tagName: "perspective-viewer-d3fc-area"): Promise<void>;
whenDefined(tagName: "perspective-viewer-d3fc-xbar"): Promise<void>;
Expand All @@ -76,5 +77,9 @@ declare global {

export class HTMLPerspectiveViewerD3FCPluginElement
extends HTMLElement
implements IPerspectiveViewerPlugin {}
implements IPerspectiveViewerPlugin
{
static get max_cells(): number;
static set max_cells(value: number);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

export const D3FC_GLOBAL_STYLES = [];

// Capture (and restore) `document.querySelector` to prevent D3FC from
// attaching styles to the document `<head>`.
export async function init() {
const old_doc = window.document.querySelector;
// @ts-ignore
window.document.querySelector = () => {
return {
appendChild(elem) {
D3FC_GLOBAL_STYLES.push(elem);
return elem;
},
};
};

const { register } = await import("./plugin");
window.document.querySelector = old_doc;
register();
}
Loading
Loading