mirror of
https://github.com/ellmau/adf-obdd.git
synced 2025-12-20 09:39:38 +01:00
Experiment with basic graph visualization
This commit is contained in:
parent
73986437f8
commit
c8cf116aaf
13
frontend/.editorconfig
Normal file
13
frontend/.editorconfig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{ts,tsx}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[package.json]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
25
frontend/.eslintrc.js
Normal file
25
frontend/.eslintrc.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
module.exports = {
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"airbnb"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true
|
||||||
|
},
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"react",
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"react/jsx-filename-extension": [1, { "extensions": [".tsx"] }]
|
||||||
|
}
|
||||||
|
}
|
||||||
5
frontend/.gitignore
vendored
Normal file
5
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.parcel-cache
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
29
frontend/package.json
Normal file
29
frontend/package.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "ADF-OBDD-Frontend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"source": "src/index.html",
|
||||||
|
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||||
|
"scripts": {
|
||||||
|
"start": "parcel",
|
||||||
|
"build": "parcel build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.0.12",
|
||||||
|
"@types/react-dom": "^18.0.5",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||||
|
"@typescript-eslint/parser": "^5.28.0",
|
||||||
|
"eslint": "^8.17.0",
|
||||||
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||||
|
"eslint-plugin-react": "^7.30.0",
|
||||||
|
"parcel": "^2.6.0",
|
||||||
|
"process": "^0.11.10",
|
||||||
|
"typescript": "^4.7.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@antv/g6": "^4.6.4",
|
||||||
|
"react": "^18.1.0",
|
||||||
|
"react-dom": "^18.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
frontend/src/app.tsx
Normal file
8
frontend/src/app.tsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
|
import App from './components/app.tsx';
|
||||||
|
|
||||||
|
const container = document.getElementById('app');
|
||||||
|
const root = createRoot(container);
|
||||||
|
root.render(<App />);
|
||||||
9
frontend/src/components/app.tsx
Normal file
9
frontend/src/components/app.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import Graph from './graph.tsx';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return <Graph />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
99
frontend/src/components/graph.tsx
Normal file
99
frontend/src/components/graph.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import G6 from '@antv/g6';
|
||||||
|
import testData from '../test-data.ts';
|
||||||
|
|
||||||
|
function Graph() {
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
|
let graph = null;
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
if (!graph) {
|
||||||
|
graph = new G6.Graph({
|
||||||
|
container: ref.current,
|
||||||
|
width: 1200,
|
||||||
|
height: 800,
|
||||||
|
modes: {
|
||||||
|
default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
|
||||||
|
},
|
||||||
|
layout: { type: 'dagre' },
|
||||||
|
defaultNode: {
|
||||||
|
style: {
|
||||||
|
r: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultEdge: {
|
||||||
|
style: {
|
||||||
|
endArrow: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodeStateStyles: {
|
||||||
|
hover: {
|
||||||
|
fill: 'lightsteelblue',
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
stroke: '#000',
|
||||||
|
lineWidth: 3,
|
||||||
|
},
|
||||||
|
lowlight: {
|
||||||
|
opacity: 0.3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
edgeStateStyles: {
|
||||||
|
lowlight: {
|
||||||
|
opacity: 0.3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse enter a node
|
||||||
|
graph.on('node:mouseenter', (e) => {
|
||||||
|
const nodeItem = e.item; // Get the target item
|
||||||
|
graph.setItemState(nodeItem, 'hover', true); // Set the state 'hover' of the item to be true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mouse leave a node
|
||||||
|
graph.on('node:mouseleave', (e) => {
|
||||||
|
const nodeItem = e.item; // Get the target item
|
||||||
|
graph.setItemState(nodeItem, 'hover', false); // Set the state 'hover' of the item to be false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click a node
|
||||||
|
graph.on('node:click', (e) => {
|
||||||
|
// Swich the 'click' state of the node to be false
|
||||||
|
const clickNodes = graph.findAllByState('node', 'highlight');
|
||||||
|
clickNodes.forEach((cn) => {
|
||||||
|
graph.setItemState(cn, 'highlight', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.getNodes().forEach((node) => {
|
||||||
|
graph.setItemState(node, 'lowlight', true);
|
||||||
|
});
|
||||||
|
graph.getEdges().forEach((edge) => {
|
||||||
|
graph.setItemState(edge, 'lowlight', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
const nodeItem = e.item; // et the clicked item
|
||||||
|
graph.setItemState(nodeItem, 'lowlight', false);
|
||||||
|
graph.setItemState(nodeItem, 'highlight', true);
|
||||||
|
nodeItem.getEdges().forEach((edge) => {
|
||||||
|
graph.setItemState(edge, 'lowlight', false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.data({
|
||||||
|
nodes: testData.map((node, index) => ({ id: index.toString(), label: node.label })),
|
||||||
|
edges: testData.flatMap((node, index) => [{ source: index.toString(), target: node.lo.toString(), style: { stroke: 'red', lineWidth: 2 } }, { source: index.toString(), target: node.hi.toString(), style: { stroke: 'green', lineWidth: 2 } }]),
|
||||||
|
});
|
||||||
|
graph.render();
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return <div ref={ref} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Graph;
|
||||||
12
frontend/src/index.html
Normal file
12
frontend/src/index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>ADF-OBDD Web Visualizer</title>
|
||||||
|
<script type="module" src="app.tsx"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
19
frontend/src/test-data.ts
Normal file
19
frontend/src/test-data.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const testData = [
|
||||||
|
{ label: 'BOT', lo: 0, hi: 0 },
|
||||||
|
{ label: 'TOP', lo: 1, hi: 1 },
|
||||||
|
{ label: 'Var8', lo: 0, hi: 1 },
|
||||||
|
{ label: 'Var7', lo: 1, hi: 0 },
|
||||||
|
{ label: 'Var0', lo: 3, hi: 1 },
|
||||||
|
{ label: 'Var9', lo: 0, hi: 1 },
|
||||||
|
{ label: 'Var8', lo: 5, hi: 0 },
|
||||||
|
{ label: 'Var0', lo: 6, hi: 5 },
|
||||||
|
{ label: 'Var1', lo: 0, hi: 1 },
|
||||||
|
{ label: 'Var0', lo: 1, hi: 0 },
|
||||||
|
{ label: 'Var9', lo: 1, hi: 0 },
|
||||||
|
{ label: 'Var8', lo: 0, hi: 10 },
|
||||||
|
{ label: 'Var0', lo: 5, hi: 0 },
|
||||||
|
{ label: 'Var8', lo: 1, hi: 0 },
|
||||||
|
{ label: 'Var5', lo: 13, hi: 0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default testData;
|
||||||
3424
frontend/yarn.lock
Normal file
3424
frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user