SpawnDev.BlazorJS.VisNetwork 2.0.0

dotnet add package SpawnDev.BlazorJS.VisNetwork --version 2.0.0
                    
NuGet\Install-Package SpawnDev.BlazorJS.VisNetwork -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SpawnDev.BlazorJS.VisNetwork" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SpawnDev.BlazorJS.VisNetwork" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SpawnDev.BlazorJS.VisNetwork" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SpawnDev.BlazorJS.VisNetwork --version 2.0.0
                    
#r "nuget: SpawnDev.BlazorJS.VisNetwork, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SpawnDev.BlazorJS.VisNetwork@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SpawnDev.BlazorJS.VisNetwork&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SpawnDev.BlazorJS.VisNetwork&version=2.0.0
                    
Install as a Cake Tool

SpawnDev.BlazorJS.VisNetwork

NuGet

SpawnDev.BlazorJS.VisNetwork is a Blazor WebAssembly wrapper for vis-network, a powerful JavaScript library for creating interactive network visualizations with nodes and edges.

Features

  • ✅ Full Blazor WebAssembly support for .NET 8, 9, and 10
  • ✅ Strongly-typed C# API for vis-network
  • ✅ Interactive network graphs with customizable nodes and edges
  • ✅ Support for clustering, hierarchical layouts, and physics simulations
  • ✅ Event handling for user interactions
  • ✅ Comprehensive configuration options
  • ✅ Built on SpawnDev.BlazorJS for seamless JavaScript interop

Installation

Install the package via NuGet:

dotnet add package SpawnDev.BlazorJS.VisNetwork

Or via the NuGet Package Manager:

Install-Package SpawnDev.BlazorJS.VisNetwork

Getting Started

1. Register Services

In your Program.cs, add the required services:

using SpawnDev.BlazorJS;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");

// Add BlazorJS services
builder.Services.AddBlazorJSRuntime();

// Initialize BlazorJS by calling BlazorJSRunAsync instead of RunAsync
await builder.Build().BlazorJSRunAsync();

2. Basic Usage

Create a simple network visualization in your Blazor component:

@page "/network"
@using SpawnDev.BlazorJS.VisNetwork

<div style="width: 100%; height: 600px;">
    <VisNetworkView OnReady="OnNetworkReady" Style="width: 100%; height: 100%;" />
</div>

@code {
    void OnNetworkReady(VisNetworkView visNetwork)
    {
        visNetwork.Nodes!.Add(new List<VisNode>
        {
            new VisNode { Id = "1", Label = "Node 1" },
            new VisNode { Id = "2", Label = "Node 2" },
            new VisNode { Id = "3", Label = "Node 3" },
            new VisNode { Id = "4", Label = "Node 4" },
            new VisNode { Id = "5", Label = "Node 5" }
        });

        visNetwork.Edges!.Add(new List<VisEdge>
        {
            new VisEdge { From = "1", To = "3" },
            new VisEdge { From = "1", To = "2" },
            new VisEdge { From = "2", To = "4" },
            new VisEdge { From = "2", To = "5" },
            new VisEdge { From = "3", To = "5" }
        });
    }
}

Advanced Examples

Styled Nodes and Edges

Customize the appearance of nodes and edges:

void OnNetworkReady(VisNetworkView visNetwork)
{
    visNetwork.Nodes!.Add(new List<VisNode>
    {
        new VisNode 
        { 
            Id = "1", 
            Label = "Server",
            Shape = "box",
            Color = new VisNodeColor 
            { 
                Background = "#97C2FC", 
                Border = "#2B7CE9" 
            },
            Font = new VisFont { Color = "#000000", Size = 14 }
        },
        new VisNode 
        { 
            Id = "2", 
            Label = "Database",
            Shape = "database",
            Color = new VisNodeColor { Background = "#FFA500" },
            Size = 30
        },
        new VisNode 
        { 
            Id = "3", 
            Label = "Client",
            Shape = "circle",
            Color = new VisNodeColor { Background = "#7BE141" }
        }
    });

    visNetwork.Edges!.Add(new List<VisEdge>
    {
        new VisEdge 
        { 
            From = "1", 
            To = "2",
            Label = "Query",
            Arrows = new VisEdgeArrows { To = new VisEdgeArrowConfig { Enabled = true } },
            Color = new VisEdgeColor { Color = "#848484" },
            Width = 2,
            Dashes = true
        },
        new VisEdge 
        { 
            From = "3", 
            To = "1",
            Label = "Request",
            Arrows = new VisEdgeArrows { To = new VisEdgeArrowConfig { Enabled = true } },
            Smooth = true
        }
    });
}

