Migrate to a D3-based graph renderer
This commit is contained in:
48
src/fsm.js
48
src/fsm.js
@@ -1,4 +1,5 @@
|
||||
import mermaid from 'mermaid';
|
||||
import { Graph } from './editor/d3/graph.ts';
|
||||
import { GraphEditor } from './editor/GraphEditor.ts';
|
||||
|
||||
const IS_VALID = 'is-valid';
|
||||
const IS_INVALID = 'is-invalid';
|
||||
@@ -8,11 +9,6 @@ const buttons = /** @type {HTMLDivElement} */ (document.getElementById('input-bu
|
||||
const clearButton = /** @type {HTMLButtonElement} */ (document.getElementById('clear-button'));
|
||||
const light = /** @type {HTMLDivElement} */ (document.getElementById('light'));
|
||||
|
||||
mermaid.initialize({
|
||||
theme: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'default',
|
||||
startOnLoad: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('./examples.js').State[]} states
|
||||
*/
|
||||
@@ -20,25 +16,28 @@ export async function selectAutomaton(states) {
|
||||
let state = 0;
|
||||
let builder = '';
|
||||
|
||||
// Build the mermaid graph definition
|
||||
let graphDefinition = 'stateDiagram-v2\n classDef acceptingnode font-weight:bold,stroke-width:2px,stroke:yellow';
|
||||
for (let i = 0; i < states.length; ++i) {
|
||||
graphDefinition += `\n s${i} : ${i}`;
|
||||
if (i === 0) {
|
||||
graphDefinition += '\n [*] --> s0';
|
||||
}
|
||||
const viewer = new GraphEditor();
|
||||
viewer.readonly = true;
|
||||
const graph = new Graph();
|
||||
for (let i = 0; i < states.length; i++) {
|
||||
const node = graph.createNode(i);
|
||||
if (states[i].accepting) {
|
||||
graphDefinition += `\n s${i} --> [*]`;
|
||||
graphDefinition += `\n class s${i} acceptingnode`;
|
||||
node.accepting = true;
|
||||
}
|
||||
for (const [transition, destination] of Object.entries(states[i].transitions)) {
|
||||
graphDefinition += `\n s${i} --> s${destination}: ${transition}`;
|
||||
if (i === 0) {
|
||||
node.start = true;
|
||||
}
|
||||
}
|
||||
const graph = /** @type {HTMLDivElement} */ (document.getElementById('pen'));
|
||||
const { svg } = await mermaid.render('state-graph', graphDefinition);
|
||||
graph.innerHTML = svg;
|
||||
const nodes = graph.querySelectorAll('.label-container');
|
||||
for (let i = 0; i < states.length; i++) {
|
||||
const state = states[i];
|
||||
for (const [letter, target] of Object.entries(state.transitions)) {
|
||||
graph.createLink(i, target, letter);
|
||||
}
|
||||
}
|
||||
|
||||
const container = /** @type {HTMLDivElement} */ (document.getElementById('state-graph'));
|
||||
container.appendChild(viewer);
|
||||
viewer.graph = graph;
|
||||
|
||||
/**
|
||||
* Updates the UI to reflect the current state.
|
||||
@@ -52,10 +51,11 @@ export async function selectAutomaton(states) {
|
||||
light.classList.remove(IS_INVALID);
|
||||
light.classList.add(IS_VALID);
|
||||
}
|
||||
nodes.forEach((node) => node.classList.remove('current-node'));
|
||||
if (state in nodes) {
|
||||
nodes[state].classList.add('current-node');
|
||||
graph.forEach((node) => node.active = false);
|
||||
if (state in graph.nodes) {
|
||||
graph.nodes[state].active = true;
|
||||
}
|
||||
viewer.restart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user