Skip to content

VisState & Graph types

Madita Antonia Plogsties edited this page Mar 31, 2025 · 23 revisions

title: 'Algorithm Interfaces: Algorithm Stores & Visualisation States'

Overview

To visualise the algorithms in the Typescript "frontend" and communicate with the Rust "backend", algorithms/algorithm-interfaces.ts defines different interfaces. Every algorithm has a file config.ts located in `src/algorithms//. In it the general interfaces are extended to be more algorithm specific.

Key Components

1. IVisualisationState

Represents the current state of an algorithm's execution, providing information on:

  • lineOfCode: The current line of the algorithm being executed.
  • variables: A dictionary holding algorithm-specific variable states.
  • helptext: An explanation for the current step of the algorithm.

This interface can be extended for the specific algorithm, for example the PrimVisualisationState extends it with a start-node, arrays for the current tree-nodes, tree-edges and outgoing edges and the current optimal outgoing edge.

2. IAlgorithmStore

The core interface for managing algorithm execution and visualization. It includes:

State Management

  • visState: Stores the internal visualisation state (in unconverted Rust data type!). Do not use directly! see getVisState instead!
  • isInitialized: Indicates the module has been loaded. Always make sure it initialized before using any of the functions below otherwise their values will be null or errornous!
  • getVisState: Get the current visState to give it the Visualiser
  • nextStep(): Advance a single step in the algorithm (equates to one line of the pseudo code). Just like all the other functions that return void, this will update visState property, thus rerendering the parent component automatically.
  • prevStep(): Reverts to the previous step.
  • resetGraph(): Resets the graph to its initial state.
  • initialGraph: Stores the original graph before any steps were executed.
Graph Management
  • setGraph: (graph: Graph, startNode?: number) => void: set the graph for the algorithm to operate on. If startNode is not set, it will choose the first node it finds (graph.nodes[0]).
  • getExampleGraph(id): Retrieves a predefined example graph from the backend.
  • numberOfGraphs: Tracks the number of graphs managed.

Configuration & Layout

  • config: Stores visual configurations, such as edge colors.
  • setConfig(config): Updates visualization settings.
  • applyLayout(layout): Applies a specific graph layout algorithm.
  • layoutAlgorithm: Defines the layout algorithm to be applied.
  • layoutGraph: Graph containing layout information

The algorithm specific extensions for the Algorithm store can be found in the algorithms store.ts file, and just specifies the types of visState and config to be the algorithm specific ones. This could maybe be improved by using generics in IAlgorithmStore

Since this is a zustand store, values persist page navigation. This allows us to easily bring the graph designed on the GraphPage to the AlgorithmPage or vice versa to make adjustments.

The store will always update the parent component if a value inside updates. This may have unwanted side effects. See this example:

const MyComponent = () => {
    const store = useDijkstraStore();

    return (store.isInitialized 
        ? <div>{store.pseudoCode}</div>
        : <div>loading...</div>
    );
}

Here the component updates if for example visState is updated, even though we only care about the pseudoCode, which is usually static. To mitigate this behavior, we need to let zustand know we only care about pseudoCode:

const MyComponent = () => {
    const pseudoCode = useDijkstraStore((state) => state.pseudoCode);
    const isInitialized = useDijkstraStore((state) => state.isInitialized);

    return (isInitialized 
        ? <div>{pseudoCode}</div>
        : <div>loading...</div>
    );
}

We can also combine the two usedijkstraStore calls like this (recommended):

const MyComponent = () => {
    const { pseudoCode, isInitialized } = useDijkstraStore((state) => ({
        pseudoCode: state.pseudoCode,
        isInitialized: state.isInitialized
    });

    return (isInitialized 
        ? <div>{pseudoCode}</div>
        : <div>loading...</div>
    );
}

3. The Remaining Interfaces

  • IConfig: Extends GraphinProps to store additional visualization settings (right now just color)
  • IGraphGeneratorOptions: Used for graph generations (partially set in the algorithm specific config.ts files)
  • ILayoutAlgorithm: To keep track of the chosen layout algorithm.

Rust VisualisationState

The rust code keeps track of Visualisation States, analogous to the ones described here. The communication between these two happens through the Adapter

Clone this wiki locally