Hierarchical Layout

Create a hierarchical network layout:

<VisNetworkView OnReady="OnNetworkReady" Options="@options" Style="width: 100%; height: 100%;" />

@code {
    NetworkOptions options = new NetworkOptions
    {
        Physics = new PhysicsOptions
        {
            Enabled = false
        }
    };

    void OnNetworkReady(VisNetworkView visNetwork)
    {
        // Add nodes in a hierarchical structure
        visNetwork.Nodes!.Add(new List<VisNode>
        {
            new VisNode { Id = "1", Label = "Root", Level = 0 },
            new VisNode { Id = "2", Label = "Child 1", Level = 1 },
            new VisNode { Id = "3", Label = "Child 2", Level = 1 },
            new VisNode { Id = "4", Label = "Grandchild 1", Level = 2 },
            new VisNode { Id = "5", Label = "Grandchild 2", Level = 2 }
        });

        visNetwork.Edges!.Add(new List<VisEdge>
        {
            new VisEdge { From = "1", To = "2" },
            new VisEdge { From = "1", To = "3" },
            new VisEdge { From = "2", To = "4" },
            new VisEdge { From = "3", To = "5" }
        });
    }
}

Event Handling

Using VisNetworkView Component Events

Handle user interactions using the VisNetworkView component's event parameters:

<VisNetworkView 
    OnReady="OnNetworkReady" 
    OnClick="OnNetworkClick"
    OnDoubleClick="OnNetworkDoubleClick"
    OnSelectNode="OnNodeSelected"
    OnHoverNode="OnNodeHover"
    Style="width: 100%; height: 100%;" />

@code {
    void OnNetworkReady(VisNetworkView visNetwork)
    {
        // Add your nodes and edges
    }

    void OnNetworkClick(NetworkEvent e)
    {
        Console.WriteLine($"Clicked at position: {e.Pointer.Canvas.X}, {e.Pointer.Canvas.Y}");
        if (e.Nodes.Length > 0)
        {
            Console.WriteLine($"Clicked node: {e.Nodes[0]}");
        }
    }

    void OnNetworkDoubleClick(NetworkEvent e)
    {
        Console.WriteLine($"Double-clicked");
    }

    void OnNodeSelected(NetworkSelectEvent e)
    {
        Console.WriteLine($"Selected nodes: {string.Join(", ", e.Nodes)}");
    }

    void OnNodeHover(NetworkFocusEvent e)
    {
        Console.WriteLine($"Hovering over node: {e.Node}");
    }
}
Using Network ActionEvent Properties (Preferred for Direct Network Access)

When working with the Network object directly, use the strongly-typed ActionEvent properties with += and -= operators:

<VisNetworkView OnReady="OnNetworkReady" Style="width: 100%; height: 100%;" />

