Improves lazy loading.
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDom from "react-dom";
|
||||
import { Visualization, Theme } from "./index";
|
||||
import { Visualizer, VisualizationId, asVisualizationId } from "./Visualizer";
|
||||
import {
|
||||
Visualizer,
|
||||
VisualizationId,
|
||||
asVisualizationId,
|
||||
VisualizationRenderOptions,
|
||||
} from "./Visualizer";
|
||||
|
||||
interface Options {
|
||||
id?: string;
|
||||
@@ -27,30 +32,91 @@ export abstract class BaseReactVisualization implements Visualization<unknown> {
|
||||
|
||||
public render(
|
||||
target: HTMLDivElement,
|
||||
theme: Theme,
|
||||
previous: unknown | undefined
|
||||
): unknown {
|
||||
const node = this.getReactNode(theme);
|
||||
options: VisualizationRenderOptions<unknown>
|
||||
): { renderState: unknown } {
|
||||
const node = this.getReactNode({
|
||||
theme: options.theme,
|
||||
readyCallback: options.readyCallback,
|
||||
});
|
||||
// We could use this to get access to theme vars:
|
||||
// getComputedStyle(target).getPropertyValue("--background-color")
|
||||
//getComputedStyle(target).getPropertyValue("--background-color")
|
||||
|
||||
ReactDom.render(<>{node}</>, target);
|
||||
return undefined;
|
||||
return { renderState: undefined };
|
||||
}
|
||||
|
||||
protected abstract getReactNode(theme: Theme): React.ReactChild;
|
||||
public abstract preload(): Promise<void>;
|
||||
protected abstract getReactNode(
|
||||
options: ReactVisualizationRenderOptions
|
||||
): React.ReactChild;
|
||||
}
|
||||
|
||||
export class ReactVisualization extends BaseReactVisualization {
|
||||
export interface ReactVisualizationRenderOptions {
|
||||
theme: Theme;
|
||||
readyCallback: () => void;
|
||||
}
|
||||
|
||||
class ReactVisualization extends BaseReactVisualization {
|
||||
private readonly _preload?: () => Promise<void>;
|
||||
|
||||
constructor(
|
||||
sourceVisualizer: Visualizer,
|
||||
options: Options,
|
||||
private readonly renderReactNode: (theme: Theme) => React.ReactChild
|
||||
options: Options & { preload?: () => Promise<void> },
|
||||
private readonly renderReactNode: (
|
||||
options: ReactVisualizationRenderOptions
|
||||
) => React.ReactChild
|
||||
) {
|
||||
super(sourceVisualizer, options);
|
||||
this._preload = options.preload;
|
||||
}
|
||||
|
||||
protected getReactNode(theme: Theme): React.ReactChild {
|
||||
return this.renderReactNode(theme);
|
||||
protected getReactNode(
|
||||
options: ReactVisualizationRenderOptions
|
||||
): React.ReactChild {
|
||||
return this.renderReactNode(options);
|
||||
}
|
||||
|
||||
public async preload(): Promise<void> {
|
||||
if (this._preload) {
|
||||
return await this._preload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createReactVisualization(
|
||||
sourceVisualizer: Visualizer,
|
||||
options: Options & { preload?: () => Promise<void> },
|
||||
renderReactNode: (options: { theme: Theme }) => React.ReactChild
|
||||
) {
|
||||
return new ReactVisualization(sourceVisualizer, options, options => (
|
||||
<ComponentWithOnMount
|
||||
onDidMount={options.readyCallback}
|
||||
child={renderReactNode(options)}
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
||||
class ComponentWithOnMount extends React.Component<{
|
||||
child: React.ReactChild;
|
||||
onDidMount: () => void;
|
||||
}> {
|
||||
componentDidMount() {
|
||||
this.props.onDidMount();
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.child;
|
||||
}
|
||||
}
|
||||
|
||||
export function createLazyReactVisualization(
|
||||
sourceVisualizer: Visualizer,
|
||||
options: Options & { preload?: () => Promise<void> },
|
||||
renderReactNode: (
|
||||
options: ReactVisualizationRenderOptions
|
||||
) => React.ReactChild
|
||||
) {
|
||||
return new ReactVisualization(sourceVisualizer, options, options =>
|
||||
renderReactNode(options)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,22 @@ export class Theme {
|
||||
public static readonly light = new Theme("light", "light");
|
||||
public static readonly dark = new Theme("dark", "dark");
|
||||
|
||||
private readonly divElement = document.createElement("div");
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
public readonly kind: "light" | "dark"
|
||||
) {}
|
||||
) {
|
||||
this.divElement.classList.add(
|
||||
"themeable",
|
||||
`theme-${this.id}`,
|
||||
"visualization"
|
||||
);
|
||||
this.divElement.style.display = "none";
|
||||
document.body.append(this.divElement);
|
||||
}
|
||||
|
||||
public resolveVarToColor(varName: string): string {
|
||||
return getComputedStyle(this.divElement).getPropertyValue(varName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Theme } from "./Theme";
|
||||
export class VisualizationView extends React.Component<{
|
||||
visualization: Visualization;
|
||||
theme: Theme;
|
||||
onReady?: () => void;
|
||||
}> {
|
||||
private readonly ref = React.createRef<HTMLDivElement>();
|
||||
private visualizationRenderState: unknown = undefined;
|
||||
@@ -19,11 +20,18 @@ export class VisualizationView extends React.Component<{
|
||||
|
||||
renderVisualization() {
|
||||
const { visualization, theme } = this.props;
|
||||
this.visualizationRenderState = visualization.render(
|
||||
this.ref.current!,
|
||||
const { renderState } = visualization.render(this.ref.current!, {
|
||||
theme,
|
||||
this.visualizationRenderState
|
||||
);
|
||||
previousRenderState: this.visualizationRenderState,
|
||||
readyCallback: () => {
|
||||
const r = this.props.onReady;
|
||||
if (r) {
|
||||
r();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.visualizationRenderState = renderState;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -23,6 +23,12 @@ export function asVisualizationId(id: string): VisualizationId {
|
||||
return (id as unknown) as VisualizationId;
|
||||
}
|
||||
|
||||
export interface VisualizationRenderOptions<TRenderState> {
|
||||
theme: Theme;
|
||||
previousRenderState: TRenderState | undefined;
|
||||
readyCallback: () => void;
|
||||
}
|
||||
|
||||
export interface Visualization<TRenderState = any> {
|
||||
readonly id: VisualizationId;
|
||||
readonly name: string;
|
||||
@@ -31,7 +37,11 @@ export interface Visualization<TRenderState = any> {
|
||||
|
||||
render(
|
||||
target: HTMLDivElement,
|
||||
theme: Theme,
|
||||
previousRenderState: TRenderState | undefined
|
||||
): TRenderState;
|
||||
options: VisualizationRenderOptions<TRenderState>
|
||||
): { renderState: TRenderState };
|
||||
|
||||
/**
|
||||
* Preloads resources to speed up first rendering.
|
||||
*/
|
||||
preload(): Promise<void>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user