Preview


960 × 600 pixels
Create this example
Create a console project, add the ChartForgeX package, and replace Program.cs with this source. Run it to write SVG, PNG and HTML with the default system fonts.
For the same typography as the gallery, download the gallery-font recipe and copy the gallery’s fonts directory beside your program.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using ChartForgeX.Core;
using ChartForgeX.Primitives;
using ChartForgeX.Rendering;
using ChartForgeX.Themes;
using ChartForgeX.Topology;
using ChartForgeX.Typography;
using ChartForgeX.VisualArtifacts;
using ChartForgeX.VisualBlocks;
var mode = VisualThemeMode.Light;
var theme = VisualTheme.Graphite();
var model = TopologyRecipe.Create("expanded", mode);
var context = new VisualRenderContext(
new VisualLayoutOptions(new VisualSize(960, 600)), theme, mode,
new VisualFrame("Service request topology", "Groups, status, details and routed links", showLegend: true, showSurface: false));
var prepared = model.Prepare(context);
File.WriteAllText("visual.svg", prepared.ToSvg());
File.WriteAllBytes("visual.png", prepared.ToPng());
File.WriteAllText("visual.html", prepared.ToArtifact("example", VisualArtifactKind.Topology).ToHtmlPage());
/// <summary>Creates a service topology or an atlas of the available node shapes.</summary>
public static class TopologyRecipe {
/// <summary>Creates the diagram model for an expanded, compact or shape-atlas view.</summary>
/// <param name="variant">Use wide, expanded or compact for the service topology, or shapes for the shape atlas.</param>
/// <param name="mode">The rendering mode; diagram colors are resolved when the model is prepared.</param>
public static TopologyChart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) {
if (variant is not ("wide" or "expanded" or "compact" or "shapes"))
throw new ArgumentOutOfRangeException(nameof(variant), variant, "Use wide, expanded, compact or shapes.");
var atlas = variant == "shapes";
var chart = TopologyChart.Create();
chart.Id = atlas ? "shape-atlas" : "service-topology";
chart.DefaultRenderOptions = new TopologyRenderOptions {
FitContentToViewport = true,
WrapNodeLabels = true,
IncludeLegend = true,
IncludeGroupStatusDots = true
};
if (atlas) {
var shapes = Enum.GetValues<TopologyNodeShape>();
for (var index = 0; index < shapes.Length; index++) {
chart.Nodes.Add(new TopologyNode {
Id = "shape-" + index,
Label = shapes[index].ToString(),
X = 24 + index % 5 * 160,
Y = 24 + index / 5 * 120,
Width = 132,
Height = 86,
Shape = shapes[index],
PreserveDisplayModeSize = true,
ShowStatusBadge = false
});
}
return chart;
}
chart.Groups.Add(new TopologyGroup {
Id = "primary", Label = "Primary region", X = 0, Y = 0, Width = 340, Height = 300,
Status = TopologyHealthStatus.Healthy
});
chart.Groups.Add(new TopologyGroup {
Id = "secondary", Label = "Secondary region", X = 390, Y = 0, Width = 340, Height = 300,
Status = TopologyHealthStatus.Warning
});
var source = new TopologyNode {
Id = "client", Label = "Client service", Subtitle = "Requests", X = 30, Y = 65, Width = 240, Height = 85,
Kind = TopologyNodeKind.Server, GroupId = "primary", Status = TopologyHealthStatus.Healthy
};
source.Details.Add(new TopologyNodeDetail {
Label = "State", Value = "Available", Status = TopologyHealthStatus.Healthy
});
chart.Nodes.Add(source);
chart.Nodes.Add(new TopologyNode {
Id = "cache", Label = "Cache", X = 70, Y = 210, Width = 150, Height = 65,
Shape = TopologyNodeShape.Cylinder, GroupId = "primary"
});
chart.Nodes.Add(new TopologyNode {
Id = "worker", Label = "Processing service", X = 430, Y = 65, Width = 240, Height = 85,
Kind = TopologyNodeKind.Server, GroupId = "secondary", Status = TopologyHealthStatus.Warning
});
chart.Nodes.Add(new TopologyNode {
Id = "store", Label = "Result store", X = 470, Y = 210, Width = 150, Height = 65,
Shape = TopologyNodeShape.Cylinder, GroupId = "secondary"
});
chart.Edges.Add(new TopologyEdge {
Id = "request", SourceNodeId = "client", TargetNodeId = "worker", Label = "Requests", SecondaryLabel = "Active",
Routing = TopologyEdgeRouting.ObstacleAvoidingOrthogonal, Direction = VisualLinkDirection.Forward
});
chart.Edges.Add(new TopologyEdge {
Id = "cache-read", SourceNodeId = "client", TargetNodeId = "cache", Label = "Lookup", Routing = TopologyEdgeRouting.Curved,
LineStyle = TopologyEdgeLineStyle.Dashed, Direction = VisualLinkDirection.Bidirectional
});
chart.Edges.Add(new TopologyEdge {
Id = "persist", SourceNodeId = "worker", TargetNodeId = "store", Label = "Persist",
Routing = TopologyEdgeRouting.Orthogonal
});
chart.Legend = TopologyLegend.Create()
.AddStatus("Available", TopologyHealthStatus.Healthy)
.AddStatus("Review", TopologyHealthStatus.Warning)
.AddNodeKind("Service", TopologyNodeKind.Server)
.AddEdgeKind("Dependency", TopologyEdgeKind.Dependency, lineStyle: TopologyEdgeLineStyle.Dashed);
return chart;
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using ChartForgeX.Core;
using ChartForgeX.Primitives;
using ChartForgeX.Rendering;
using ChartForgeX.Themes;
using ChartForgeX.Topology;
using ChartForgeX.Typography;
using ChartForgeX.VisualArtifacts;
using ChartForgeX.VisualBlocks;
var mode = VisualThemeMode.Dark;
var theme = VisualTheme.Graphite();
var model = TopologyRecipe.Create("expanded", mode);
var context = new VisualRenderContext(
new VisualLayoutOptions(new VisualSize(960, 600)), theme, mode,
new VisualFrame("Service request topology", "Groups, status, details and routed links", showLegend: true, showSurface: false));
var prepared = model.Prepare(context);
File.WriteAllText("visual.svg", prepared.ToSvg());
File.WriteAllBytes("visual.png", prepared.ToPng());
File.WriteAllText("visual.html", prepared.ToArtifact("example", VisualArtifactKind.Topology).ToHtmlPage());
/// <summary>Creates a service topology or an atlas of the available node shapes.</summary>
public static class TopologyRecipe {
/// <summary>Creates the diagram model for an expanded, compact or shape-atlas view.</summary>
/// <param name="variant">Use wide, expanded or compact for the service topology, or shapes for the shape atlas.</param>
/// <param name="mode">The rendering mode; diagram colors are resolved when the model is prepared.</param>
public static TopologyChart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) {
if (variant is not ("wide" or "expanded" or "compact" or "shapes"))
throw new ArgumentOutOfRangeException(nameof(variant), variant, "Use wide, expanded, compact or shapes.");
var atlas = variant == "shapes";
var chart = TopologyChart.Create();
chart.Id = atlas ? "shape-atlas" : "service-topology";
chart.DefaultRenderOptions = new TopologyRenderOptions {
FitContentToViewport = true,
WrapNodeLabels = true,
IncludeLegend = true,
IncludeGroupStatusDots = true
};
if (atlas) {
var shapes = Enum.GetValues<TopologyNodeShape>();
for (var index = 0; index < shapes.Length; index++) {
chart.Nodes.Add(new TopologyNode {
Id = "shape-" + index,
Label = shapes[index].ToString(),
X = 24 + index % 5 * 160,
Y = 24 + index / 5 * 120,
Width = 132,
Height = 86,
Shape = shapes[index],
PreserveDisplayModeSize = true,
ShowStatusBadge = false
});
}
return chart;
}
chart.Groups.Add(new TopologyGroup {
Id = "primary", Label = "Primary region", X = 0, Y = 0, Width = 340, Height = 300,
Status = TopologyHealthStatus.Healthy
});
chart.Groups.Add(new TopologyGroup {
Id = "secondary", Label = "Secondary region", X = 390, Y = 0, Width = 340, Height = 300,
Status = TopologyHealthStatus.Warning
});
var source = new TopologyNode {
Id = "client", Label = "Client service", Subtitle = "Requests", X = 30, Y = 65, Width = 240, Height = 85,
Kind = TopologyNodeKind.Server, GroupId = "primary", Status = TopologyHealthStatus.Healthy
};
source.Details.Add(new TopologyNodeDetail {
Label = "State", Value = "Available", Status = TopologyHealthStatus.Healthy
});
chart.Nodes.Add(source);
chart.Nodes.Add(new TopologyNode {
Id = "cache", Label = "Cache", X = 70, Y = 210, Width = 150, Height = 65,
Shape = TopologyNodeShape.Cylinder, GroupId = "primary"
});
chart.Nodes.Add(new TopologyNode {
Id = "worker", Label = "Processing service", X = 430, Y = 65, Width = 240, Height = 85,
Kind = TopologyNodeKind.Server, GroupId = "secondary", Status = TopologyHealthStatus.Warning
});
chart.Nodes.Add(new TopologyNode {
Id = "store", Label = "Result store", X = 470, Y = 210, Width = 150, Height = 65,
Shape = TopologyNodeShape.Cylinder, GroupId = "secondary"
});
chart.Edges.Add(new TopologyEdge {
Id = "request", SourceNodeId = "client", TargetNodeId = "worker", Label = "Requests", SecondaryLabel = "Active",
Routing = TopologyEdgeRouting.ObstacleAvoidingOrthogonal, Direction = VisualLinkDirection.Forward
});
chart.Edges.Add(new TopologyEdge {
Id = "cache-read", SourceNodeId = "client", TargetNodeId = "cache", Label = "Lookup", Routing = TopologyEdgeRouting.Curved,
LineStyle = TopologyEdgeLineStyle.Dashed, Direction = VisualLinkDirection.Bidirectional
});
chart.Edges.Add(new TopologyEdge {
Id = "persist", SourceNodeId = "worker", TargetNodeId = "store", Label = "Persist",
Routing = TopologyEdgeRouting.Orthogonal
});
chart.Legend = TopologyLegend.Create()
.AddStatus("Available", TopologyHealthStatus.Healthy)
.AddStatus("Review", TopologyHealthStatus.Warning)
.AddNodeKind("Service", TopologyNodeKind.Server)
.AddEdgeKind("Dependency", TopologyEdgeKind.Dependency, lineStyle: TopologyEdgeLineStyle.Dashed);
return chart;
}
}