1
0
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:
monsterkrampe 2022-06-15 16:38:43 +02:00
parent 11083098a2
commit f7302511be
No known key found for this signature in database
GPG Key ID: B8ADC1F5A5CE5057
10 changed files with 3643 additions and 0 deletions

13
frontend/.editorconfig Normal file
View 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
View 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
View File

@ -0,0 +1,5 @@
node_modules
dist
.parcel-cache
yarn-error.log

29
frontend/package.json Normal file
View 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
View 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 />);

View File

@ -0,0 +1,9 @@
import * as React from 'react';
import Graph from './graph.tsx';
function App() {
return <Graph />;
}
export default App;

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff