Code/Core/Node.GraphViz.cs
using Nodebox.Dependencies.DotNetGraph.Core;
using Nodebox.Dependencies.DotNetGraph.Attributes;
using Nodebox.Dependencies.DotNetGraph.Extensions;
namespace Nodebox.GraphViz;
public static partial class NodeExtensions {
extension(Node node) {
public DotSubgraph ToGraphVizSubGraph(Dictionary<(Node, Flow, PinIndex), DotNode> pinStore = null, IdentifierDisjunctor identifierDisjunctor = null) {
identifierDisjunctor ??= IdentifierDisjunctor.Bypass;
string DirectionToString(Flow flow) => flow == Flow.Input ? "In" : "Out";
string PinSanitizeName(PinIndex index, Pin pin) => pin.Name ?? index.ToString();
string PinToIdentifier(Flow flow, PinIndex index, Pin pin) => $"{DirectionToString(flow)} {PinSanitizeName(index, pin)}";
var name = DisplayInfo.ForGenericType(node.GetType()).Name;
var label = name;
if (node.GraphVizIdentifier != null && node.GraphVizIdentifier.Length > 0) {
label += $" ({node.GraphVizIdentifier})";
}
var subgraph = new DotSubgraph()
.WithIdentifier(identifierDisjunctor[$"cluster_{name}"])
.WithLabel(label)
.WithStyle(DotSubgraphStyle.Filled)
.WithColor(DotColor.LightGrey);
subgraph.SetAttribute("rank", new DotAttribute("same"));
foreach (var (flow, index, pin) in node.GetAllPins()) {
string value = flow == Flow.Input ? $"{node.GetInputValue(index)}" : null;
var pinIdentifier = PinToIdentifier(flow, index, pin);
var dotNode = new DotNode()
.WithIdentifier(identifierDisjunctor[pinIdentifier] + (value != null ? $" :{value}" : null))
.WithShape(DotNodeShape.Box)
.WithStyle(DotNodeStyle.Filled)
.WithColor(DotColor.White);
pinStore?[(node, flow, index)] = dotNode;
subgraph.Add(dotNode);
}
return subgraph;
}
public string GraphVizIdentifier {
get => node.GetMetaOrDefault<string>("GraphVizName", null);
set => node.SetMeta("GraphVizName", value);
}
}
extension<T>(T node) where T : Node {
public T WithGraphVizIdentifier(string identifier) {
node.GraphVizIdentifier = identifier;
return node;
}
}
}