@code {
    Network? network;

    void OnNetworkReady(VisNetworkView visNetwork)
    {
        network = visNetwork.Network;

        // Attach event handlers using ActionEvent properties
        network.OnClick += HandleClick;
        network.OnDoubleClick += HandleDoubleClick;
        network.OnSelectNode += HandleNodeSelect;
        network.OnHoverNode += HandleNodeHover;
        network.OnZoom += HandleZoom;

        // Add your nodes and edges
    }

    void HandleClick(NetworkEvent e)
    {
        Console.WriteLine($"Clicked at position: {e.Pointer.Canvas.X}, {e.Pointer.Canvas.Y}");
        if (e.Nodes.Length > 0)
        {
            Console.WriteLine($"Clicked node: {e.Nodes[0]}");
        }
    }

    void HandleDoubleClick(NetworkEvent e)
    {
        Console.WriteLine($"Double-clicked");
    }

    void HandleNodeSelect(NetworkSelectEvent e)
    {
        Console.WriteLine($"Selected nodes: {string.Join(", ", e.Nodes)}");
    }

    void HandleNodeHover(NetworkFocusEvent e)
    {
        Console.WriteLine($"Hovering over node: {e.Node}");
    }

    void HandleZoom(NetworkZoomEvent e)
    {
        Console.WriteLine($"Zoom scale: {e.Scale}, Direction: {e.Direction}");
    }

    public void Dispose()
    {
        if (network != null)
        {
            // Detach event handlers to prevent memory leaks
            network.OnClick -= HandleClick;
            network.OnDoubleClick -= HandleDoubleClick;
            network.OnSelectNode -= HandleNodeSelect;
            network.OnHoverNode -= HandleNodeHover;
            network.OnZoom -= HandleZoom;
            network.Dispose();
        }
    }
}

Important: Always use the ActionEvent properties (e.g., OnClick, OnDoubleClick) with += and -= operators instead of string-based event methods like On("click", callback) or Once("click", callback). The ActionEvent pattern provides strong typing, automatic reference management, and cleaner syntax.

Dynamic Data Updates

Add, update, and remove nodes and edges dynamically:

<button @onclick="AddNode">Add Node</button>
<button @onclick="UpdateNode">Update Node</button>
<button @onclick="RemoveNode">Remove Node</button>
<button @onclick="AddEdge">Add Edge</button>

<VisNetworkView OnReady="OnNetworkReady" Style="width: 100%; height: 400px;" />

@code {
    VisNetworkView? networkView;
    int nodeCounter = 6;

    void OnNetworkReady(VisNetworkView visNetwork)
    {
        networkView = visNetwork;

        visNetwork.Nodes!.Add(new List<VisNode>
        {
            new VisNode { Id = "1", Label = "Node 1" },
            new VisNode { Id = "2", Label = "Node 2" },
            new VisNode { Id = "3", Label = "Node 3" }
        });

        visNetwork.Edges!.Add(new List<VisEdge>
        {
            new VisEdge { From = "1", To = "2" },
            new VisEdge { From = "2", To = "3" }
        });
    }

    void AddNode()
    {
        var newId = nodeCounter++.ToString();
        networkView?.Nodes?.Add(new VisNode 
        { 
            Id = newId, 
            Label = $"Node {newId}",
            X = 0,
            Y = 0
        });
    }

    void UpdateNode()
    {
        networkView?.Nodes?.Update(new VisNode 
        { 
            Id = "1",
            Label = "Updated Node",
            Color = new VisNodeColor { Background = "#FF0000" }
        });
    }

    void RemoveNode()
    {
        networkView?.Nodes?.Remove("3");
    }

    void AddEdge()
    {
        networkView?.Edges?.Add(new VisEdge 
        { 
            From = "1",
            To = "3"
        });
    }
}

Clustering

Group nodes together using clustering:

void OnNetworkReady(VisNetworkView visNetwork)
{
    // Add nodes with groups
    visNetwork.Nodes!.Add(new List<VisNode>
    {
        new VisNode { Id = "1", Label = "Server 1", Group = "servers" },
        new VisNode { Id = "2", Label = "Server 2", Group = "servers" },
        new VisNode { Id = "3", Label = "Server 3", Group = "servers" },
        new VisNode { Id = "4", Label = "Client 1", Group = "clients" },
        new VisNode { Id = "5", Label = "Client 2", Group = "clients" }
    });

    visNetwork.Edges!.Add(new List<VisEdge>
    {
        new VisEdge { From = "4", To = "1" },
        new VisEdge { From = "5", To = "2" },
        new VisEdge { From = "1", To = "2" },
        new VisEdge { From = "2", To = "3" }
    });

    // Cluster nodes by group
    // Note: Use Network API directly for advanced clustering
    // visNetwork.Network?.Cluster(clusterOptions);
}

