Improves lazy loading.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hediet/visualization-bundle",
|
||||
"description": "Bundles several visualizers",
|
||||
"version": "0.1.8",
|
||||
"version": "0.1.9",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "tsc --watch",
|
||||
@@ -24,7 +24,7 @@
|
||||
"@finos/perspective-viewer-d3fc": "^0.5.2",
|
||||
"@finos/perspective-viewer-datagrid": "^0.5.2",
|
||||
"@hediet/monaco-editor-react": "^0.1.1",
|
||||
"@hediet/semantic-json": "^0.3.14",
|
||||
"@hediet/semantic-json": "^0.3.15",
|
||||
"@hediet/std": "^0.6.0",
|
||||
"classnames": "^2.2.6",
|
||||
"line-column": "^1.0.2",
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
import * as React from "react";
|
||||
import { observable, runInAction } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { Loadable } from "./Loadable";
|
||||
|
||||
export function makeLazyLoadable<TProps>(
|
||||
selector: () => Promise<React.ComponentClass<TProps>>
|
||||
): React.ComponentClass<TProps> {
|
||||
): React.ComponentClass<TProps> & { preload(): Promise<void> } {
|
||||
const loader = new Loadable(selector);
|
||||
|
||||
@observer
|
||||
class MyComponent extends React.Component<TProps> {
|
||||
@observable
|
||||
component: React.ComponentClass<TProps> | undefined;
|
||||
|
||||
async componentDidMount() {
|
||||
const result = await selector();
|
||||
runInAction("Set Lazily Loaded Component", () => {
|
||||
this.component = result;
|
||||
});
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
loader.load();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.component) {
|
||||
if (!loader.result) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
const C = this.component;
|
||||
const C = loader.result;
|
||||
return <C {...this.props} />;
|
||||
}
|
||||
|
||||
static async preload(): Promise<void> {
|
||||
await loader.load();
|
||||
}
|
||||
}
|
||||
|
||||
return MyComponent;
|
||||
|
||||
22
visualization-bundle/src/utils/Loadable.tsx
Normal file
22
visualization-bundle/src/utils/Loadable.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { observable, runInAction } from "mobx";
|
||||
|
||||
export class Loadable<T> {
|
||||
@observable.ref
|
||||
public result: T | undefined;
|
||||
|
||||
private operation?: Promise<void> = undefined;
|
||||
|
||||
constructor(private readonly _load: () => Promise<T>) {}
|
||||
|
||||
public load(): Promise<void> {
|
||||
if (!this.operation) {
|
||||
this.operation = (async () => {
|
||||
const r = await this._load();
|
||||
runInAction(() => {
|
||||
this.result = r;
|
||||
});
|
||||
})();
|
||||
}
|
||||
return this.operation;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import * as React from "react";
|
||||
import { observer, disposeOnUnmount } from "mobx-react";
|
||||
import { observable, autorun, trace, computed } from "mobx";
|
||||
import * as monacoTypes from "monaco-editor";
|
||||
import { getLanguageId } from "../monaco-text-visualizer/MonacoEditor";
|
||||
import { getLanguageId } from "../monaco-text-visualizer/getLanguageId";
|
||||
import {
|
||||
TreeWithPathView,
|
||||
TreeViewModel,
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
import { visualizationNs } from "../../consts";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { createTreeViewModelFromTreeNodeData } from "../tree-visualizer";
|
||||
import { AstTree, NodeInfo } from "./AstVisualizer";
|
||||
@@ -81,7 +81,7 @@ export const astVisualizer = createVisualizer({
|
||||
name: "AST",
|
||||
serializer: sAstTree,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1500 }, theme => {
|
||||
createReactVisualization(self, { priority: 1500 }, ({ theme }) => {
|
||||
const m = createTreeViewModelFromTreeNodeData(
|
||||
data.root,
|
||||
node => node.span
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { observer, disposeOnUnmount } from "mobx-react";
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { observable, autorun, runInAction } from "mobx";
|
||||
import { SvgViewer } from "../../svg-visualizer/SvgViewer";
|
||||
import { Loadable } from "../../../utils/Loadable";
|
||||
|
||||
class VisLoader {
|
||||
private result: any | undefined;
|
||||
@@ -24,26 +24,29 @@ class VisLoader {
|
||||
|
||||
const vizLoader = new VisLoader();
|
||||
|
||||
export function getSvgFromDotCode(dotCode: string): Loadable<string> {
|
||||
return new Loadable(async () => {
|
||||
const viz = await vizLoader.getViz();
|
||||
return await viz.renderString(dotCode);
|
||||
});
|
||||
}
|
||||
|
||||
@observer
|
||||
export class GraphvizDotViewer extends React.Component<{
|
||||
dotCode: string;
|
||||
svgSource: Loadable<string>;
|
||||
svgRef?: (element: SVGSVGElement | null) => void;
|
||||
}> {
|
||||
@observable private svg: string | null = null;
|
||||
|
||||
@disposeOnUnmount
|
||||
// @ts-ignore
|
||||
private readonly _updateSvgAutorun = autorun(async () => {
|
||||
const dotCode = this.props.dotCode; // to trigger mobx dependency
|
||||
const viz = await vizLoader.getViz();
|
||||
const svg = await viz.renderString(dotCode);
|
||||
runInAction("Update svg", () => (this.svg = svg));
|
||||
});
|
||||
|
||||
render() {
|
||||
if (!this.svg) {
|
||||
const { svgSource } = this.props;
|
||||
svgSource.load();
|
||||
if (!svgSource.result) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
return <SvgViewer svgRef={this.props.svgRef} svgContent={this.svg} />;
|
||||
return (
|
||||
<SvgViewer
|
||||
svgRef={this.props.svgRef}
|
||||
svgContent={svgSource.result}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { sOpenObject, sLiteral, sString } from "@hediet/semantic-json";
|
||||
import { GraphvizDotViewer } from "./GraphvizDotVisualizer";
|
||||
import { getSvgFromDotCode, GraphvizDotViewer } from "./GraphvizDotVisualizer";
|
||||
import {
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createVisualizer,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../../consts";
|
||||
|
||||
@@ -17,10 +17,17 @@ export const graphvizDotVisualizer = createVisualizer({
|
||||
}),
|
||||
text: sString(),
|
||||
}).defineAs(visualizationNs("GraphvizDotVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1500 }, () => (
|
||||
<GraphvizDotViewer dotCode={data.text} />
|
||||
)),
|
||||
getVisualization: (data, self) => {
|
||||
const svgSource = getSvgFromDotCode(data.text);
|
||||
return createReactVisualization(
|
||||
self,
|
||||
{
|
||||
priority: 1500,
|
||||
preload: () => svgSource.load(),
|
||||
},
|
||||
() => <GraphvizDotViewer svgSource={svgSource} />
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(graphvizDotVisualizer);
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { GraphvizDotViewer } from "../dot-graphviz-visualizer/GraphvizDotVisualizer";
|
||||
|
||||
@observer
|
||||
export class GraphvizGraphViewer extends React.Component<{
|
||||
nodes: { id: string; label?: string }[];
|
||||
edges: { from: string; to: string; label?: string; style: string }[];
|
||||
}> {
|
||||
render() {
|
||||
const { nodes, edges } = this.props;
|
||||
const dotContent = `
|
||||
digraph MyGraph {
|
||||
${nodes
|
||||
.map(
|
||||
n =>
|
||||
`"${n.id}" [ label = ${JSON.stringify(
|
||||
n.label !== undefined ? n.label : n.id
|
||||
)} ];`
|
||||
)
|
||||
.join("\n ")}
|
||||
${edges
|
||||
.map(
|
||||
e =>
|
||||
`"${e.from}" -> "${
|
||||
e.to
|
||||
}" [ label = ${JSON.stringify(
|
||||
e.label !== undefined ? e.label : ""
|
||||
)} style = ${JSON.stringify(e.style || "")} ];`
|
||||
)
|
||||
.join("\n")}
|
||||
}
|
||||
`;
|
||||
return <GraphvizDotViewer dotCode={dotContent} />;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Loadable } from "../../../utils/Loadable";
|
||||
import { getSvgFromDotCode } from "../dot-graphviz-visualizer/GraphvizDotVisualizer";
|
||||
|
||||
export function getSvgFromGraphData(
|
||||
nodes: { id: string; label?: string }[],
|
||||
edges: {
|
||||
from: string;
|
||||
to: string;
|
||||
label?: string;
|
||||
style?: string;
|
||||
}[]
|
||||
): Loadable<string> {
|
||||
const dotContent = `
|
||||
digraph MyGraph {
|
||||
${nodes
|
||||
.map(
|
||||
n =>
|
||||
`"${n.id}" [ label = ${JSON.stringify(
|
||||
n.label !== undefined ? n.label : n.id
|
||||
)} ];`
|
||||
)
|
||||
.join("\n ")}
|
||||
${edges
|
||||
.map(
|
||||
e =>
|
||||
`"${e.from}" -> "${e.to}" [ label = ${JSON.stringify(
|
||||
e.label !== undefined ? e.label : ""
|
||||
)} style = ${JSON.stringify(e.style || "")} ];`
|
||||
)
|
||||
.join("\n")}
|
||||
}
|
||||
`;
|
||||
return getSvgFromDotCode(dotContent);
|
||||
}
|
||||
@@ -1,20 +1,25 @@
|
||||
import * as React from "react";
|
||||
import { GraphvizGraphViewer } from "./GraphvizGraphVisualizer";
|
||||
import { sGraph } from "../sGraph";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { GraphvizDotViewer } from "../dot-graphviz-visualizer/GraphvizDotVisualizer";
|
||||
import { getSvgFromGraphData } from "./getGraphVizData";
|
||||
|
||||
export const graphvizGraphVisualizer = createVisualizer({
|
||||
id: "graphviz-graph",
|
||||
name: "Graphviz",
|
||||
serializer: sGraph,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, () => (
|
||||
<GraphvizGraphViewer edges={data.edges} nodes={data.nodes} />
|
||||
)),
|
||||
getVisualization: (data, self) => {
|
||||
const svgSource = getSvgFromGraphData(data.nodes, data.edges);
|
||||
return createReactVisualization(
|
||||
self,
|
||||
{ priority: 1000, preload: () => svgSource.load() },
|
||||
() => <GraphvizDotViewer svgSource={svgSource} />
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(graphvizGraphVisualizer);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from "react";
|
||||
import { makeLazyLoadable } from "../../../utils/LazyLoadable";
|
||||
import {
|
||||
createReactVisualization,
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { sGraph } from "../sGraph";
|
||||
@@ -16,12 +16,19 @@ export const visJsGraphVisualizer = createVisualizer({
|
||||
name: "vis.js",
|
||||
serializer: sGraph,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1500 }, () => (
|
||||
<VisJsGraphViewerLazyLoadable
|
||||
edges={data.edges}
|
||||
nodes={data.nodes}
|
||||
/>
|
||||
)),
|
||||
createReactVisualization(
|
||||
self,
|
||||
{
|
||||
priority: 1500,
|
||||
preload: VisJsGraphViewerLazyLoadable.preload,
|
||||
},
|
||||
() => (
|
||||
<VisJsGraphViewerLazyLoadable
|
||||
edges={data.edges}
|
||||
nodes={data.nodes}
|
||||
/>
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(visJsGraphVisualizer);
|
||||
|
||||
@@ -4,15 +4,14 @@ import {
|
||||
sLiteral,
|
||||
sString,
|
||||
sArrayOf,
|
||||
sObject,
|
||||
sOptionalProp,
|
||||
sNumber,
|
||||
} from "@hediet/semantic-json";
|
||||
import { DecoratedGridComponent } from "./GridVisualizer";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
@@ -65,7 +64,7 @@ export const gridVisualizer = createVisualizer({
|
||||
name: "Grid",
|
||||
serializer: sGrid,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, () => (
|
||||
createReactVisualization(self, { priority: 1000 }, () => (
|
||||
<DecoratedGridComponent data={data} />
|
||||
)),
|
||||
});
|
||||
|
||||
@@ -2,8 +2,8 @@ import { sOpenObject, sLiteral, sString, sProp } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { SvgViewer } from "../svg-visualizer/SvgViewer";
|
||||
import { Observer, observer, disposeOnUnmount } from "mobx-react";
|
||||
@@ -22,7 +22,7 @@ export const imageVisualizer = createVisualizer({
|
||||
}),
|
||||
}).defineAs(visualizationNs("ImageVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, () => {
|
||||
createReactVisualization(self, { priority: 1000 }, () => {
|
||||
return <ImageViewer base64Data={data.base64Data} />;
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -33,10 +33,10 @@ export function getLanguageId(fileName: string): string {
|
||||
}
|
||||
|
||||
@observer
|
||||
export class MonacoEditor extends React.Component<{
|
||||
export class MonacoDiffEditor extends React.Component<{
|
||||
originalText: string;
|
||||
modifiedText: string;
|
||||
languageId: string;
|
||||
fileName?: string;
|
||||
theme: Theme;
|
||||
}> {
|
||||
@observable private editor:
|
||||
@@ -49,6 +49,13 @@ export class MonacoEditor extends React.Component<{
|
||||
}
|
||||
}
|
||||
|
||||
get languageId(): string {
|
||||
if (!this.props.fileName) {
|
||||
return "text";
|
||||
}
|
||||
return getLanguageId(this.props.fileName);
|
||||
}
|
||||
|
||||
private originalModel:
|
||||
| monacoTypes.editor.ITextModel
|
||||
| undefined = undefined;
|
||||
@@ -61,12 +68,12 @@ export class MonacoEditor extends React.Component<{
|
||||
if (this.editor) {
|
||||
const originalModel = getLoadedMonaco().editor.createModel(
|
||||
this.props.originalText,
|
||||
this.props.languageId,
|
||||
this.languageId,
|
||||
undefined
|
||||
);
|
||||
const modifiedModel = getLoadedMonaco().editor.createModel(
|
||||
this.props.modifiedText,
|
||||
this.props.languageId,
|
||||
this.languageId,
|
||||
undefined
|
||||
);
|
||||
|
||||
|
||||
@@ -7,15 +7,16 @@ import {
|
||||
} from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
getLanguageId,
|
||||
MonacoEditor as MonacoDiffEditor,
|
||||
} from "./MonacoEditor";
|
||||
import {
|
||||
createReactVisualization,
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
import { makeLazyLoadable } from "../../utils/LazyLoadable";
|
||||
|
||||
const MonacoDiffEditorLazyLoadable = makeLazyLoadable(
|
||||
async () => (await import("./MonacoEditor")).MonacoDiffEditor
|
||||
);
|
||||
|
||||
export const monacoTextDiffVisualizer = createVisualizer({
|
||||
id: "monaco-text-diff",
|
||||
@@ -34,20 +35,18 @@ export const monacoTextDiffVisualizer = createVisualizer({
|
||||
}),
|
||||
}).defineAs(visualizationNs("MonacoTextDiffVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 900 }, theme => {
|
||||
let id = "text";
|
||||
if (data.fileName) {
|
||||
id = getLanguageId(data.fileName);
|
||||
}
|
||||
return (
|
||||
<MonacoDiffEditor
|
||||
createReactVisualization(
|
||||
self,
|
||||
{ priority: 900, preload: MonacoDiffEditorLazyLoadable.preload },
|
||||
({ theme }) => (
|
||||
<MonacoDiffEditorLazyLoadable
|
||||
originalText={data.otherText}
|
||||
modifiedText={data.text}
|
||||
languageId={id}
|
||||
fileName={data.fileName}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
}),
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(monacoTextDiffVisualizer);
|
||||
|
||||
@@ -4,39 +4,13 @@ import { observable, autorun } from "mobx";
|
||||
import * as monacoTypes from "monaco-editor";
|
||||
import { Theme } from "@hediet/visualization-core";
|
||||
import { getLoadedMonaco } from "@hediet/monaco-editor-react";
|
||||
|
||||
export function getLanguageId(fileName: string): string {
|
||||
const l = getLoadedMonaco().languages.getLanguages();
|
||||
const result = l.find(l => {
|
||||
if (l.filenamePatterns) {
|
||||
for (const p of l.filenamePatterns) {
|
||||
if (new RegExp(p).test(fileName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (l.extensions) {
|
||||
for (const p of l.extensions) {
|
||||
if (fileName.endsWith(p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (result) {
|
||||
return result.id;
|
||||
}
|
||||
return "text";
|
||||
}
|
||||
import { getLanguageId } from "./getLanguageId";
|
||||
|
||||
@observer
|
||||
export class MonacoEditor extends React.Component<{
|
||||
text: string;
|
||||
languageId: string;
|
||||
theme: Theme;
|
||||
fileName?: string;
|
||||
}> {
|
||||
@observable private editor:
|
||||
| monacoTypes.editor.IStandaloneCodeEditor
|
||||
@@ -48,6 +22,13 @@ export class MonacoEditor extends React.Component<{
|
||||
}
|
||||
}
|
||||
|
||||
get languageId(): string {
|
||||
if (!this.props.fileName) {
|
||||
return "text";
|
||||
}
|
||||
return getLanguageId(this.props.fileName);
|
||||
}
|
||||
|
||||
private model: monacoTypes.editor.ITextModel | undefined = undefined;
|
||||
|
||||
@disposeOnUnmount
|
||||
@@ -55,7 +36,7 @@ export class MonacoEditor extends React.Component<{
|
||||
if (this.editor) {
|
||||
const model = getLoadedMonaco().editor.createModel(
|
||||
this.props.text,
|
||||
this.props.languageId,
|
||||
this.languageId,
|
||||
undefined
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { getLoadedMonaco } from "@hediet/monaco-editor-react";
|
||||
|
||||
export function getLanguageId(fileName: string): string {
|
||||
const l = getLoadedMonaco().languages.getLanguages();
|
||||
const result = l.find(l => {
|
||||
if (l.filenamePatterns) {
|
||||
for (const p of l.filenamePatterns) {
|
||||
if (new RegExp(p).test(fileName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (l.extensions) {
|
||||
for (const p of l.extensions) {
|
||||
if (fileName.endsWith(p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (result) {
|
||||
return result.id;
|
||||
}
|
||||
return "text";
|
||||
}
|
||||
@@ -6,13 +6,17 @@ import {
|
||||
sProp,
|
||||
} from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import { getLanguageId, MonacoEditor } from "./MonacoEditor";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
import { makeLazyLoadable } from "../../utils/LazyLoadable";
|
||||
|
||||
export const MonacoEditorLazyLoadable = makeLazyLoadable(
|
||||
async () => (await import("./MonacoEditor")).MonacoEditor
|
||||
);
|
||||
|
||||
export const monacoTextVisualizer = createVisualizer({
|
||||
id: "monaco-text",
|
||||
@@ -28,15 +32,17 @@ export const monacoTextVisualizer = createVisualizer({
|
||||
}),
|
||||
}).defineAs(visualizationNs("MonacoTextVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 500 }, theme => {
|
||||
let id = "text";
|
||||
if (data.fileName) {
|
||||
id = getLanguageId(data.fileName);
|
||||
}
|
||||
return (
|
||||
<MonacoEditor text={data.text} languageId={id} theme={theme} />
|
||||
);
|
||||
}),
|
||||
createReactVisualization(
|
||||
self,
|
||||
{ priority: 500, preload: MonacoEditorLazyLoadable.preload },
|
||||
({ theme }) => (
|
||||
<MonacoEditorLazyLoadable
|
||||
text={data.text}
|
||||
fileName={data.fileName}
|
||||
theme={theme}
|
||||
/>
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(monacoTextVisualizer);
|
||||
|
||||
@@ -3,8 +3,8 @@ import { sOpenObject, sLiteral, sArrayOf, sProp } from "@hediet/semantic-json";
|
||||
import { toJS } from "mobx";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { makeLazyLoadable } from "../../utils/LazyLoadable";
|
||||
import { visualizationNs } from "../../consts";
|
||||
@@ -28,21 +28,28 @@ export const perspectiveTableVisualizer = createVisualizer({
|
||||
name: "Perspective Table",
|
||||
serializer: sTable,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, theme => (
|
||||
<PerspectiveDataViewerLazyLoadable
|
||||
className={
|
||||
{
|
||||
light: "perspective-viewer-material",
|
||||
dark: "perspective-viewer-material-dark",
|
||||
}[theme.kind]
|
||||
}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
data={toJS(data.rows)}
|
||||
/>
|
||||
)),
|
||||
createReactVisualization(
|
||||
self,
|
||||
{
|
||||
priority: 1000,
|
||||
preload: PerspectiveDataViewerLazyLoadable.preload,
|
||||
},
|
||||
({ theme }) => (
|
||||
<PerspectiveDataViewerLazyLoadable
|
||||
className={
|
||||
{
|
||||
light: "perspective-viewer-material",
|
||||
dark: "perspective-viewer-material-dark",
|
||||
}[theme.kind]
|
||||
}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
data={toJS(data.rows)}
|
||||
/>
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(perspectiveTableVisualizer);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Theme } from "@hediet/visualization-core";
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import Plot from "react-plotly.js";
|
||||
@@ -6,13 +7,14 @@ import Plot from "react-plotly.js";
|
||||
export class PlotlyViewer extends React.Component<{
|
||||
data: Plotly.Data[];
|
||||
layout?: Partial<Plotly.Layout>;
|
||||
theme: "light" | "dark";
|
||||
theme: Theme;
|
||||
onReady: () => void;
|
||||
}> {
|
||||
render() {
|
||||
const { theme, data, layout } = this.props;
|
||||
const computedLayout = Object.assign(
|
||||
{},
|
||||
theme === "dark" ? darkLayout : {},
|
||||
theme.id === "dark" ? getLayout(theme) : {},
|
||||
layout || {}
|
||||
);
|
||||
|
||||
@@ -39,11 +41,108 @@ export class PlotlyViewer extends React.Component<{
|
||||
data={data}
|
||||
layout={computedLayout}
|
||||
config={{ responsive: true }}
|
||||
onInitialized={this.props.onReady}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getLayout(theme: Theme): Partial<Plotly.Layout> {
|
||||
return {
|
||||
colorway: [
|
||||
"#636efa",
|
||||
"#EF553B",
|
||||
"#00cc96",
|
||||
"#ab63fa",
|
||||
"#19d3f3",
|
||||
"#e763fa",
|
||||
"#fecb52",
|
||||
"#ffa15a",
|
||||
"#ff6692",
|
||||
"#b6e880",
|
||||
],
|
||||
autosize: true,
|
||||
font: { color: "#f2f5fa" },
|
||||
title: { x: 0.05 },
|
||||
paper_bgcolor: theme.resolveVarToColor("--visualizer-background"), // "rgb(17,17,17)",
|
||||
plot_bgcolor: theme.resolveVarToColor("--visualizer-background"), // "rgb(17,17,17)",
|
||||
hovermode: "closest",
|
||||
polar: {
|
||||
bgcolor: theme.resolveVarToColor("--visualizer-background"),
|
||||
angularaxis: {
|
||||
gridcolor: "#506784",
|
||||
linecolor: "#506784",
|
||||
ticks: "",
|
||||
},
|
||||
radialaxis: {
|
||||
gridcolor: "#506784",
|
||||
linecolor: "#506784",
|
||||
ticks: "",
|
||||
},
|
||||
},
|
||||
ternary: {
|
||||
bgcolor: theme.resolveVarToColor("--visualizer-background"),
|
||||
aaxis: { gridcolor: "#506784", linecolor: "#506784", ticks: "" },
|
||||
baxis: { gridcolor: "#506784", linecolor: "#506784", ticks: "" },
|
||||
caxis: { gridcolor: "#506784", linecolor: "#506784", ticks: "" },
|
||||
},
|
||||
xaxis: {
|
||||
gridcolor: "#283442",
|
||||
linecolor: "#506784",
|
||||
ticks: "",
|
||||
zerolinecolor: "#283442",
|
||||
zerolinewidth: 2,
|
||||
automargin: true,
|
||||
},
|
||||
yaxis: {
|
||||
gridcolor: "#283442",
|
||||
linecolor: "#506784",
|
||||
ticks: "",
|
||||
zerolinecolor: "#283442",
|
||||
zerolinewidth: 2,
|
||||
automargin: true,
|
||||
},
|
||||
scene: {
|
||||
xaxis: {
|
||||
gridcolor: "#506784",
|
||||
linecolor: "#506784",
|
||||
showbackground: false,
|
||||
ticks: "",
|
||||
zerolinecolor: "#C8D4E3",
|
||||
gridwidth: 2,
|
||||
},
|
||||
yaxis: {
|
||||
gridcolor: "#506784",
|
||||
linecolor: "#506784",
|
||||
showbackground: false,
|
||||
ticks: "",
|
||||
zerolinecolor: "#C8D4E3",
|
||||
gridwidth: 2,
|
||||
},
|
||||
zaxis: {
|
||||
gridcolor: "#506784",
|
||||
linecolor: "#506784",
|
||||
showbackground: false,
|
||||
ticks: "",
|
||||
zerolinecolor: "#C8D4E3",
|
||||
gridwidth: 2,
|
||||
},
|
||||
},
|
||||
geo: {
|
||||
bgcolor: theme.resolveVarToColor("--visualizer-plotly-background"),
|
||||
landcolor: theme.resolveVarToColor(
|
||||
"--visualizer-plotly-background"
|
||||
),
|
||||
subunitcolor: "#506784",
|
||||
showland: true,
|
||||
showlakes: true,
|
||||
lakecolor: theme.resolveVarToColor(
|
||||
"--visualizer-plotly-background"
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// extracted from the plotly website
|
||||
const darkLayout: Partial<Plotly.Layout> = {
|
||||
colorway: [
|
||||
@@ -59,53 +158,6 @@ const darkLayout: Partial<Plotly.Layout> = {
|
||||
"#b6e880",
|
||||
],
|
||||
autosize: true,
|
||||
//margin: { b: 0, t: 0, pad: 0 },
|
||||
//height: 300,
|
||||
/*colorscale: {
|
||||
sequential: [
|
||||
[0, "#0508b8"],
|
||||
[0.0893854748603352, "#1910d8"],
|
||||
[0.1787709497206704, "#3c19f0"],
|
||||
[0.2681564245810056, "#6b1cfb"],
|
||||
[0.3575418994413408, "#981cfd"],
|
||||
[0.44692737430167595, "#bf1cfd"],
|
||||
[0.5363128491620112, "#dd2bfd"],
|
||||
[0.6256983240223464, "#f246fe"],
|
||||
[0.7150837988826816, "#fc67fd"],
|
||||
[0.8044692737430168, "#fe88fc"],
|
||||
[0.8938547486033519, "#fea5fd"],
|
||||
[0.9832402234636871, "#febefe"],
|
||||
[1, "#fec3fe"],
|
||||
],
|
||||
sequentialminus: [
|
||||
[0, "#0508b8"],
|
||||
[0.0893854748603352, "#1910d8"],
|
||||
[0.1787709497206704, "#3c19f0"],
|
||||
[0.2681564245810056, "#6b1cfb"],
|
||||
[0.3575418994413408, "#981cfd"],
|
||||
[0.44692737430167595, "#bf1cfd"],
|
||||
[0.5363128491620112, "#dd2bfd"],
|
||||
[0.6256983240223464, "#f246fe"],
|
||||
[0.7150837988826816, "#fc67fd"],
|
||||
[0.8044692737430168, "#fe88fc"],
|
||||
[0.8938547486033519, "#fea5fd"],
|
||||
[0.9832402234636871, "#febefe"],
|
||||
[1, "#fec3fe"],
|
||||
],
|
||||
diverging: [
|
||||
[0, "#8e0152"],
|
||||
[0.1, "#c51b7d"],
|
||||
[0.2, "#de77ae"],
|
||||
[0.3, "#f1b6da"],
|
||||
[0.4, "#fde0ef"],
|
||||
[0.5, "#f7f7f7"],
|
||||
[0.6, "#e6f5d0"],
|
||||
[0.7, "#b8e186"],
|
||||
[0.8, "#7fbc41"],
|
||||
[0.9, "#4d9221"],
|
||||
[1, "#276419"],
|
||||
],
|
||||
},*/
|
||||
font: { color: "#f2f5fa" },
|
||||
title: { x: 0.05 },
|
||||
paper_bgcolor: "rgb(17,17,17)",
|
||||
@@ -175,17 +227,6 @@ const darkLayout: Partial<Plotly.Layout> = {
|
||||
gridwidth: 2,
|
||||
},
|
||||
},
|
||||
/*
|
||||
shapedefaults: {
|
||||
fillcolor: "#f2f5fa",
|
||||
line: { width: 0 },
|
||||
opacity: 0.4,
|
||||
},
|
||||
annotationdefaults: {
|
||||
arrowcolor: "#f2f5fa",
|
||||
arrowhead: 0,
|
||||
arrowwidth: 1,
|
||||
},*/
|
||||
geo: {
|
||||
bgcolor: "rgb(17,17,17)",
|
||||
landcolor: "rgb(17,17,17)",
|
||||
@@ -194,13 +235,4 @@ const darkLayout: Partial<Plotly.Layout> = {
|
||||
showlakes: true,
|
||||
lakecolor: "rgb(17,17,17)",
|
||||
},
|
||||
/*
|
||||
updatemenudefaults: { bgcolor: "#506784", borderwidth: 0 },
|
||||
sliderdefaults: {
|
||||
bgcolor: "#C8D4E3",
|
||||
borderwidth: 1,
|
||||
bordercolor: "rgb(17,17,17)",
|
||||
tickwidth: 0,
|
||||
},
|
||||
*/
|
||||
};
|
||||
|
||||
@@ -14,8 +14,9 @@ import {
|
||||
import { makeLazyLoadable } from "../../utils/LazyLoadable";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
createLazyReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
@@ -111,13 +112,21 @@ export const plotlyVisualizer = createVisualizer({
|
||||
),
|
||||
}).defineAs(visualizationNs("PlotlyVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, theme => (
|
||||
<PlotlyViewerLazyLoadable
|
||||
data={data.data}
|
||||
layout={data.layout}
|
||||
theme={theme.kind}
|
||||
/>
|
||||
)),
|
||||
createLazyReactVisualization(
|
||||
self,
|
||||
{
|
||||
priority: 1000,
|
||||
preload: PlotlyViewerLazyLoadable.preload,
|
||||
},
|
||||
({ theme, readyCallback }) => (
|
||||
<PlotlyViewerLazyLoadable
|
||||
data={data.data}
|
||||
layout={data.layout}
|
||||
theme={theme}
|
||||
onReady={readyCallback}
|
||||
/>
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(plotlyVisualizer);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.themeable {
|
||||
--visualizer-plotly-background: var(--visualizer-background);
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import { sOpenObject, sLiteral, sString } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
@@ -30,7 +30,7 @@ export const simpleTextVisualizer = createVisualizer({
|
||||
) =>
|
||||
// If you want to use react, this is the way to go.
|
||||
// Return your own implementation if you want to render directly to the DOM.
|
||||
new ReactVisualization(
|
||||
createReactVisualization(
|
||||
self,
|
||||
{
|
||||
// The priority is used for automatically selecting the best visualization
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { sAny, sOpenObject } from "@hediet/semantic-json";
|
||||
import { sOpenObject } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
createReactVisualization,
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { MonacoEditor } from "../monaco-text-visualizer/MonacoEditor";
|
||||
import { visualizationNs } from "../../consts";
|
||||
import { MonacoEditorLazyLoadable } from "../monaco-text-visualizer";
|
||||
|
||||
export const sourceVisualizer = createVisualizer({
|
||||
id: "source",
|
||||
@@ -15,10 +15,10 @@ export const sourceVisualizer = createVisualizer({
|
||||
kind: sOpenObject({}),
|
||||
}).defineAs(visualizationNs("SourceVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: -100 }, theme => (
|
||||
<MonacoEditor
|
||||
createReactVisualization(self, { priority: -100 }, ({ theme }) => (
|
||||
<MonacoEditorLazyLoadable
|
||||
text={JSON.stringify(data, undefined, 4)}
|
||||
languageId={"json"}
|
||||
fileName={"main.json"}
|
||||
theme={theme}
|
||||
/>
|
||||
)),
|
||||
|
||||
@@ -3,8 +3,8 @@ import { sOpenObject, sLiteral, sString, sProp } from "@hediet/semantic-json";
|
||||
import { SvgViewer } from "./SvgViewer";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
@@ -18,7 +18,7 @@ export const svgVisualizer = createVisualizer({
|
||||
text: sProp(sString(), { description: "The svg content" }),
|
||||
}).defineAs(visualizationNs("SvgVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1500 }, () => (
|
||||
createReactVisualization(self, { priority: 1500 }, () => (
|
||||
<SvgViewer svgContent={data.text} />
|
||||
)),
|
||||
});
|
||||
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
} from "@hediet/semantic-json";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
createReactVisualization,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
@@ -86,7 +86,7 @@ export const treeVisualizer = createVisualizer({
|
||||
name: "Tree",
|
||||
serializer: sTree,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1200 }, () => {
|
||||
createReactVisualization(self, { priority: 1200 }, () => {
|
||||
const m = createTreeViewModelFromTreeNodeData(
|
||||
data.root,
|
||||
() => undefined
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
@import "./src/visualizers/ast-visualizer/style.scss";
|
||||
@import "./src/visualizers/svg-visualizer/style.scss";
|
||||
@import "./src/visualizers/graph/graph-visjs-visualizer/style.scss";
|
||||
@import "./src/visualizers/plotly-visualizer/style.scss";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hediet/visualization-core",
|
||||
"description": "Provides infrastructure to find registered visualizations for given json data",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/hediet/visualization",
|
||||
"repository": {
|
||||
@@ -28,7 +28,7 @@
|
||||
"types": "./dist/index.d.ts",
|
||||
"dependencies": {
|
||||
"@hediet/std": "^0.6.0",
|
||||
"@hediet/semantic-json": "^0.3.14",
|
||||
"@hediet/semantic-json": "^0.3.15",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-measure": "^2.3.0"
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -316,6 +316,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@hediet/semantic-json/-/semantic-json-0.3.14.tgz#876bd5c4b646c134641ad17e9ef352595fb163e7"
|
||||
integrity sha512-u2QGfT98RNrcQjqRHwFUy+TU8+sLneBOYvHHNbkHyYNokqi8kCpE9LReTygGT+6SfMtydTWN6JT9L2ffxrvV6w==
|
||||
|
||||
"@hediet/semantic-json@^0.3.15":
|
||||
version "0.3.15"
|
||||
resolved "https://registry.yarnpkg.com/@hediet/semantic-json/-/semantic-json-0.3.15.tgz#e38f799b1a7dd2624a3ee2e05bca58cfe76cb58d"
|
||||
integrity sha512-8t1NXiYDF2wqIt1jEknxNnpucdtgFAI2MGSWnnewDhaYqWOJLMY/MxH60gDX03vycf2ySb6vEYpEwsiB6r0O3Q==
|
||||
|
||||
"@hediet/std@^0.6.0":
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@hediet/std/-/std-0.6.0.tgz#f7d2ffc1180ecef6ff272d0d6780f0c0d9337e4e"
|
||||
|
||||
Reference in New Issue
Block a user