Compare commits
28 Commits
@hediet/vi
...
@hediet/vi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff96aff56 | ||
|
|
107ba3f8e8 | ||
|
|
cd9f7aa5ef | ||
|
|
27a616d43f | ||
|
|
c9143877f7 | ||
|
|
7f158bd500 | ||
|
|
340a5a5315 | ||
|
|
aa2502452e | ||
|
|
9277f7a99a | ||
|
|
620458924b | ||
|
|
3cdbd1d9b1 | ||
|
|
2c8ac3977c | ||
|
|
4a564eca9b | ||
|
|
33de54d696 | ||
|
|
3a64fd9704 | ||
|
|
6bdf8c3b61 | ||
|
|
84d59393ee | ||
|
|
743d0db6c9 | ||
|
|
f7fa31995e | ||
|
|
20c52ff4a7 | ||
|
|
8b6d65614d | ||
|
|
1fe6ae1270 | ||
|
|
1911a8092e | ||
|
|
b46c7155b2 | ||
|
|
3c41b3c0bf | ||
|
|
c0e10d9a97 | ||
|
|
41357e6821 | ||
|
|
93ea01fc79 |
23
.github/workflows/ci.yml
vendored
Normal file
23
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10.x
|
||||
- run: yarn install
|
||||
- run: yarn build
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"tasksStatusbar.taskLabelFilter": "dev"
|
||||
"tasksStatusbar.taskLabelFilter": "dev",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
|
||||
78
README.md
78
README.md
@@ -1,76 +1,16 @@
|
||||
# Visualization Framework
|
||||
|
||||
## Installation
|
||||
This repository contains two packages.
|
||||
|
||||
You can use yarn to install the core library:
|
||||
## @hediet/visualization-core
|
||||
|
||||
```
|
||||
yarn add @hediet/visualization-core
|
||||
```
|
||||
This package provides basic infrastructure for implementing visualizations.
|
||||
See its readme [here](./visualization-core/README.md).
|
||||
|
||||
If you want to use the existing visualizations, add the bundle library:
|
||||
## @hediet/visualization-bundle
|
||||
|
||||
```
|
||||
yarn add @hediet/visualization-bundle
|
||||
```
|
||||
This package bundles all the visualizations.
|
||||
See its readme [here](./visualization-bundle/README.md).
|
||||
|
||||
## Usage
|
||||
|
||||
Import `@hediet/visualization-bundle` to register all default visualizations:
|
||||
|
||||
```tsx
|
||||
// This registers all visualizations
|
||||
import "@hediet/visualization-bundle";
|
||||
```
|
||||
|
||||
Don't forget to import the styles in your scss file:
|
||||
|
||||
```scss
|
||||
@import "~@hediet/visualization-bundle/style.scss";
|
||||
```
|
||||
|
||||
Use `globalVisualizationFactory` to visualize some data:
|
||||
|
||||
```tsx
|
||||
import { globalVisualizationFactory } from "@hediet/visualization-core";
|
||||
|
||||
const data = {
|
||||
kind: { graph: true as true },
|
||||
nodes: [
|
||||
{ id: "1", label: "1" },
|
||||
{ id: "2", label: "2", color: "orange" },
|
||||
{ id: "3", label: "3" },
|
||||
],
|
||||
edges: [
|
||||
{ from: "1", to: "2", color: "red" },
|
||||
{ from: "1", to: "3" },
|
||||
],
|
||||
};
|
||||
|
||||
const visualizations = globalVisualizationFactory.getVisualizations(
|
||||
data,
|
||||
/* preferred visualization id */ undefined
|
||||
);
|
||||
// `visualizations.bestVisualization` is the visualization that is best suited to visualize the data.
|
||||
// `visualiztaions.allVisualizations` contains all other available visualizations than can visualize the data.
|
||||
```
|
||||
|
||||
If you use react, you can use the `VisualizationView` component to render a visualization:
|
||||
|
||||
```tsx
|
||||
import { VisualizationView, Theme } from "@hediet/visualization-core";
|
||||
|
||||
// const visualizations = ...
|
||||
|
||||
function App() {
|
||||
if (!visualizations.bestVisualization) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<VisualizationView
|
||||
theme={Theme.light}
|
||||
visualization={visualizations.bestVisualization}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
If you want to add your own visualization to this project, visualization-bundle is the right place!
|
||||
The readme documents how to implement your own visualization.
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
"./simple-demo",
|
||||
"./playground"
|
||||
],
|
||||
"scripts": {},
|
||||
"scripts": {
|
||||
"build": "yarn build-core && yarn build-bundle && yarn build-playground && yarn build-simple-demo",
|
||||
"build-core": "yarn workspace @hediet/visualization-core run build",
|
||||
"build-bundle": "yarn workspace @hediet/visualization-bundle run build",
|
||||
"build-playground": "yarn workspace playground run build",
|
||||
"build-simple-demo": "yarn workspace simple-demo run build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^1.19.1"
|
||||
}
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --hot --port 8080",
|
||||
"build": "webpack",
|
||||
"dev": "webpack-dev-server --hot",
|
||||
"build": "yarn build-webpack && yarn build-docs",
|
||||
"build-webpack": "node --max_old_space_size=4096 ../node_modules/webpack/bin/webpack.js --mode production",
|
||||
"build-docs": "ts-node ./scripts/build-docs",
|
||||
"pub": "gh-pages -d dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blueprintjs/core": "^3.23.1",
|
||||
"@hediet/std": "^0.6.0",
|
||||
"@hediet/semantic-json": "^0.3.11",
|
||||
"@hediet/semantic-json": "^0.3.14",
|
||||
"blueprintjs": "^0.0.8",
|
||||
"classnames": "^2.2.6",
|
||||
"mobx": "^5.15.4",
|
||||
@@ -21,7 +23,7 @@
|
||||
"messagepack": "^1.1.10",
|
||||
"base64-js": "^1.3.1",
|
||||
"lzma": "^2.3.2",
|
||||
"@hediet/monaco-editor-react": "^0.1.0"
|
||||
"@hediet/monaco-editor-react": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gh-pages": "^2.2.0",
|
||||
@@ -38,6 +40,7 @@
|
||||
"monaco-editor-webpack-plugin": "^1.9.0",
|
||||
"raw-loader": "^4.0.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"sass": "^1.25.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"ts-loader": "^6.2.1",
|
||||
"ts-node": "^8.6.2",
|
||||
|
||||
34
playground/scripts/build-docs.ts
Normal file
34
playground/scripts/build-docs.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
JsonSchemaGenerator,
|
||||
TypeScriptTypeGenerator,
|
||||
} from "@hediet/semantic-json";
|
||||
import { writeFileSync, mkdirSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { globalVisualizationFactory } from "@hediet/visualization-core";
|
||||
import "../src/visualizations";
|
||||
|
||||
const tsGen = new TypeScriptTypeGenerator();
|
||||
const tp = tsGen.getType(globalVisualizationFactory.getSerializer());
|
||||
|
||||
const tsSrc = `export type KnownVisualizationData = ${tp};\n\n\n${[
|
||||
...tsGen.definitions.values(),
|
||||
]
|
||||
.map(v => v.getDefinitionSource({ exported: true }) + `\n\n`)
|
||||
.join("")}`;
|
||||
|
||||
const targetDir = join(__dirname, "../dist/docs");
|
||||
|
||||
mkdirSync(targetDir, { recursive: true });
|
||||
|
||||
writeFileSync(join(targetDir, "visualization-data.ts"), tsSrc, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
|
||||
const schema = new JsonSchemaGenerator().getJsonSchemaWithDefinitions(
|
||||
globalVisualizationFactory.getSerializer()
|
||||
);
|
||||
const jsonSchema = JSON.stringify(schema, undefined, 4);
|
||||
|
||||
writeFileSync(join(targetDir, "visualization-data-schema.json"), jsonSchema, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,5 @@
|
||||
//// 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" /*
|
||||
@@ -7,6 +8,7 @@
|
||||
// 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"; /*
|
||||
@@ -16,6 +18,10 @@
|
||||
|
||||
// This bundles the monaco editor. Uncomment it to load monaco dynamically.
|
||||
// Dynamic loading increases webpack build speed significantly.
|
||||
import "monaco-editor";
|
||||
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"; // */
|
||||
|
||||
@@ -56,7 +56,7 @@ module.exports = {
|
||||
plugins: (() => {
|
||||
const plugins: any[] = [
|
||||
new HtmlWebpackPlugin({
|
||||
title: "Debug Visualizer",
|
||||
title: "Visualization Playground",
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin(),
|
||||
new CleanWebpackPlugin(),
|
||||
@@ -64,7 +64,6 @@ module.exports = {
|
||||
|
||||
plugins.push(
|
||||
new MonacoWebpackPlugin({
|
||||
// Add more languages here once webworker issues are solved.
|
||||
languages: ["typescript", "json"],
|
||||
})
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --hot --port 8090",
|
||||
"build": "webpack"
|
||||
"build": "node --max_old_space_size=4096 ../node_modules/webpack/bin/webpack.js --mode production"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hediet/visualization-core": "^0.1.0",
|
||||
@@ -25,6 +25,7 @@
|
||||
"monaco-editor-webpack-plugin": "^1.9.0",
|
||||
"raw-loader": "^4.0.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"sass": "^1.25.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"ts-loader": "^6.2.1",
|
||||
"ts-node": "^8.6.2",
|
||||
|
||||
@@ -64,7 +64,6 @@ module.exports = {
|
||||
|
||||
plugins.push(
|
||||
new MonacoWebpackPlugin({
|
||||
// Add more languages here once webworker issues are solved.
|
||||
languages: ["typescript", "json"],
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
# Visualization Bundle
|
||||
|
||||
This package registers various visualizations. If you have an idea for a cool visualization, add it here!
|
||||
|
||||
## Installation
|
||||
|
||||
You can use yarn to install this library:
|
||||
|
||||
```
|
||||
yarn add @hediet/visualization-bundle
|
||||
```
|
||||
|
||||
Install `@hediet/visualization-core` before!
|
||||
|
||||
## Usage
|
||||
|
||||
Import `@hediet/visualization-bundle` to register all default visualizations to `globalVisualizationFactory` of `@hediet/visualization-core`:
|
||||
@@ -21,11 +27,38 @@ Don't forget to import the styles in your scss file:
|
||||
@import "~@hediet/visualization-bundle/style.scss";
|
||||
```
|
||||
|
||||
You will need to configure webpack
|
||||
|
||||
- to compile scss files:
|
||||
|
||||
```js
|
||||
{ test: /\.scss$/, loader: "style-loader!css-loader!sass-loader" },
|
||||
```
|
||||
|
||||
- to compile less files:
|
||||
|
||||
```js
|
||||
{ test: /\.less$/, loaders: ["style-loader", "css-loader", "less-loader"] }
|
||||
```
|
||||
|
||||
- to register monaco workers
|
||||
|
||||
```js
|
||||
plugins: [
|
||||
// ...
|
||||
new MonacoWebpackPlugin({
|
||||
languages: ["typescript", "json"],
|
||||
}),
|
||||
];
|
||||
```
|
||||
|
||||
See docs of `@hediet/visualization-core` for how to find and render visualizations!
|
||||
|
||||
## Supported Visualizations
|
||||
|
||||
### Origin Visualizations
|
||||
You can find a playground that demonstrates all visualizations [here](https://hediet.github.io/visualization/).
|
||||
|
||||
### Source Visualizations
|
||||
|
||||
- Tree Visualizer
|
||||
- AST Visualizer (+ Monaco Source Code View)
|
||||
@@ -34,7 +67,7 @@ See docs of `@hediet/visualization-core` for how to find and render visualizatio
|
||||
- Image Visualizer
|
||||
- Simple Text Visualizer
|
||||
|
||||
### Integrated Visualizations
|
||||
### Integrated Visualization Libraries
|
||||
|
||||
- Plotly Visualizer
|
||||
- Perspective JS Visualizer
|
||||
@@ -43,3 +76,22 @@ See docs of `@hediet/visualization-core` for how to find and render visualizatio
|
||||
- Graphviz Dot Visualizer
|
||||
- Vis.js Visualizer
|
||||
- Monaco Editor Source Code Visualizer
|
||||
|
||||
## Setup Local Development Copy
|
||||
|
||||
- Clone this repository.
|
||||
- Run `yarn` in the root folder.
|
||||
- Run `yarn dev` in the `visualization-bundle` folder to start tsc in watch mode.
|
||||
- Edit [./playground/src/visualization.ts](../playground/src/visualizations.ts) to your needs to improve webpack performance. This is highly recommended, but not required.
|
||||
- Run `yarn dev` in the `playground` folder to start the playground where you can debug your visualization.
|
||||
|
||||
Any changes to the source are now reflected in the playground!
|
||||
|
||||
## Implementing New Visualizations
|
||||
|
||||
First, setup your local development copy.
|
||||
|
||||
You can use the [`simple-text-visualizer`](./src/visualizers/simple-text-visualizer/index.tsx) as starting point!
|
||||
Just copy the folder, rename the ids and names, export it [here](./src/visualizers/index.ts) and read through all the comments of the simple-text-visualizer!
|
||||
|
||||
Use the "open" button in the playground to debug your new visualization!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hediet/visualization-bundle",
|
||||
"description": "Bundles several visualizers",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.7",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "tsc --watch",
|
||||
@@ -14,13 +14,14 @@
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
"src",
|
||||
"style.scss"
|
||||
],
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"dependencies": {
|
||||
"@hediet/std": "^0.6.0",
|
||||
"@hediet/semantic-json": "^0.3.11",
|
||||
"@hediet/semantic-json": "^0.3.14",
|
||||
"classnames": "^2.2.6",
|
||||
"mobx": "^5.15.4",
|
||||
"mobx-react": "^6.1.8",
|
||||
@@ -38,10 +39,10 @@
|
||||
"@finos/perspective-viewer": "^0.5.2",
|
||||
"@finos/perspective-viewer-d3fc": "^0.5.2",
|
||||
"@finos/perspective-viewer-datagrid": "^0.5.2",
|
||||
"@hediet/monaco-editor-react": "^0.1.0"
|
||||
"@hediet/monaco-editor-react": "^0.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@hediet/visualization-core": "^0.1.0"
|
||||
"@hediet/visualization-core": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/plotly.js": "^1.50.16",
|
||||
@@ -53,7 +54,6 @@
|
||||
"@types/react": "^16.9.22",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/line-column": "^1.0.0",
|
||||
"sass": "^1.25.0",
|
||||
"ts-loader": "^6.2.1",
|
||||
"ts-node": "^8.6.2",
|
||||
"typescript": "^3.9.7"
|
||||
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
} from "@hediet/visualization-core";
|
||||
import { createTreeViewModelFromTreeNodeData } from "../tree-visualizer";
|
||||
import { AstTree, NodeInfo } from "./AstVisualizer";
|
||||
import React from "react";
|
||||
import LineColumn from "line-column";
|
||||
import * as React from "react";
|
||||
import LineColumn = require("line-column");
|
||||
import * as monacoTypes from "monaco-editor";
|
||||
import { getLoadedMonaco } from "@hediet/monaco-editor-react";
|
||||
|
||||
@@ -54,7 +54,7 @@ export const sAstTreeNode: Serializer<AstTreeNode> = sLazy(() =>
|
||||
{ inclusive: true }
|
||||
)
|
||||
),
|
||||
}).defineAs(visualizationNs("TreeNodeItem"))
|
||||
}).defineAs(visualizationNs("AstTreeNodeItem"))
|
||||
),
|
||||
segment: sOptionalProp(sString()),
|
||||
isMarked: sOptionalProp(sBoolean()),
|
||||
@@ -62,18 +62,19 @@ export const sAstTreeNode: Serializer<AstTreeNode> = sLazy(() =>
|
||||
start: sNumber(),
|
||||
length: sNumber(),
|
||||
}),
|
||||
}).defineAs(visualizationNs("TreeNode"))
|
||||
}).defineAs(visualizationNs("AstTreeNode"))
|
||||
);
|
||||
|
||||
export const sAstTree = sOpenObject({
|
||||
kind: sOpenObject({
|
||||
ast: sLiteral(true),
|
||||
tree: sLiteral(true),
|
||||
text: sLiteral(true),
|
||||
}),
|
||||
root: sAstTreeNode,
|
||||
text: sString(),
|
||||
fileName: sOptionalProp(sString()),
|
||||
});
|
||||
}).defineAs(visualizationNs("AstTreeVisualizationData"));
|
||||
|
||||
export const astVisualizer = createVisualizer({
|
||||
id: "ast",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import * as React from "react";
|
||||
import { sOpenObject, sLiteral, sString } from "@hediet/semantic-json";
|
||||
import { GraphvizDotViewer } from "./GraphvizDotVisualizer";
|
||||
import {
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
globalVisualizationFactory,
|
||||
createVisualizer,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../../consts";
|
||||
|
||||
export const graphvizDotVisualizer = createVisualizer({
|
||||
id: "graphviz-dot",
|
||||
@@ -15,7 +16,7 @@ export const graphvizDotVisualizer = createVisualizer({
|
||||
dotGraph: sLiteral(true),
|
||||
}),
|
||||
text: sString(),
|
||||
}),
|
||||
}).defineAs(visualizationNs("GraphvizDotVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1500 }, () => (
|
||||
<GraphvizDotViewer dotCode={data.text} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import * as React from "react";
|
||||
import { GraphvizGraphViewer } from "./GraphvizGraphVisualizer";
|
||||
import { sGraph } from "../sGraph";
|
||||
import {
|
||||
|
||||
@@ -32,4 +32,4 @@ export const sGraph = sOpenObject({
|
||||
kind: sOpenObject({ graph: sLiteral(true) }),
|
||||
nodes: sArrayOf(sGraphNode),
|
||||
edges: sArrayOf(sGraphEdge),
|
||||
}).defineAs(visualizationNs("Graph"));
|
||||
}).defineAs(visualizationNs("GraphVisualizationData"));
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { computed, action, observable } from "mobx";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
import { sGrid } from ".";
|
||||
|
||||
export class DecoratedGridComponent extends React.Component<{
|
||||
@@ -72,15 +71,7 @@ export class DecoratedGridComponent extends React.Component<{
|
||||
r.columns.push({
|
||||
id: m.id,
|
||||
kind: "empty",
|
||||
content: (
|
||||
<Cell>
|
||||
<Icon
|
||||
icon="arrow-up"
|
||||
color="var(--vscode-editor-foreground)"
|
||||
/>
|
||||
{m.label || m.id}
|
||||
</Cell>
|
||||
),
|
||||
content: <Cell>{m.label || m.id}</Cell>,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import * as React from "react";
|
||||
import {
|
||||
sOpenObject,
|
||||
sLiteral,
|
||||
@@ -14,15 +14,18 @@ import {
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const sGrid = sOpenObject({
|
||||
kind: sOpenObject({
|
||||
array: sLiteral(true),
|
||||
grid: sLiteral(true),
|
||||
}),
|
||||
columnLabels: sArrayOf(
|
||||
sOpenObject({
|
||||
label: sOptionalProp(sString(), {}),
|
||||
})
|
||||
columnLabels: sOptionalProp(
|
||||
sArrayOf(
|
||||
sOpenObject({
|
||||
label: sOptionalProp(sString(), {}),
|
||||
})
|
||||
)
|
||||
),
|
||||
rows: sArrayOf(
|
||||
sOpenObject({
|
||||
@@ -55,7 +58,7 @@ export const sGrid = sOpenObject({
|
||||
),
|
||||
{}
|
||||
),
|
||||
});
|
||||
}).defineAs(visualizationNs("GridVisualizationData"));
|
||||
|
||||
export const gridVisualizer = createVisualizer({
|
||||
id: "grid",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
.theme-dark {
|
||||
--visualizer-grid-empty-foreground: #f0f0f0;
|
||||
}
|
||||
.theme-light {
|
||||
--visualizer-grid-empty-foreground: #000000;
|
||||
}
|
||||
|
||||
.component-Grid {
|
||||
.part-data {
|
||||
border: 1px solid lightgray;
|
||||
@@ -9,6 +16,6 @@
|
||||
}
|
||||
|
||||
.part-empty {
|
||||
color: var(--vscode-editor-foreground);
|
||||
color: var(--visualizer-grid-empty-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { sOpenObject, sLiteral, sString } from "@hediet/semantic-json";
|
||||
import React from "react";
|
||||
import { sOpenObject, sLiteral, sString, sProp } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { SvgViewer } from "../svg-visualizer/SvgViewer";
|
||||
import { Observer, observer, disposeOnUnmount } from "mobx-react";
|
||||
import { observable, autorun } from "mobx";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const imageVisualizer = createVisualizer({
|
||||
id: "image",
|
||||
@@ -16,8 +17,10 @@ export const imageVisualizer = createVisualizer({
|
||||
kind: sOpenObject({
|
||||
imagePng: sLiteral(true),
|
||||
}),
|
||||
base64Data: sString(),
|
||||
}),
|
||||
base64Data: sProp(sString(), {
|
||||
description: "The base 64 encoded PNG representation of the image",
|
||||
}),
|
||||
}).defineAs(visualizationNs("ImageVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, () => {
|
||||
return <ImageViewer base64Data={data.base64Data} />;
|
||||
|
||||
@@ -3,6 +3,7 @@ export * from "./graph";
|
||||
export * from "./grid-visualizer";
|
||||
export * from "./image-visualizer";
|
||||
export * from "./monaco-text-visualizer";
|
||||
export * from "./monaco-text-diff-visualizer";
|
||||
export * from "./perspective-table-visualizer";
|
||||
export * from "./plotly-visualizer";
|
||||
export * from "./simple-text-visualizer";
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import * as React from "react";
|
||||
import { observer, disposeOnUnmount } from "mobx-react";
|
||||
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";
|
||||
}
|
||||
|
||||
@observer
|
||||
export class MonacoEditor extends React.Component<{
|
||||
originalText: string;
|
||||
modifiedText: string;
|
||||
languageId: string;
|
||||
theme: Theme;
|
||||
}> {
|
||||
@observable private editor:
|
||||
| monacoTypes.editor.IStandaloneDiffEditor
|
||||
| undefined;
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.editor) {
|
||||
this.editor.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private originalModel:
|
||||
| monacoTypes.editor.ITextModel
|
||||
| undefined = undefined;
|
||||
private modifiedModel:
|
||||
| monacoTypes.editor.ITextModel
|
||||
| undefined = undefined;
|
||||
|
||||
@disposeOnUnmount
|
||||
private _updateText = autorun(() => {
|
||||
if (this.editor) {
|
||||
const originalModel = getLoadedMonaco().editor.createModel(
|
||||
this.props.originalText,
|
||||
this.props.languageId,
|
||||
undefined
|
||||
);
|
||||
const modifiedModel = getLoadedMonaco().editor.createModel(
|
||||
this.props.modifiedText,
|
||||
this.props.languageId,
|
||||
undefined
|
||||
);
|
||||
|
||||
this.editor.setModel({
|
||||
original: originalModel,
|
||||
modified: modifiedModel,
|
||||
});
|
||||
|
||||
if (this.originalModel) {
|
||||
this.originalModel.dispose();
|
||||
}
|
||||
this.originalModel = originalModel;
|
||||
|
||||
if (this.modifiedModel) {
|
||||
this.modifiedModel.dispose();
|
||||
}
|
||||
this.modifiedModel = modifiedModel;
|
||||
}
|
||||
});
|
||||
|
||||
private readonly setEditorDiv = (editorDiv: HTMLDivElement) => {
|
||||
if (!editorDiv) {
|
||||
return;
|
||||
}
|
||||
this.editor = getLoadedMonaco().editor.createDiffEditor(editorDiv, {
|
||||
automaticLayout: true,
|
||||
scrollBeyondLastLine: false,
|
||||
minimap: { enabled: false },
|
||||
fixedOverflowWidgets: true,
|
||||
readOnly: true,
|
||||
theme: this.props.theme.kind === "dark" ? "vs-dark" : "vs",
|
||||
});
|
||||
if (this.originalModel && this.modifiedModel) {
|
||||
this.editor.setModel({
|
||||
original: this.originalModel!,
|
||||
modified: this.modifiedModel!,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="component-monaco-editor">
|
||||
<div className="part-editor" ref={this.setEditorDiv} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
sOpenObject,
|
||||
sLiteral,
|
||||
sString,
|
||||
sOptionalProp,
|
||||
sProp,
|
||||
} from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
getLanguageId,
|
||||
MonacoEditor as MonacoDiffEditor,
|
||||
} from "./MonacoEditor";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const monacoTextDiffVisualizer = createVisualizer({
|
||||
id: "monaco-text-diff",
|
||||
name: "Text Diff",
|
||||
serializer: sOpenObject({
|
||||
kind: sOpenObject({
|
||||
text: sLiteral(true),
|
||||
}),
|
||||
text: sProp(sString(), { description: "The text to show" }),
|
||||
otherText: sProp(sString(), {
|
||||
description: "The text to compare against",
|
||||
}),
|
||||
fileName: sOptionalProp(sString(), {
|
||||
description:
|
||||
"An optional filename that might be used for chosing a syntax highlighter",
|
||||
}),
|
||||
}).defineAs(visualizationNs("MonacoTextDiffVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 900 }, theme => {
|
||||
let id = "text";
|
||||
if (data.fileName) {
|
||||
id = getLanguageId(data.fileName);
|
||||
}
|
||||
return (
|
||||
<MonacoDiffEditor
|
||||
originalText={data.otherText}
|
||||
modifiedText={data.text}
|
||||
languageId={id}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
globalVisualizationFactory.addVisualizer(monacoTextDiffVisualizer);
|
||||
@@ -0,0 +1,22 @@
|
||||
.component-monaco-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
padding: 2px;
|
||||
border: 0.5px solid gray;
|
||||
|
||||
.part-editor {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
|
||||
.current-line {
|
||||
border: none !important;
|
||||
}
|
||||
.selectionHighlight {
|
||||
background: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import * as React from "react";
|
||||
import { observer, disposeOnUnmount } from "mobx-react";
|
||||
import { observable, autorun } from "mobx";
|
||||
import * as monacoTypes from "monaco-editor";
|
||||
|
||||
@@ -3,14 +3,16 @@ import {
|
||||
sLiteral,
|
||||
sString,
|
||||
sOptionalProp,
|
||||
sProp,
|
||||
} from "@hediet/semantic-json";
|
||||
import React from "react";
|
||||
import * as React from "react";
|
||||
import { getLanguageId, MonacoEditor } from "./MonacoEditor";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const monacoTextVisualizer = createVisualizer({
|
||||
id: "monaco-text",
|
||||
@@ -19,12 +21,12 @@ export const monacoTextVisualizer = createVisualizer({
|
||||
kind: sOpenObject({
|
||||
text: sLiteral(true),
|
||||
}),
|
||||
text: sString(),
|
||||
text: sProp(sString(), { description: "The text to show" }),
|
||||
fileName: sOptionalProp(sString(), {
|
||||
description:
|
||||
"An optional filename that might be used for chosing a syntax highlighter",
|
||||
}),
|
||||
}),
|
||||
}).defineAs(visualizationNs("MonacoTextVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 500 }, theme => {
|
||||
let id = "text";
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import * as React from "react";
|
||||
import { Table } from "@finos/perspective";
|
||||
import "@finos/perspective-viewer";
|
||||
import "@finos/perspective-viewer-datagrid";
|
||||
import "@finos/perspective-viewer-d3fc";
|
||||
import "@finos/perspective-viewer/themes/all-themes.css";
|
||||
import { HTMLPerspectiveViewerElement } from "@finos/perspective-viewer";
|
||||
import { observer } from "mobx-react";
|
||||
import { computed, observable } from "mobx";
|
||||
|
||||
@observer
|
||||
export class PerspectiveDataViewer extends React.Component<
|
||||
{ data: object[] } & React.HTMLAttributes<HTMLDivElement>
|
||||
> {
|
||||
private readonly nodeRef = React.createRef<HTMLPerspectiveViewerElement>();
|
||||
|
||||
@observable key = 0;
|
||||
|
||||
private oldSchemaStr: string | undefined;
|
||||
|
||||
private async replaceData() {
|
||||
const elem = this.nodeRef.current!;
|
||||
const data = this.props.data;
|
||||
const table = (elem as any).worker.table(data) as Table;
|
||||
|
||||
const newSchema = await table.schema();
|
||||
const newSchemaStr = JSON.stringify(newSchema);
|
||||
const oldSchemaStr = this.oldSchemaStr;
|
||||
this.oldSchemaStr = newSchemaStr;
|
||||
|
||||
if (oldSchemaStr && oldSchemaStr !== newSchemaStr) {
|
||||
// perspective js does not like it if new data arrives that has a different schema.
|
||||
// We check if the schema changed an remount the component if it did.
|
||||
this.key++;
|
||||
} else {
|
||||
await elem.load(data);
|
||||
}
|
||||
|
||||
if (!(elem as any)._show_config) {
|
||||
elem.toggleConfig();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.replaceData();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.replaceData();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<perspective-viewer
|
||||
key={this.key}
|
||||
class={this.props.className}
|
||||
style={this.props.style}
|
||||
ref={this.nodeRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,27 @@
|
||||
import React from "react";
|
||||
import { sOpenObject, sLiteral, sArrayOf, sAny } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import { sOpenObject, sLiteral, sArrayOf, sProp } from "@hediet/semantic-json";
|
||||
import { toJS } from "mobx";
|
||||
import "@finos/perspective-viewer";
|
||||
import "@finos/perspective-viewer-datagrid";
|
||||
import "@finos/perspective-viewer-d3fc";
|
||||
import "@finos/perspective-viewer/themes/all-themes.css";
|
||||
import { HTMLPerspectiveViewerElement } from "@finos/perspective-viewer";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { makeLazyLoadable } from "../../utils/LazyLoadable";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const sTable = sOpenObject({
|
||||
kind: sOpenObject({
|
||||
table: sLiteral(true),
|
||||
}),
|
||||
rows: sArrayOf(
|
||||
sAny() // object
|
||||
),
|
||||
});
|
||||
rows: sProp(sArrayOf(sOpenObject({})), {
|
||||
description:
|
||||
"An array of objects. The properties of the objects are used as columns.",
|
||||
}),
|
||||
}).defineAs(visualizationNs("TableVisualizationData"));
|
||||
|
||||
const PerspectiveDataViewerLazyLoadable = makeLazyLoadable(
|
||||
async () => (await import("./PerspectiveDataViewer")).PerspectiveDataViewer
|
||||
);
|
||||
|
||||
export const perspectiveTableVisualizer = createVisualizer({
|
||||
id: "perspective-table",
|
||||
@@ -27,7 +29,7 @@ export const perspectiveTableVisualizer = createVisualizer({
|
||||
serializer: sTable,
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, theme => (
|
||||
<PerspectiveDataViewer
|
||||
<PerspectiveDataViewerLazyLoadable
|
||||
className={
|
||||
{
|
||||
light: "perspective-viewer-material",
|
||||
@@ -43,34 +45,4 @@ export const perspectiveTableVisualizer = createVisualizer({
|
||||
)),
|
||||
});
|
||||
|
||||
class PerspectiveDataViewer extends React.Component<
|
||||
{ data: object[] } & React.HTMLAttributes<HTMLDivElement>
|
||||
> {
|
||||
private readonly nodeRef = React.createRef<HTMLPerspectiveViewerElement>();
|
||||
|
||||
componentDidUpdate() {
|
||||
this.nodeRef.current!.load(this.props.data);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
setTimeout(() => {
|
||||
// TODO: Why timeout?
|
||||
// It does not work without it.
|
||||
|
||||
this.nodeRef.current!.load(this.props.data);
|
||||
this.nodeRef.current!.toggleConfig();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<perspective-viewer
|
||||
class={this.props.className}
|
||||
style={this.props.style}
|
||||
ref={this.nodeRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
globalVisualizationFactory.addVisualizer(perspectiveTableVisualizer);
|
||||
|
||||
@@ -10,15 +10,34 @@ export class PlotlyViewer extends React.Component<{
|
||||
}> {
|
||||
render() {
|
||||
const { theme, data, layout } = this.props;
|
||||
const computedLayout = Object.assign(
|
||||
{},
|
||||
theme === "dark" ? darkLayout : {},
|
||||
layout || {}
|
||||
);
|
||||
|
||||
if (
|
||||
data.length === 1 &&
|
||||
data[0].type === "mesh3d" &&
|
||||
(layout || {}).margin === undefined
|
||||
) {
|
||||
// Fixes https://github.com/JetBrains/rider-debug-visualizer-web-view/issues/6
|
||||
Object.assign(computedLayout, {
|
||||
margin: {
|
||||
l: 0,
|
||||
r: 0,
|
||||
b: 0,
|
||||
t: 0,
|
||||
pad: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Plot
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
data={data}
|
||||
layout={Object.assign(
|
||||
{},
|
||||
theme === "dark" ? darkLayout : {},
|
||||
layout || {}
|
||||
)}
|
||||
layout={computedLayout}
|
||||
config={{ responsive: true }}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -6,6 +6,10 @@ import {
|
||||
sOptionalProp,
|
||||
sAny,
|
||||
sProp,
|
||||
sString,
|
||||
sUnion,
|
||||
sNumber,
|
||||
sNull,
|
||||
} from "@hediet/semantic-json";
|
||||
import { makeLazyLoadable } from "../../utils/LazyLoadable";
|
||||
import {
|
||||
@@ -13,11 +17,15 @@ import {
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
const PlotlyViewerLazyLoadable = makeLazyLoadable(
|
||||
async () => (await import("./PlotlyViewer")).PlotlyViewer
|
||||
);
|
||||
|
||||
const sDatum = sUnion([sString(), sNumber(), sNull()]);
|
||||
const sDatumArr = sUnion([sArrayOf(sDatum), sArrayOf(sArrayOf(sDatum))]);
|
||||
//const x: Plotly.Data;
|
||||
export const plotlyVisualizer = createVisualizer({
|
||||
id: "plotly",
|
||||
name: "plotly",
|
||||
@@ -25,15 +33,83 @@ export const plotlyVisualizer = createVisualizer({
|
||||
kind: sOpenObject({
|
||||
plotly: sLiteral(true),
|
||||
}),
|
||||
data: sProp(sArrayOf(sAny()), {
|
||||
description:
|
||||
"Expecting Plotly.Data[] (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/795ce172038dbafcb9cba030d637d733a7eea19c/types/plotly.js/index.d.ts#L1036)",
|
||||
}),
|
||||
layout: sOptionalProp(sAny(), {
|
||||
description:
|
||||
"Expecting Partial<Plotly.Layout> (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/795ce172038dbafcb9cba030d637d733a7eea19c/types/plotly.js/index.d.ts#L329)",
|
||||
}),
|
||||
}),
|
||||
data: sProp(
|
||||
sArrayOf(
|
||||
sOpenObject({
|
||||
text: sOptionalProp(
|
||||
sUnion([sString(), sArrayOf(sString())])
|
||||
),
|
||||
xaxis: sOptionalProp(sString()),
|
||||
yaxis: sOptionalProp(sString()),
|
||||
x: sOptionalProp(sDatumArr),
|
||||
y: sOptionalProp(sDatumArr),
|
||||
z: sOptionalProp(sDatumArr),
|
||||
type: sOptionalProp(
|
||||
sUnion([
|
||||
sLiteral("bar"),
|
||||
sLiteral("box"),
|
||||
sLiteral("candlestick"),
|
||||
sLiteral("choropleth"),
|
||||
sLiteral("contour"),
|
||||
sLiteral("heatmap"),
|
||||
sLiteral("histogram"),
|
||||
sLiteral("indicator"),
|
||||
sLiteral("mesh3d"),
|
||||
sLiteral("ohlc"),
|
||||
sLiteral("parcoords"),
|
||||
sLiteral("pie"),
|
||||
sLiteral("pointcloud"),
|
||||
sLiteral("scatter"),
|
||||
sLiteral("scatter3d"),
|
||||
sLiteral("scattergeo"),
|
||||
sLiteral("scattergl"),
|
||||
sLiteral("scatterpolar"),
|
||||
sLiteral("scatterternary"),
|
||||
sLiteral("sunburst"),
|
||||
sLiteral("surface"),
|
||||
sLiteral("treemap"),
|
||||
sLiteral("waterfall"),
|
||||
sLiteral("funnel"),
|
||||
sLiteral("funnelarea"),
|
||||
sLiteral("scattermapbox"),
|
||||
])
|
||||
),
|
||||
mode: sOptionalProp(
|
||||
sUnion([
|
||||
sLiteral("lines"),
|
||||
sLiteral("markers"),
|
||||
sLiteral("text"),
|
||||
sLiteral("lines+markers"),
|
||||
sLiteral("text+markers"),
|
||||
sLiteral("text+lines"),
|
||||
sLiteral("text+lines+markers"),
|
||||
sLiteral("none"),
|
||||
sLiteral("gauge"),
|
||||
sLiteral("number"),
|
||||
sLiteral("delta"),
|
||||
sLiteral("number+delta"),
|
||||
sLiteral("gauge+number"),
|
||||
sLiteral("gauge+number+delta"),
|
||||
sLiteral("gauge+delta"),
|
||||
])
|
||||
),
|
||||
})
|
||||
),
|
||||
{
|
||||
description:
|
||||
"Expecting Plotly.Data[] (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/795ce172038dbafcb9cba030d637d733a7eea19c/types/plotly.js/index.d.ts#L1036)",
|
||||
}
|
||||
),
|
||||
layout: sOptionalProp(
|
||||
sOpenObject({
|
||||
title: sOptionalProp(sString()),
|
||||
}),
|
||||
{
|
||||
description:
|
||||
"Expecting Partial<Plotly.Layout> (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/795ce172038dbafcb9cba030d637d733a7eea19c/types/plotly.js/index.d.ts#L329)",
|
||||
}
|
||||
),
|
||||
}).defineAs(visualizationNs("PlotlyVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1000 }, theme => (
|
||||
<PlotlyViewerLazyLoadable
|
||||
|
||||
@@ -1,33 +1,60 @@
|
||||
import { sOpenObject, sLiteral, sString } from "@hediet/semantic-json";
|
||||
import React from "react";
|
||||
import * as React from "react";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const simpleTextVisualizer = createVisualizer({
|
||||
// The id must be unique
|
||||
id: "simple-text",
|
||||
// The name can be some display text
|
||||
name: "Simple Text",
|
||||
// Here you can define the schema for the data that this visualizer can handle.
|
||||
// You must have a kind property of type object whose properties must be `true`.
|
||||
serializer: sOpenObject({
|
||||
kind: sOpenObject({
|
||||
text: sLiteral(true),
|
||||
}),
|
||||
text: sString(),
|
||||
}),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 100 }, () => (
|
||||
<pre
|
||||
className="visualizer-simple-text"
|
||||
style={{
|
||||
margin: 0,
|
||||
padding: 10,
|
||||
color: "var(--visualizer-simple-text-color)",
|
||||
}}
|
||||
>
|
||||
{data.text}
|
||||
</pre>
|
||||
)),
|
||||
}).defineAs(
|
||||
// This name is important for schema and code generation of the interface types.
|
||||
// Make sure it is unique. It should end with "VisualizationData".
|
||||
visualizationNs("SimpleTextVisualizationData")
|
||||
),
|
||||
getVisualization: (
|
||||
/* The type of data is specified by the serializer above. */ data,
|
||||
self
|
||||
) =>
|
||||
// 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(
|
||||
self,
|
||||
{
|
||||
// The priority is used for automatically selecting the best visualization
|
||||
// if multiple visualizations can handle the data.
|
||||
priority: 100,
|
||||
},
|
||||
() => (
|
||||
<pre
|
||||
className="visualizer-simple-text"
|
||||
style={{
|
||||
margin: 0,
|
||||
padding: 10,
|
||||
// Use css vars for theming.
|
||||
// See ./style.scss.
|
||||
color: "var(--visualizer-simple-text-color)",
|
||||
}}
|
||||
>
|
||||
{data.text}
|
||||
</pre>
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
// This registers the visualizer for automatic discovery.
|
||||
// Make sure to import this file in "../index.ts" so that it gets loaded when
|
||||
// someone imports "@hediet/visualization-bundle"!
|
||||
globalVisualizationFactory.addVisualizer(simpleTextVisualizer);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Provide default colors for both the dark and light theme here!
|
||||
|
||||
.theme-dark {
|
||||
--visualizer-simple-text-color: white;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { sAny } from "@hediet/semantic-json";
|
||||
import React from "react";
|
||||
import { sAny, sOpenObject } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { MonacoEditor } from "../monaco-text-visualizer/MonacoEditor";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const sourceVisualizer = createVisualizer({
|
||||
id: "source",
|
||||
name: "JSON Source",
|
||||
serializer: sAny(),
|
||||
serializer: sOpenObject({
|
||||
kind: sOpenObject({}),
|
||||
}).defineAs(visualizationNs("SourceVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: -100 }, theme => (
|
||||
<MonacoEditor
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from "react";
|
||||
import { sOpenObject, sLiteral, sString } from "@hediet/semantic-json";
|
||||
import * as React from "react";
|
||||
import { sOpenObject, sLiteral, sString, sProp } from "@hediet/semantic-json";
|
||||
import { SvgViewer } from "./SvgViewer";
|
||||
import {
|
||||
createVisualizer,
|
||||
ReactVisualization,
|
||||
globalVisualizationFactory,
|
||||
} from "@hediet/visualization-core";
|
||||
import { visualizationNs } from "../../consts";
|
||||
|
||||
export const svgVisualizer = createVisualizer({
|
||||
id: "svg",
|
||||
@@ -14,8 +15,8 @@ export const svgVisualizer = createVisualizer({
|
||||
kind: sOpenObject({
|
||||
svg: sLiteral(true),
|
||||
}),
|
||||
text: sString(),
|
||||
}),
|
||||
text: sProp(sString(), { description: "The svg content" }),
|
||||
}).defineAs(visualizationNs("SvgVisualizationData")),
|
||||
getVisualization: (data, self) =>
|
||||
new ReactVisualization(self, { priority: 1500 }, () => (
|
||||
<SvgViewer svgContent={data.text} />
|
||||
|
||||
@@ -226,33 +226,14 @@ export class TreeWithPathView extends React.Component<{
|
||||
<span>
|
||||
{model.selected.path.reduce((acc, v) => {
|
||||
acc = acc.slice();
|
||||
function add() {
|
||||
acc.push(
|
||||
<span
|
||||
className="part-path-item"
|
||||
key={acc.length}
|
||||
>
|
||||
{v}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (isValidFunctionName(v)) {
|
||||
if (acc.length > 0) {
|
||||
acc.push(
|
||||
<span key={acc.length}>.</span>
|
||||
);
|
||||
}
|
||||
add();
|
||||
} else {
|
||||
acc.push(
|
||||
<span key={acc.length}>[</span>
|
||||
);
|
||||
add();
|
||||
acc.push(
|
||||
<span key={acc.length}>]</span>
|
||||
);
|
||||
}
|
||||
|
||||
acc.push(
|
||||
<span
|
||||
className="part-path-item"
|
||||
key={acc.length}
|
||||
>
|
||||
{v}
|
||||
</span>
|
||||
);
|
||||
return acc;
|
||||
}, new Array<React.ReactElement>())}
|
||||
</span>
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
Serializer,
|
||||
sOptionalProp,
|
||||
sUnion,
|
||||
sProp,
|
||||
} from "@hediet/semantic-json";
|
||||
import {
|
||||
createVisualizer,
|
||||
@@ -37,25 +38,39 @@ export interface Item {
|
||||
|
||||
const sTreeNode: Serializer<TreeNode> = sLazy(() =>
|
||||
sOpenObject({
|
||||
children: sArrayOf(sTreeNode),
|
||||
items: sArrayOf(
|
||||
sOpenObject({
|
||||
text: sString(),
|
||||
emphasis: sOptionalProp(
|
||||
sUnion(
|
||||
[
|
||||
sLiteral("style1"),
|
||||
sLiteral("style2"),
|
||||
sLiteral("style3"),
|
||||
sString(),
|
||||
],
|
||||
{ inclusive: true }
|
||||
)
|
||||
),
|
||||
}).defineAs(visualizationNs("TreeNodeItem"))
|
||||
children: sProp(sArrayOf(sTreeNode), {
|
||||
description: "The children of this tree-node",
|
||||
}),
|
||||
items: sProp(
|
||||
sArrayOf(
|
||||
sOpenObject({
|
||||
text: sProp(sString(), { description: "The text to show" }),
|
||||
emphasis: sOptionalProp(
|
||||
sUnion(
|
||||
[
|
||||
sLiteral("style1"),
|
||||
sLiteral("style2"),
|
||||
sLiteral("style3"),
|
||||
sString(),
|
||||
],
|
||||
{ inclusive: true }
|
||||
),
|
||||
{
|
||||
description: "The style of the text",
|
||||
}
|
||||
),
|
||||
}).defineAs(visualizationNs("TreeNodeItem"))
|
||||
),
|
||||
{ description: "The parts that make up the text of this item" }
|
||||
),
|
||||
segment: sOptionalProp(sString()),
|
||||
isMarked: sOptionalProp(sBoolean()),
|
||||
segment: sOptionalProp(sString(), {
|
||||
description:
|
||||
"If a node is selected, the concatenation of all segment values from root to the selected node is shown to the user.",
|
||||
}),
|
||||
isMarked: sOptionalProp(sBoolean(), {
|
||||
description:
|
||||
"Marked nodes are highlighted and scrolled into view on every visualization update.",
|
||||
}),
|
||||
}).defineAs(visualizationNs("TreeNode"))
|
||||
);
|
||||
|
||||
@@ -64,7 +79,7 @@ const sTree = sOpenObject({
|
||||
tree: sLiteral(true),
|
||||
}),
|
||||
root: sTreeNode,
|
||||
});
|
||||
}).defineAs(visualizationNs("TreeVisualizationData"));
|
||||
|
||||
export const treeVisualizer = createVisualizer({
|
||||
id: "tree",
|
||||
@@ -98,8 +113,10 @@ export function createTreeViewModelFromTreeNodeData<TData, TNodeData>(
|
||||
recurse(c, viewModel)
|
||||
);
|
||||
|
||||
let segment = node.segment;
|
||||
if (!segment && node.items.length > 0) {
|
||||
let segment;
|
||||
if (node.segment) {
|
||||
segment = node.segment;
|
||||
} else if (node.items.length > 0) {
|
||||
segment = node.items[0].text;
|
||||
} else {
|
||||
segment = "";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "es2020",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"outDir": "dist",
|
||||
|
||||
@@ -35,7 +35,7 @@ const visualizations = globalVisualizationFactory.getVisualizations(
|
||||
/* preferred visualization id */ undefined
|
||||
);
|
||||
// `visualizations.bestVisualization` is the visualization that is best suited to visualize the data.
|
||||
// `visualiztaions.allVisualizations` contains all other available visualizations than can visualize the data.
|
||||
// `visualiztaions.allVisualizations` contains all suitable visualizations.
|
||||
```
|
||||
|
||||
If you use react, you can use the `VisualizationView` component to render a visualization:
|
||||
@@ -57,3 +57,7 @@ function App() {
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||

|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hediet/visualization-core",
|
||||
"description": "Provides infrastructure to find registered visualizations for given json data",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"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.11",
|
||||
"@hediet/semantic-json": "^0.3.14",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-measure": "^2.3.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "es2020",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"outDir": "dist",
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -306,15 +306,15 @@
|
||||
tslib "^1.9.3"
|
||||
ws "^6.1.2"
|
||||
|
||||
"@hediet/monaco-editor-react@^0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@hediet/monaco-editor-react/-/monaco-editor-react-0.1.0.tgz#b00dfa28e2ffa09ecc748e35f4befc0e887947f2"
|
||||
integrity sha512-EFAmKW1u9ks2iqTP63qqLPUezKMAnK+UvZrvoRmUMCpRRxG9uduYGPQfASaHcIQYzOqzWaVKvCQN5wQQ+lSxIQ==
|
||||
"@hediet/monaco-editor-react@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@hediet/monaco-editor-react/-/monaco-editor-react-0.1.1.tgz#041f805aeb188403c7876f0f364d2a429e706031"
|
||||
integrity sha512-0DZZfLcFNuc3Wrn+2eztnRloCBe6GV8zIrGT3LPdZlWYEigJT+Qh7ANvRHF0tCS5YPAFGQNZJcfzKbBfqRGo4w==
|
||||
|
||||
"@hediet/semantic-json@^0.3.11":
|
||||
version "0.3.11"
|
||||
resolved "https://registry.yarnpkg.com/@hediet/semantic-json/-/semantic-json-0.3.11.tgz#9420a89d30645ba333dfd4f3f2c120f973297ee2"
|
||||
integrity sha512-KKw6ZcYHiyfhanNmln/WlG4KvZnMi/Ojy8O6HB6sqfDC5XCcNYjccUMMtaX23F/Hox0dWJPFqXYs54KJAA5itg==
|
||||
"@hediet/semantic-json@^0.3.14":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@hediet/semantic-json/-/semantic-json-0.3.14.tgz#876bd5c4b646c134641ad17e9ef352595fb163e7"
|
||||
integrity sha512-u2QGfT98RNrcQjqRHwFUy+TU8+sLneBOYvHHNbkHyYNokqi8kCpE9LReTygGT+6SfMtydTWN6JT9L2ffxrvV6w==
|
||||
|
||||
"@hediet/std@^0.6.0":
|
||||
version "0.6.0"
|
||||
|
||||
Reference in New Issue
Block a user