Physics Simulation

Control the physics simulation:

<button @onclick="TogglePhysics">Toggle Physics</button>
<button @onclick="Stabilize">Stabilize</button>

<VisNetworkView OnReady="OnNetworkReady" Options="@options" Style="width: 100%; height: 400px;" />

@code {
    VisNetworkView? networkView;
    bool physicsEnabled = true;

    NetworkOptions options = new NetworkOptions
    {
        Physics = new PhysicsOptions
        {
            Enabled = true,
            BarnesHut = new BarnesHutPhysicsOptions
            {
                GravitationalConstant = -2000,
                CentralGravity = 0.3,
                SpringLength = 95,
                SpringConstant = 0.04,
                Damping = 0.09,
                AvoidOverlap = 0.1
            },
            MaxVelocity = 50,
            MinVelocity = 0.1,
            Solver = "barnesHut",
            TimeStep = 0.5
        }
    };

    void OnNetworkReady(VisNetworkView visNetwork)
    {
        networkView = visNetwork;
        // Add your nodes and edges
    }

    void TogglePhysics()
    {
        physicsEnabled = !physicsEnabled;
        networkView?.Network?.SetOptions(new NetworkOptions 
        { 
            Physics = new PhysicsOptions { Enabled = physicsEnabled } 
        });
    }

    void Stabilize()
    {
        networkView?.Network?.Stabilize();
    }
}

Network Methods

The Network class provides many useful methods:

// Selection
var selectedNodes = networkView.Network?.GetSelectedNodes();
var selectedEdges = networkView.Network?.GetSelectedEdges();
networkView.Network?.SelectNodes(new[] { "1", "2", "3" });
networkView.Network?.UnselectAll();

// View control
networkView.Network?.Fit(); // Zoom to fit all nodes
networkView.Network?.Focus("nodeId", new FocusOptions { Scale = 1.5, Animation = true });
networkView.Network?.MoveTo(new MoveToOptions 
{ 
    Position = new Position { X = 0, Y = 0 },
    Scale = 1.0,
    Animation = true
});

// Data access
var nodePositions = networkView.Network?.GetPositions();
var nodePosition = networkView.Network?.GetPosition("nodeId");
var boundingBox = networkView.Network?.GetBoundingBox("nodeId");
var connectedNodes = networkView.Network?.GetConnectedNodes("nodeId");
var connectedEdges = networkView.Network?.GetConnectedEdges("nodeId");

// Physics
networkView.Network?.StartSimulation();
networkView.Network?.StopSimulation();
networkView.Network?.Stabilize();

// Canvas
networkView.Network?.Redraw();
networkView.Network?.SetSize("800px", "600px");

Configuration Options

The library supports extensive configuration through the NetworkOptions class:

  • Nodes: Shape, size, color, font, borders, shadows, and more
  • Edges: Width, color, arrows, dashes, smooth curves, and labels
  • Layout: Hierarchical, random, or custom positioning
  • Physics: Barnes-Hut, force atlas, repulsion, and stabilization
  • Interaction: Hover, selection, drag, zoom, and keyboard controls
  • Manipulation: Add, edit, and delete nodes/edges through UI

Examples Repository

For more examples, check out the examples project in this repository.

Documentation

Requirements

  • .NET 8, 9, or 10
  • Blazor WebAssembly
  • SpawnDev.BlazorJS

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Credits

Support

If you encounter any issues or have questions:

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 35 2/12/2026
1.9.0 118 1/21/2026
1.8.2 423 11/19/2025
1.8.1 416 11/19/2025
1.7.0 225 11/2/2025
1.6.0 172 10/3/2025
1.5.1 237 12/5/2024
1.5.0 175 10/11/2024
1.4.1 163 7/26/2024
1.4.0 153 7/26/2024
1.3.0 178 7/17/2024
1.2.0 171 6/12/2024
1.1.2 182 4/29/2024
1.1.0 190 4/29/2024
1.0.3 179 4/29/2024
1.0.2 197 4/16/2024
1.0.1 230 3/29/2024
1.0.0 204 3/26/2024