-
+
+
-
@_mermaidDefinition
}
@code {
- private string _mermaidDefinition = string.Empty;
+ private NetworkData? _networkData;
private bool _isLoading = true;
protected override async Task OnInitializedAsync()
@@ -55,7 +55,7 @@ else
private async Task LoadDataAsync()
{
_isLoading = true;
-
+
try
{
var events = await Context.Events
@@ -71,7 +71,7 @@ else
if (eventsWithFields.Any())
{
- _mermaidDefinition = GenerateMermaidDiagram(eventsWithFields);
+ _networkData = GenerateNetworkData(eventsWithFields);
}
}
finally
@@ -80,16 +80,16 @@ else
}
}
- private string GenerateMermaidDiagram(List
events)
+ private NetworkData GenerateNetworkData(List events)
{
- var builder = new System.Text.StringBuilder();
- builder.AppendLine("graph LR");
+ var nodes = new List();
+ var edges = new List();
- // Dictionary to track node IDs and labels (to avoid duplicates)
- var eventNodeIds = new Dictionary();
- var fieldNodeIds = new Dictionary();
- var fieldCounter = 1;
+ // Dictionary to track node IDs (to avoid duplicates)
+ var eventNodeIds = new Dictionary();
+ var fieldNodeIds = new Dictionary();
var eventCounter = 1;
+ var fieldCounter = 1;
// Dictionary to track which events connect to which career fields
var eventToFields = new Dictionary>();
@@ -100,8 +100,17 @@ else
if (!eventNodeIds.ContainsKey(evt.Id))
{
var eventNodeId = $"E{eventCounter++}";
- var eventLabel = EscapeMermaidLabel(evt.Name);
- eventNodeIds[evt.Id] = (eventNodeId, eventLabel);
+ eventNodeIds[evt.Id] = eventNodeId;
+
+ // Add event node (blue)
+ nodes.Add(new Node
+ {
+ Id = eventNodeId,
+ Label = evt.Name,
+ Color = new NodeColorType { Background = "#90C3F5", Border = "#7DB3F0" },
+ Shape = "box",
+ Size = 25
+ });
}
// Get related career fields for this event's careers
@@ -110,65 +119,70 @@ else
{
eventToFields[evt.Id] = new HashSet(relatedFields);
- // Track career field nodes
+ // Track and add career field nodes
foreach (var field in relatedFields)
{
if (!fieldNodeIds.ContainsKey(field.Id))
{
var fieldNodeId = $"F{fieldCounter++}";
- var fieldLabel = EscapeMermaidLabel(field.Name);
- fieldNodeIds[field.Id] = (fieldNodeId, fieldLabel);
+ fieldNodeIds[field.Id] = fieldNodeId;
+
+ // Add career field node (green)
+ nodes.Add(new Node
+ {
+ Id = fieldNodeId,
+ Label = field.Name,
+ Color = new NodeColorType
+ {
+ Background = "#90F8B0",
+ Border = "#80E8A0",
+ Highlight = new NodeColorType.BorderBackgroundColor { Background = "#90F8B0", Border = "#80E8A0" }
+ },
+ Shape = "box",
+ Size = 20
+ });
}
}
}
}
- // Second pass: define all event nodes (blue)
- foreach (var (id, (nodeId, label)) in eventNodeIds.OrderBy(e => e.Value.Label))
- {
- builder.AppendLine($" {nodeId}[\"{label}\"]:::eventNode");
- }
-
- // Third pass: define all career field nodes (green)
- foreach (var (id, (nodeId, label)) in fieldNodeIds.OrderBy(f => f.Value.Label))
- {
- builder.AppendLine($" {nodeId}[\"{label}\"]:::fieldNode");
- }
-
- // Fourth pass: define all edges (events on left, fields on right)
+ // Second pass: create edges from events to career fields
foreach (var evt in events.OrderBy(e => e.Name))
{
if (eventToFields.TryGetValue(evt.Id, out var fields))
{
- var currentEventNodeId = eventNodeIds[evt.Id].Id;
+ var eventNodeId = eventNodeIds[evt.Id];
foreach (var field in fields.OrderBy(f => f.Name))
{
- var currentFieldNodeId = fieldNodeIds[field.Id].Id;
- builder.AppendLine($" {currentEventNodeId} --> {currentFieldNodeId}");
+ var fieldNodeId = fieldNodeIds[field.Id];
+ edges.Add(new Edge
+ {
+ From = eventNodeId,
+ To = fieldNodeId
+ });
}
}
}
- // Add styling for different colors
- builder.AppendLine("");
- builder.AppendLine("classDef eventNode fill:#4A90E2,stroke:#2E5C8A,stroke-width:2px,color:#fff");
- builder.AppendLine("classDef fieldNode fill:#50C878,stroke:#2D8659,stroke-width:2px,color:#fff");
-
- return builder.ToString();
+ return new NetworkData
+ {
+ Nodes = nodes,
+ Edges = edges
+ };
}
- private string EscapeMermaidLabel(string label)
+ private NetworkOptions GetNetworkOptions(Network network)
{
- if (string.IsNullOrEmpty(label))
- return string.Empty;
-
- // Escape quotes and other special characters for Mermaid labels
- return label
- .Replace("\"", """)
- .Replace("\n", " ")
- .Replace("\r", " ")
- .Trim();
+ return new NetworkOptions
+ {
+ AutoResize = true,
+ Physics = new PhysicsOptions
+ {
+ Enabled = true
+ },
+ Height = "600px"
+ };
}
-}
+}
\ No newline at end of file
diff --git a/WebApp/Components/_Imports.razor b/WebApp/Components/_Imports.razor
index 0ad4ad2..39e4dc2 100644
--- a/WebApp/Components/_Imports.razor
+++ b/WebApp/Components/_Imports.razor
@@ -26,4 +26,4 @@
@using MudBlazor
@using Core.Entities
@using Data
-@using Blazorade.Mermaid.Components
+@using VisNetwork.Blazor
diff --git a/WebApp/Program.cs b/WebApp/Program.cs
index 7fbd1bf..7820822 100644
--- a/WebApp/Program.cs
+++ b/WebApp/Program.cs
@@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
using MudBlazor.Services;
using Serilog;
using System.Text.Json;
+using VisNetwork.Blazor;
using WebApp;
using WebApp.Authentication;
using WebApp.Components;
@@ -118,6 +119,7 @@ builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddMudServices();
+builder.Services.AddVisNetwork();
// Configure Data Protection to persist keys across container restarts
var keysPath = Path.Combine(builder.Environment.ContentRootPath, "DataProtectionKeys");
diff --git a/WebApp/WebApp.csproj b/WebApp/WebApp.csproj
index 6a8184c..d7933df 100644
--- a/WebApp/WebApp.csproj
+++ b/WebApp/WebApp.csproj
@@ -14,8 +14,8 @@
-
+