-
-
Notifications
You must be signed in to change notification settings - Fork 7
添加NodeGraph组件 #438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
添加NodeGraph组件 #438
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<NodeGraphCanvas> Logger | ||
|
|
||
| <div class="@ClassString" @attributes="@AdditionalAttributes" id="@Id"> | ||
| <canvas @ref="_graphCanvas"></canvas> | ||
| </div> | ||
|
|
||
| @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; | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override async Task OnAfterRenderAsync(bool firstRender) | ||
| { | ||
| await base.OnAfterRenderAsync(firstRender); | ||
| if (firstRender) | ||
| { | ||
| // 初始化并添加引用 | ||
| await InvokeVoidAsync("init", Id, DotNetObjectReference.Create(NodeGraphService)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (bug_risk): Inline DotNetObjectReference.Create can leak references Store the DotNetObjectReference in a private field and implement IAsyncDisposable to dispose it when the component is disposed. |
||
| // 创建图表配置 | ||
| var graphRef = await InvokeAsync<IJSObjectReference>("createLGraph"); | ||
| Graph = new Graph(graphRef!); | ||
| // var graph = new Graph(graphRef!); | ||
| // 创建图表画布 | ||
| _graphCanvasRef = await InvokeAsync<IJSObjectReference>("createLGraphCanvas", _graphCanvas, graphRef) | ||
| ?? throw new InvalidOperationException("Create GraphCanvas failed!"); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| .graph-main-container{ | ||
| position: relative; | ||
| width: 100%; | ||
| height: 100%; | ||
| margin: 0; | ||
| padding: 0; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -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; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点插槽 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public class NodeSlotDto | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 插槽名称 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string Name { get; set; } = string.Empty; | ||||||||||||||||||||||||||||
|
Comment on lines
+12
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (bug_risk): NodeSlotDto omits the slot Id Include the slot
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 插槽类型 TypeName | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string Type { get; set; } = string.Empty; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点组件 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public class WidgetDto | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 组件ID,需要在当前节点下唯一 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string WidgetId { get; set; } = string.Empty; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点组件类型 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string WidgetType { get; set; } = string.Empty; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点组件名称 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string DisplayName { get; set; } = string.Empty; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 默认值 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public object? Value { get; set; } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点组件配置 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public WidgetOptions? WidgetOptions { get; set; } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 是否有回调函数 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public bool HasCallback { get; set; } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点配置 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public class GraphNodeConfigDto | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点唯一类型路径,形如 groupA/groupB/NodeName | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string TypePath { get; set; } = null!; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点名称 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public string DisplayName { get; set; } = string.Empty; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 输入插槽 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public List<NodeSlotDto> Inputs { get; set; } = new(); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 输出插槽 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public List<NodeSlotDto> Outputs { get; set; } = new(); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 节点组件 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public List<WidgetDto> Widgets { get; set; } = new(); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// 是否有执行方法 | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public bool HasAction { get; set; } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
|
|
||
| /// <summary> | ||
| /// 节点组件配置 | ||
| /// </summary> | ||
| public abstract record WidgetOptions | ||
| { | ||
| // public string? On { get; set; } | ||
| // public string? Off { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 是否只读 | ||
| /// </summary> | ||
| public bool? ReadOnly { get; set; } | ||
|
|
||
| // public int? Y { get; set; } | ||
| // public bool? Multiline { get; set; } | ||
|
|
||
| // TODO: 待测试 | ||
| public string? Property { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 不显示可编辑组件 | ||
| /// </summary> | ||
| public bool? Socketless { get; set; } | ||
|
|
||
| // TODO: Combo中使用 | ||
| // public TValue[]? Values { get; set; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 布尔组件配置 | ||
| /// </summary> | ||
| public record BooleanWidgetOptions : WidgetOptions | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 数字组件配置 | ||
| /// </summary> | ||
| public record NumberWidgetOptions : WidgetOptions | ||
| { | ||
| /// <summary> | ||
| /// 最小值 | ||
| /// </summary> | ||
| public double? Min { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 最大值 | ||
| /// </summary> | ||
| public double? Max { get; set; } | ||
|
|
||
| // step 已经废弃 | ||
| /// <summary> | ||
| /// 步长 | ||
| /// </summary> | ||
| [JsonPropertyName("step2")] | ||
| public double? Step { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 精度 | ||
| /// </summary> | ||
| public int? Precision { get; set; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 滑动条组件配置 | ||
| /// </summary> | ||
| public record SliderWidgetOptions : WidgetOptions | ||
| { | ||
| /// <summary> | ||
| /// 最小值 | ||
| /// </summary> | ||
| public double Min { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 最大值 | ||
| /// </summary> | ||
| public double Max { get; set; } | ||
|
|
||
| // step 已经废弃 | ||
| /// <summary> | ||
| /// 步长 | ||
| /// </summary> | ||
| [JsonPropertyName("step2")] | ||
| public double? Step { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 精度 | ||
| /// </summary> | ||
| 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 | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 旋钮组件配置 | ||
| /// </summary> | ||
| public record KnobWidgetOptions : WidgetOptions | ||
| { | ||
| /// <summary> | ||
| /// 最小值 | ||
| /// </summary> | ||
| public double Min { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 最大值 | ||
| /// </summary> | ||
| public double Max { get; set; } | ||
|
|
||
| // step 已经废弃 | ||
| /// <summary> | ||
| /// 步长 | ||
| /// </summary> | ||
| [JsonPropertyName("step2")] | ||
| public double? Step { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// 精度 | ||
| /// </summary> | ||
| 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; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 文本组件配置 | ||
| /// </summary> | ||
| public record StringWidgetOptions : WidgetOptions | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 按钮组件配置 | ||
| /// </summary> | ||
| public record ButtonWidgetOptions : WidgetOptions | ||
| { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public ValueTask DisposeAsync() | ||
| { | ||
| return _graphNodeReference.DisposeAsync(); | ||
| } | ||
|
|
||
| public ValueTask<T?> GetInputData<T>(int slotIndex) | ||
| { | ||
| return _graphNodeReference.InvokeAsync<T?>( "getInputData", slotIndex); | ||
| } | ||
|
|
||
| public ValueTask<T?> GetOutputData<T>(int slotIndex) | ||
| { | ||
| return _graphNodeReference.InvokeAsync<T?>( "getOutputData", slotIndex); | ||
| } | ||
|
|
||
| public ValueTask SetOutputData<T>(int slotIndex, T outputData) | ||
| { | ||
| return _graphNodeReference.InvokeVoidAsync( "setOutputData", slotIndex, outputData); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| { | ||
| /// <summary> | ||
| /// slot name | ||
| /// </summary> | ||
| public string Name { get; set; } | ||
| /// <summary> | ||
| /// node下的唯一id | ||
| /// </summary> | ||
| public string Id { get; set; } | ||
| /// <summary> | ||
| /// 数据类型 | ||
| /// </summary> | ||
| public Type ValueType { get; } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): Graph.js is imported both here and in the service
This creates two module instances. Unify to a single import to prevent duplicate downloads and ensure state is shared.
Suggested implementation: