Skip to content

Commit

Permalink
Adds support for external visualizer functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
hediet committed Apr 21, 2023
1 parent ac15ceb commit 96115a9
Show file tree
Hide file tree
Showing 13 changed files with 316 additions and 155 deletions.
54 changes: 27 additions & 27 deletions playground/src/visualizations.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
//// Uncomment the visualization that you work on to increase webpack build speed!
//// If you create a new visualization, add it here!

// import "@hediet/visualization-bundle/dist/visualizers/ast-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/graph/dot-graphviz-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/graph/graph-graphviz-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/graph/graph-visjs-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/grid-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/image-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/monaco-text-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/monaco-text-diff-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/perspective-table-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/plotly-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/simple-text-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/source-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/svg-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/tree-visualizer"; /*

// This bundles the monaco editor. Uncomment it to load monaco dynamically.
// Dynamic loading increases webpack build speed significantly.
if (typeof process === undefined) {
// We check for process so that we don't load monaco from nodejs.
require("monaco-editor");
}

// This import bundles *all* visualizations. This makes webpack super slow.
import "@hediet/visualization-bundle"; // */
//// Uncomment the visualization that you work on to increase webpack build speed!
//// If you create a new visualization, add it here!

// import "@hediet/visualization-bundle/dist/visualizers/ast-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/graph/dot-graphviz-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/graph/graph-graphviz-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/graph/graph-visjs-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/grid-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/image-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/monaco-text-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/monaco-text-diff-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/perspective-table-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/plotly-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/simple-text-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/source-visualizer"; /*
// import "@hediet/visualization-bundle/dist/visualizers/svg-visualizer" /*
// import "@hediet/visualization-bundle/dist/visualizers/tree-visualizer"; /*

// This bundles the monaco editor. Uncomment it to load monaco dynamically.
// Dynamic loading increases webpack build speed significantly.
if (typeof process === undefined) {
// We check for process so that we don't load monaco from nodejs.
require("monaco-editor");
}

// This import bundles *all* visualizations. This makes webpack super slow.
import "@hediet/visualization-bundle"; // */
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class VisJsGraphViewer extends React.Component<{
shape: n.shape,
});
}
this.nodes.forEach(item => {
this.nodes.forEach((item) => {
if (!newNodes.has(item.id)) {
this.nodes.remove(item);
}
Expand Down Expand Up @@ -74,7 +74,7 @@ export class VisJsGraphViewer extends React.Component<{
],
});
}
this.edges.forEach(item => {
this.edges.forEach((item) => {
if (!newEdges.has(item.id)) {
this.edges.remove(item);
}
Expand All @@ -99,6 +99,92 @@ export class VisJsGraphViewer extends React.Component<{
},
},
};
const network = new Network(this.divRef.current!, data, options);
this.network = new Network(this.divRef.current!, data, options);
this.divRef.current!.setAttribute("tabindex", "0");
document.addEventListener("copy", this.onCopy);
}

private network: Network | undefined;
private readonly onCopy = (e: ClipboardEvent) => {
if (!this.network) {
return;
}
if (
!(
document.activeElement &&
document.activeElement.className === "vis-network"
)
) {
return;
}

const n = this.network as any;

const nodesText: string[] = [];

let id = 10;
const visJsIdToNodeId = new Map<string, number>();

// export to draw.io
for (const node of Object.values(n.body.nodes) as any) {
const label = node.shape.options.label;
if (label === undefined) {
continue;
}

let style = "";
if (node.shape.constructor.name === "Ellipse") {
style += "ellipse;";
} else {
style += "rounded=1;";
}

const nodeId = id++;
visJsIdToNodeId.set(node.id, nodeId);

nodesText.push(
`
<mxCell id="${nodeId}" value="${label}" style="${style}" vertex="1" parent="1">
<mxGeometry x="${node.x}" y="${node.y}" width="${node.shape.width}" height="${node.shape.height}" as="geometry"/>
</mxCell>`
);
}

for (const edge of Object.values(n.body.edges) as any) {
const label = edge.options.label || "";
const edgeId = id++;

nodesText.push(
`
<mxCell id="${edgeId}" value="${label}" edge="1" source="${visJsIdToNodeId.get(
edge.from.id
)}" target="${visJsIdToNodeId.get(edge.to.id)}" parent="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>`
);
}

const data = `
<mxGraphModel>
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
${nodesText.join("\n")}
</root>
</mxGraphModel>`;

/*
<mxCell id="2" value="xxx" edge="1" source="3" target="4" parent="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
*/

e.clipboardData!.setData("text/plain", encodeURIComponent(data));
e.preventDefault();
};

componentWillUnmount() {
document.removeEventListener("copy", this.onCopy);
}
}
65 changes: 38 additions & 27 deletions visualization-bundle/src/visualizers/plotly-visualizer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import * as React from "react";
import {
sOpenObject,
sLiteral,
sArrayOf,
sLiteral,
sNull,
sNumber,
sOpenObject,
sOptionalProp,
sAny,
sProp,
sString,
sUnion,
sNumber,
sNull,
} from "@hediet/semantic-json";
import { makeLazyLoadable } from "../../utils/LazyLoadable";
import { Deferred } from "@hediet/std/synchronization";
import {
createLazyReactVisualization,
createVisualizer,
globalVisualizationFactory,
createReactVisualization,
createLazyReactVisualization,
} from "@hediet/visualization-core";
import * as React from "react";
import { visualizationNs } from "../../consts";
import { makeLazyLoadable } from "../../utils/LazyLoadable";

const PlotlyViewerLazyLoadable = makeLazyLoadable(
async () => (await import("./PlotlyViewer")).PlotlyViewer
Expand All @@ -45,16 +44,22 @@ export const plotlyVisualizer = createVisualizer({
x: sOptionalProp(sDatumArr),
y: sOptionalProp(sDatumArr),
z: sOptionalProp(sDatumArr),
cells: sOptionalProp(sOpenObject({
values: sArrayOf(sDatumArr),
})),
header: sOptionalProp(sOpenObject({
values: sDatumArr,
})),
domain: sOptionalProp(sOpenObject({
x: sArrayOf(sNumber()),
y: sArrayOf(sNumber()),
})),
cells: sOptionalProp(
sOpenObject({
values: sArrayOf(sDatumArr),
})
),
header: sOptionalProp(
sOpenObject({
values: sDatumArr,
})
),
domain: sOptionalProp(
sOpenObject({
x: sArrayOf(sNumber()),
y: sArrayOf(sNumber()),
})
),
type: sOptionalProp(
sUnion([
sLiteral("bar"),
Expand Down Expand Up @@ -129,14 +134,20 @@ export const plotlyVisualizer = createVisualizer({
priority: 1000,
preload: PlotlyViewerLazyLoadable.preload,
},
({ theme, readyCallback }) => (
<PlotlyViewerLazyLoadable
data={data.data}
layout={data.layout}
theme={theme}
onReady={readyCallback}
/>
)
({ theme }) => {
const b = new Deferred();
return {
node: (
<PlotlyViewerLazyLoadable
data={data.data}
layout={data.layout}
theme={theme}
onReady={() => b.resolve}
/>
),
ready: b.promise,
};
}
),
});

Expand Down
2 changes: 1 addition & 1 deletion visualization-core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@hediet/visualization-core",
"description": "Provides infrastructure to find registered visualizations for given json data",
"version": "0.2.0",
"version": "0.2.1",
"license": "MIT",
"homepage": "https://github.com/hediet/visualization",
"repository": {
Expand Down
30 changes: 30 additions & 0 deletions visualization-core/src/CanvasVisualization.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from "react";
import { createReactVisualization } from "./ReactVisualization";
import { Visualization, Visualizer } from "./Visualizer";
import { Disposable } from "@hediet/std/disposable";

export function createCanvas2DVisualization(
sourceVisualizer: Visualizer,
options: { priority: number },
render: (context: CanvasRenderingContext2D) => Disposable | void
): Visualization {
return createReactVisualization(
sourceVisualizer,
{ priority: options.priority },
() => (
<canvas
ref={(canvas) => {
if (canvas) {
const ctx = canvas.getContext("2d")!;
ctx.clearRect(0, 0, canvas.width, canvas.height);

// We don't want to use try/catch to swallow the error, so we use setTimeout to protect the caller
setTimeout(() => {
render(ctx);
}, 0);
}
}}
/>
)
);
}
Loading

0 comments on commit 96115a9

Please sign in to comment.