Creating a Step-by-Step Graph Animation
This guide provides comprehensive standards and patterns for creating interactive step-by-step graph algorithm visualizations using p5.js. These MicroSims allow students to understand algorithms by watching them execute one step at a time or running automatically at a controlled speed.
Overview
Step-by-step graph animations are powerful teaching tools that help students:
- Visualize how graph algorithms make decisions
- Understand the order of operations
- See which elements are being considered, accepted, or rejected
- Track algorithm progress through a visual log
- Control the pace of learning through manual stepping or auto-run
The key insight behind these visualizations is that algorithms are easier to understand when you can see each decision being made. Rather than showing only the final result, we reveal the process—showing students why certain edges are chosen and others rejected.
Standard MicroSim Layout
The recommended layout divides the canvas into distinct functional areas. This consistent structure helps students quickly orient themselves when using different algorithm visualizations.
Run the Graph Tutorial Layout Fullscreen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
The graph visualization occupies the left portion where students can see nodes and edges change state as the algorithm progresses. The step log on the right provides a textual record of each decision, allowing students to review the algorithm's history. The control panel at the bottom gives students complete control over execution.
Layout Proportions
These proportions have been tested to provide good visual balance across different screen sizes:
| Area | Position | Size |
|---|---|---|
| Graph Center | canvasWidth * 0.34 |
Left portion |
| Step Log | canvasWidth * 0.67 |
Right 30% |
| Drawing Area | Top | drawHeight (500px default) |
| Control Panel | Bottom | controlHeight (150px default) |
Canvas Structure
Dimension Variables
We begin by defining global variables that control the canvas layout. Keeping these as variables (rather than hard-coded values) makes the visualization responsive and easy to adjust.
1 2 3 4 5 6 7 8 | |
The drawHeight separates the visualization area from the controls. The controlHeight provides space for buttons, sliders, and status text. The margin and sliderLeftMargin ensure consistent spacing throughout the interface.
Setup Function
The setup() function runs once when the page loads. It's responsible for creating the canvas, initializing the graph data, and creating the UI controls.
1 2 3 4 5 6 7 8 9 10 | |
Notice that we call updateCanvasSize() before creating the canvas. This ensures our canvas matches the container width for responsive design. The describe() function provides accessibility support for screen readers.
Draw Function Structure
The draw() function is called repeatedly by p5.js (typically 60 times per second). It's responsible for rendering the current state of the visualization and checking if it's time to execute the next algorithm step during auto-run mode.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
The draw function follows a consistent pattern:
- Clear and set up backgrounds - We draw the aliceblue drawing area and white control area fresh each frame
- Draw the title - Centered at the top of the canvas
- Reset drawing settings - Ensure consistent defaults before drawing components
- Draw graph components - Edges first (so they appear behind nodes), then nodes, then the step log
- Handle auto-run timing - Check if enough time has passed to execute the next step
- Draw control labels - Status text and slider labels in the control area
Data Structures
Graph Representation
The graph is stored using simple JavaScript arrays and objects. This approach is easy to understand and manipulate, making it ideal for educational purposes.
1 2 3 4 5 6 | |
Each node contains its position, identifier, and display label:
1 2 3 4 5 6 7 | |
The id is used internally to reference nodes in edges. The x and y coordinates determine where the node is drawn. The label (typically a letter A-H) is displayed to the user.
Each edge connects two nodes and tracks its current state in the algorithm:
1 2 3 4 5 6 7 | |
The state property is crucial for visualization. As the algorithm runs, edges transition through states: they start as 'available', may briefly be 'considering' while being evaluated, and end up either 'accepted' (included in the result) or 'rejected' (excluded). Each state is rendered with a different color.
Algorithm State Variables
Beyond the graph data, we need variables to track the algorithm's execution state:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
These variables serve different purposes:
currentAlgorithm- Allows switching between multiple algorithms (e.g., Kruskal's vs. Prim's)animationSpeed- Controls the delay between steps during auto-run (in milliseconds)isRunning- True when auto-run is active, false when paused or stepping manuallyisComplete- True when the algorithm has finished (prevents further steps)stepIndex- Tracks progress through the algorithm's work queueconsideredElement- The edge currently being evaluated (highlighted in yellow)stepDescription- Human-readable text explaining the current/last stepstepLog- Array of all steps for display in the log panel
UI Controls
Control Creation
The control panel provides four buttons and a slider. Each control is created using p5.js DOM functions and positioned absolutely within the canvas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |
Algorithm Selector: A dropdown that lets users choose between algorithms. When changed, it resets the visualization to start fresh with the new algorithm.
Step Forward Button: Executes exactly one step of the algorithm. This is essential for detailed study—students can carefully examine each decision.
Auto Run Button: Toggles between automatic execution and paused state. The button label changes to "Pause" when running.
Reset Button: Generates a new random graph and resets all algorithm state. This lets students see the algorithm work on different inputs.
Speed Slider: Controls the delay between auto-run steps. Notice the inversion logic: we want "Slower" on the left (intuitive), but higher delay values mean slower animation. The formula 2100 - sliderValue converts the slider's 100-2000 range into a 2000-100ms delay range.
Auto-Run Toggle
The auto-run toggle function manages the running state and updates the button label to reflect the current mode:
1 2 3 4 5 6 7 8 9 10 | |
When starting auto-run, we record the current time in lastStepTime. This ensures the first step doesn't execute immediately—it waits for the full animationSpeed delay, giving students time to observe the initial state.
Control Labels
The control panel needs text labels to explain the slider and show current status. This function draws those labels, being careful to reset text alignment after drawing positioned labels.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Important: After drawing the right-aligned "Faster" label, we must reset textAlign back to LEFT, CENTER. Forgetting this will cause the status text to render off-screen. This is a common p5.js pitfall—drawing state persists between calls.
Step Execution Pattern
The step execution pattern is the heart of the visualization. It separates the concerns of when to execute (timing/UI) from what to execute (algorithm logic).
Main Execution Function
This function acts as a dispatcher, routing to the appropriate algorithm and checking for completion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
The early return on isComplete prevents any action after the algorithm finishes. After executing a step, we check if the algorithm is now complete (e.g., MST has n-1 edges). If so, we update the UI state and log the completion.
Algorithm Step Function Template
Each algorithm step follows a consistent pattern: get the next element to consider, evaluate it, and either accept or reject it. This template can be adapted for any greedy graph algorithm:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
The key educational value comes from the branching logic. Students see clearly that the algorithm makes a binary decision for each element: accept or reject. The stepDescription provides detailed context, while the stepLog entry provides a concise record.
For Kruskal's algorithm, the acceptance criterion is "does this edge create a cycle?" (using union-find). For Prim's algorithm, it's "does this edge connect a visited node to an unvisited node?"
Reset Function
The reset function restores all state to initial values, preparing for a fresh run:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Notice that we reset both the general state (arrays, flags) and the visual state (edge states back to 'available'). The initializeAlgorithmState() call handles algorithm-specific setup—for Kruskal's, this sorts edges by weight and initializes union-find; for Prim's, it marks the starting node as visited and populates the priority queue.
Visual Styling
Node Drawing
Nodes are drawn as colored circles with letter labels. The color indicates state—particularly useful for algorithms like Prim's where "visited" status matters.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
We draw nodes after edges so they appear on top, covering the edge lines where they connect. The steel blue default color provides good contrast with the white labels and distinguishes nodes from edge weight labels.
Edge Drawing
Edges require more complex rendering: the line itself, and a label showing the weight. The visual treatment varies dramatically based on edge state, providing immediate feedback about the algorithm's decisions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |
The visual hierarchy is important:
- Gold (accepted): Bright and thick—these edges are the result
- Yellow (considering): Draws attention to the current decision
- Gray (available): Neutral, waiting to be evaluated
- Light gray (rejected): Faded and thin—de-emphasized but still visible
For weight labels, we use a fitted rectangle rather than a fixed-size circle. This accommodates different weight values (single digits vs. three digits) and provides a cleaner look.
Color Standards
Consistent colors across all algorithm visualizations help students transfer their understanding:
| Element State | Color | RGB Value |
|---|---|---|
| Node default | Steel blue | (70, 130, 180) |
| Node visited | Light green | (100, 200, 100) |
| Edge default | Gray | (128, 128, 128) |
| Edge accepted | Gold | (255, 215, 0) |
| Edge rejected | Light gray | (200, 200, 200) |
| Edge considering | Yellow | (255, 255, 0) |
| Edge label bg | Aliceblue | (240, 248, 255) |
Step Log
The step log provides a running history of algorithm decisions. This is valuable for several reasons:
- Students can review earlier decisions without having to restart
- The log makes the algorithm's decision pattern visible
- Color coding reinforces which actions were accepts vs. rejects
- The completion marker provides clear feedback when done
Log Data Structure
Each log entry is a simple object with a type (for coloring) and display text:
1 2 3 4 5 6 7 | |
The text includes Unicode symbols (✓, ✗, ★) for quick visual scanning. Keep the text concise—the log panel has limited width.
Drawing the Step Log
The log panel is drawn as a semi-transparent white rectangle with a list of entries. When there are more entries than fit, it automatically scrolls to show the most recent.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
The auto-scroll logic (startIndex = max(0, stepLog.length - maxVisible)) ensures that when the log fills up, older entries scroll off the top while the most recent entries remain visible. Entry numbers are preserved so students can reference specific steps.
Log Entry Types and Symbols
| Type | Symbol | Color | Usage |
|---|---|---|---|
| Accepted | ✓ | Forest green | Element added to result |
| Rejected | ✗ | Firebrick red | Element skipped/rejected |
| Complete | ★ | Dark goldenrod | Algorithm finished |
Responsive Design
The visualization should adapt to different screen sizes, particularly for embedding in course materials or viewing on tablets.
Window Resize Handler
When the browser window resizes, we need to update the canvas and reposition elements:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Nodes are arranged in a circle, so we recalculate their positions using polar coordinates. The center point and radius are based on the new canvas width, keeping the graph properly positioned in the left portion of the canvas.
1 2 3 4 5 6 7 8 9 10 11 | |
The updateCanvasSize() function reads the container width and updates the slider to stretch accordingly. This function is called both on resize and at the start of each draw() frame to handle container changes.
Best Practices
1. Clear Visual Feedback
Students should never wonder "what just happened?" Use distinct colors for different states, make transitions visible, and always highlight the element currently being considered.
- Use distinct colors for different states
- Animate transitions between states when possible
- Highlight the currently considered element
2. Informative Status Messages
The status text should tell a complete story. Don't just say "edge rejected"—explain why. For Kruskal's: "would create cycle." For Prim's: "both nodes already visited."
- Explain what happened in each step
- Include relevant values (weights, counts)
- State why elements were rejected
3. Accessible Controls
Place frequently used controls (Step, Auto Run) prominently. Use intuitive labels—"Slower/Faster" communicates better than raw millisecond values. Provide both manual and automatic modes to accommodate different learning styles.
- Place frequently used controls prominently
- Use intuitive labels ("Slower" / "Faster" not just values)
- Provide both manual and automatic modes
4. Educational Value
The goal is learning, not just demonstration. Show intermediate states so students can pause and think. Log all decisions so students can review. Let students control the pace—some need more time than others.
- Show intermediate state, not just final result
- Log all decisions for review
- Allow students to control the pace
5. Consistent Layout
When students use multiple algorithm visualizations, consistency reduces cognitive load. They can focus on the algorithm differences rather than relearning the interface.
- Follow the standard layout across all algorithm visualizations
- Use consistent color schemes
- Maintain the same control positions
Example: Adapting for Different Algorithms
This pattern can be adapted for various graph algorithms:
- Minimum Spanning Tree: Kruskal's, Prim's
- Shortest Path: Dijkstra's, Bellman-Ford
- Graph Traversal: BFS, DFS
- Network Flow: Ford-Fulkerson
- Matching: Hungarian algorithm
For each algorithm, modify:
- The
executeAlgorithmStep()function - Implement the algorithm's core logic for selecting and evaluating elements - The acceptance/rejection criteria - Define what makes an element valid for inclusion
- The step log messages - Write clear, educational explanations for each decision
- Any algorithm-specific state variables - Add data structures the algorithm needs (priority queues, distance arrays, etc.)
- Node/edge coloring based on algorithm state - Decide what states are meaningful to visualize
Reference Implementation
See the complete Minimum Spanning Tree MicroSim at:
docs/sims/minimum-spanning-tree/minimum-spanning-tree.js
This implementation demonstrates all the patterns described in this guide with both Kruskal's and Prim's algorithms. Study the code to see how the abstract patterns translate into working visualization code.