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