diff --git a/src/components/BootstrapBlazor.Graph/BootstrapBlazor.Graph.csproj b/src/components/BootstrapBlazor.NodeGraph/BootstrapBlazor.NodeGraph.csproj
similarity index 82%
rename from src/components/BootstrapBlazor.Graph/BootstrapBlazor.Graph.csproj
rename to src/components/BootstrapBlazor.NodeGraph/BootstrapBlazor.NodeGraph.csproj
index 2cc4cef0..9c2cf8a5 100644
--- a/src/components/BootstrapBlazor.Graph/BootstrapBlazor.Graph.csproj
+++ b/src/components/BootstrapBlazor.NodeGraph/BootstrapBlazor.NodeGraph.csproj
@@ -17,4 +17,9 @@
+
+
+
+
+
diff --git a/src/components/BootstrapBlazor.NodeGraph/Components/NodeGraphCanvas.razor b/src/components/BootstrapBlazor.NodeGraph/Components/NodeGraphCanvas.razor
new file mode 100644
index 00000000..21827311
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Components/NodeGraphCanvas.razor
@@ -0,0 +1,41 @@
+@namespace BootstrapBlazor.Components
+@using Microsoft.Extensions.Logging
+@attribute [JSModuleAutoLoader("./_content/BootstrapBlazor.NodeGraph/js/Graph.js", AutoInvokeDispose = false, JSObjectReference = true)]
+@inherits BootstrapModuleComponentBase
+
+@inject NodeGraphService NodeGraphService
+@inject ILogger Logger
+
+
+
+
+
+@code {
+ public Graph Graph { get; private set; } = null!;
+
+ private string? ClassString => CssBuilder.Default("graph-main-container")
+ .AddClassFromAttributes(AdditionalAttributes)
+ .Build();
+
+ private IJSObjectReference _graphCanvasRef = null!;
+ private ElementReference _graphCanvas;
+
+ ///
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ await base.OnAfterRenderAsync(firstRender);
+ if (firstRender)
+ {
+ // 初始化并添加引用
+ await InvokeVoidAsync("init", Id, DotNetObjectReference.Create(NodeGraphService));
+ // 创建图表配置
+ var graphRef = await InvokeAsync("createLGraph");
+ Graph = new Graph(graphRef!);
+ // var graph = new Graph(graphRef!);
+ // 创建图表画布
+ _graphCanvasRef = await InvokeAsync("createLGraphCanvas", _graphCanvas, graphRef)
+ ?? throw new InvalidOperationException("Create GraphCanvas failed!");
+ }
+ }
+
+}
diff --git a/src/components/BootstrapBlazor.NodeGraph/Components/NodeGraphCanvas.razor.css b/src/components/BootstrapBlazor.NodeGraph/Components/NodeGraphCanvas.razor.css
new file mode 100644
index 00000000..a8709d54
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Components/NodeGraphCanvas.razor.css
@@ -0,0 +1,7 @@
+.graph-main-container{
+ position: relative;
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
diff --git a/src/components/BootstrapBlazor.Graph/_Imports.razor b/src/components/BootstrapBlazor.NodeGraph/Components/_Imports.razor
similarity index 100%
rename from src/components/BootstrapBlazor.Graph/_Imports.razor
rename to src/components/BootstrapBlazor.NodeGraph/Components/_Imports.razor
diff --git a/src/components/BootstrapBlazor.NodeGraph/Data/Interop/NodeRegister.cs b/src/components/BootstrapBlazor.NodeGraph/Data/Interop/NodeRegister.cs
new file mode 100644
index 00000000..9de693a1
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Data/Interop/NodeRegister.cs
@@ -0,0 +1,93 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Components.Data.Interop;
+
+///
+/// 节点插槽
+///
+public class NodeSlotDto
+{
+ ///
+ /// 插槽名称
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// 插槽类型 TypeName
+ ///
+ public string Type { get; set; } = string.Empty;
+}
+
+///
+/// 节点组件
+///
+public class WidgetDto
+{
+ ///
+ /// 组件ID,需要在当前节点下唯一
+ ///
+ public string WidgetId { get; set; } = string.Empty;
+
+ ///
+ /// 节点组件类型
+ ///
+ public string WidgetType { get; set; } = string.Empty;
+
+ ///
+ /// 节点组件名称
+ ///
+ public string DisplayName { get; set; } = string.Empty;
+
+ ///
+ /// 默认值
+ ///
+ public object? Value { get; set; }
+
+ ///
+ /// 节点组件配置
+ ///
+ public WidgetOptions? WidgetOptions { get; set; }
+
+ ///
+ /// 是否有回调函数
+ ///
+ public bool HasCallback { get; set; }
+}
+
+///
+/// 节点配置
+///
+public class GraphNodeConfigDto
+{
+ ///
+ /// 节点唯一类型路径,形如 groupA/groupB/NodeName
+ ///
+ public string TypePath { get; set; } = null!;
+
+ ///
+ /// 节点名称
+ ///
+ public string DisplayName { get; set; } = string.Empty;
+
+ ///
+ /// 输入插槽
+ ///
+ public List Inputs { get; set; } = new();
+
+ ///
+ /// 输出插槽
+ ///
+ public List Outputs { get; set; } = new();
+
+ ///
+ /// 节点组件
+ ///
+ public List Widgets { get; set; } = new();
+
+ ///
+ /// 是否有执行方法
+ ///
+ public bool HasAction { get; set; }
+}
diff --git a/src/components/BootstrapBlazor.NodeGraph/Data/WidgetsConfig.cs b/src/components/BootstrapBlazor.NodeGraph/Data/WidgetsConfig.cs
new file mode 100644
index 00000000..33699f61
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Data/WidgetsConfig.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Text.Json.Serialization;
+
+namespace BootstrapBlazor.Components.Data;
+
+///
+/// 节点组件配置
+///
+public abstract record WidgetOptions
+{
+ // public string? On { get; set; }
+ // public string? Off { get; set; }
+
+ ///
+ /// 是否只读
+ ///
+ public bool? ReadOnly { get; set; }
+
+ // public int? Y { get; set; }
+ // public bool? Multiline { get; set; }
+
+ // TODO: 待测试
+ public string? Property { get; set; }
+
+ ///
+ /// 不显示可编辑组件
+ ///
+ public bool? Socketless { get; set; }
+
+ // TODO: Combo中使用
+ // public TValue[]? Values { get; set; }
+}
+
+///
+/// 布尔组件配置
+///
+public record BooleanWidgetOptions : WidgetOptions
+{
+}
+
+///
+/// 数字组件配置
+///
+public record NumberWidgetOptions : WidgetOptions
+{
+ ///
+ /// 最小值
+ ///
+ public double? Min { get; set; }
+
+ ///
+ /// 最大值
+ ///
+ public double? Max { get; set; }
+
+ // step 已经废弃
+ ///
+ /// 步长
+ ///
+ [JsonPropertyName("step2")]
+ public double? Step { get; set; }
+
+ ///
+ /// 精度
+ ///
+ public int? Precision { get; set; }
+}
+
+///
+/// 滑动条组件配置
+///
+public record SliderWidgetOptions : WidgetOptions
+{
+ ///
+ /// 最小值
+ ///
+ public double Min { get; set; }
+
+ ///
+ /// 最大值
+ ///
+ public double Max { get; set; }
+
+ // step 已经废弃
+ ///
+ /// 步长
+ ///
+ [JsonPropertyName("step2")]
+ public double? Step { get; set; }
+
+ ///
+ /// 精度
+ ///
+ public int? Precision { get; set; }
+
+ // TODO: CanvasColour
+ // public object? SliderColor { get; set; } // TODO: Replace with actual type for CanvasColour
+ // public object? MarkerColor { get; set; } // TODO: Replace with actual type for CanvasColour
+}
+
+///
+/// 旋钮组件配置
+///
+public record KnobWidgetOptions : WidgetOptions
+{
+ ///
+ /// 最小值
+ ///
+ public double Min { get; set; }
+
+ ///
+ /// 最大值
+ ///
+ public double Max { get; set; }
+
+ // step 已经废弃
+ ///
+ /// 步长
+ ///
+ [JsonPropertyName("step2")]
+ public double? Step { get; set; }
+
+ ///
+ /// 精度
+ ///
+ public int? Precision { get; set; }
+
+ // TODO: CanvasColour
+ // public object? SliderColor { get; set; } // TODO: Replace with actual type for CanvasColour
+ // public object? MarkerColor { get; set; } // TODO: Replace with actual type for CanvasColour
+
+ // public string? GradientStops { get; set; }
+}
+
+///
+/// 文本组件配置
+///
+public record StringWidgetOptions : WidgetOptions
+{
+}
+
+///
+/// 按钮组件配置
+///
+public record ButtonWidgetOptions : WidgetOptions
+{
+}
diff --git a/src/components/BootstrapBlazor.NodeGraph/Graph.cs b/src/components/BootstrapBlazor.NodeGraph/Graph.cs
new file mode 100644
index 00000000..e25cc949
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Graph.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Components;
+
+public class Graph
+{
+ public IJSObjectReference GraphRef { get; }
+
+ internal Graph(IJSObjectReference lGraphRef)
+ {
+ GraphRef = lGraphRef;
+ }
+
+ public async Task RunStep(int step, bool ignoreErrors = true, int? limits = null)
+ {
+ await GraphRef.InvokeVoidAsync("runStep", step, ignoreErrors, limits);
+ }
+}
diff --git a/src/components/BootstrapBlazor.NodeGraph/GraphNode.cs b/src/components/BootstrapBlazor.NodeGraph/GraphNode.cs
new file mode 100644
index 00000000..e5206f1a
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/GraphNode.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Components;
+
+public class GraphNode : IAsyncDisposable
+{
+ private IJSObjectReference _graphNodeReference;
+
+ internal GraphNode(IJSObjectReference graphNodeReference)
+ {
+ _graphNodeReference = graphNodeReference;
+ }
+
+ ///
+ public ValueTask DisposeAsync()
+ {
+ return _graphNodeReference.DisposeAsync();
+ }
+
+ public ValueTask GetInputData(int slotIndex)
+ {
+ return _graphNodeReference.InvokeAsync( "getInputData", slotIndex);
+ }
+
+ public ValueTask GetOutputData(int slotIndex)
+ {
+ return _graphNodeReference.InvokeAsync( "getOutputData", slotIndex);
+ }
+
+ public ValueTask SetOutputData(int slotIndex, T outputData)
+ {
+ return _graphNodeReference.InvokeVoidAsync( "setOutputData", slotIndex, outputData);
+ }
+}
diff --git a/src/components/BootstrapBlazor.NodeGraph/Interfaces/INodeSlot.cs b/src/components/BootstrapBlazor.NodeGraph/Interfaces/INodeSlot.cs
new file mode 100644
index 00000000..20e33f42
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Interfaces/INodeSlot.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Components.Interfaces;
+
+public interface INodeSlot
+{
+ ///
+ /// slot name
+ ///
+ public string Name { get; set; }
+ ///
+ /// node下的唯一id
+ ///
+ public string Id { get; set; }
+ ///
+ /// 数据类型
+ ///
+ public Type ValueType { get; }
+}
diff --git a/src/components/BootstrapBlazor.NodeGraph/Interfaces/INodeWidget.cs b/src/components/BootstrapBlazor.NodeGraph/Interfaces/INodeWidget.cs
new file mode 100644
index 00000000..97333d62
--- /dev/null
+++ b/src/components/BootstrapBlazor.NodeGraph/Interfaces/INodeWidget.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using BootstrapBlazor.Components.Data;
+
+namespace BootstrapBlazor.Components.Interfaces;
+
+///
+/// 节点组件接口
+///
+public interface INodeWidget
+{
+ ///
+ /// 组件ID,需要在当前节点下唯一
+ ///
+ public string WidgetId { get; set; }
+ ///
+ /// 节点组件类型
+ ///
+ public NodeWidgetType WidgetType { get; }
+
+ ///
+ /// 节点组件名称
+ ///
+ public string DisplayName { get; set; }
+
+ ///
+ /// 默认值
+ ///
+ public object? Value { get; set; }
+
+ ///
+ /// 节点组件配置
+ ///
+ public WidgetOptions? WidgetOptions { get; set; }
+
+ ///
+ /// 回调函数
+ ///
+ public Func