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; // Optional exact gallery typography; copy the gallery's fonts directory beside this program. FontRegistry.Register("CFX Proof Carlito", "fonts/Carlito-Regular.ttf", 400); FontRegistry.Register("CFX Proof Carlito", "fonts/Carlito-Bold.ttf", 700); var mode = VisualThemeMode.Light; var theme = VisualTheme.Graphite(); var model = ComparisonRecipe.Create("compact", mode); var context = new VisualRenderContext( new VisualLayoutOptions(new VisualSize(360, 360)), theme, mode, new VisualFrame("Checks over the reporting period", "One prepared scene for SVG and native PNG", showLegend: null, showSurface: false), FontSpec.FromFamily("CFX Proof Carlito")); 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.Chart).ToHtmlPage()); /// Line, area and bar observations share categories, including explicit missing and empty states. public static class ComparisonRecipe { public static Chart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) { var count = variant == "empty" ? 0 : variant == "dense" ? 24 : 7; var names = variant == "wrapped-legend" ? new[] { "Observed checks across all locations", "Expected coverage of monitored services", "Capacity available for the next assessment" } : new[] { "Observed", "Expected", "Capacity" }; var observed = ChartSeries.CreateLine(new ChartSeriesId("observed"), names[0], Points(count, variant, 0)); var expected = ChartSeries.CreateArea(new ChartSeriesId("expected"), names[1], Points(count, variant, 1)); var capacity = ChartSeries.CreateBar(new ChartSeriesId("capacity"), names[2], Points(count, variant, 2, false)); if (variant is "explicit-status" or "explicit-series") { var colors = VisualTheme.Graphite().Resolve(mode); var selected = variant == "explicit-status" ? new[] { colors.Status.Pass.Fill, colors.Status.Medium.Fill, colors.Status.Critical.Fill } : colors.Palette.Take(3).ToArray(); observed.WithColor(selected[0]); expected.WithColor(selected[1]); capacity.WithColor(selected[2]); } return Chart.Create().WithXLabels(Enumerable.Range(1, count).Select(index => "Day " + index).ToArray()) .AddSeries(observed).AddSeries(expected).AddSeries(capacity); } private static IEnumerable Points(int count, string variant, int series, bool allowBreaks = true) { for (var index = 0; index < count; index++) { if (variant == "missing" && (index == 2 || index == 3)) continue; var value = variant == "zero" ? 0 : 20 + series * 14 + index * (series + 3) % 23; yield return new ChartPoint(index + 1, value, allowBreaks && variant == "missing" && index == 4); } } }