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 = TreemapRecipe.Create("wide", mode); var context = new VisualRenderContext( new VisualLayoutOptions(new VisualSize(800, 440)), theme, mode, new VisualFrame("How work is allocated across teams", "Explore the data, then download the chart", 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()); /// Creates a treemap showing work allocation and independent numeric color values. public static class TreemapRecipe { /// Creates the source model for a gallery variant without choosing an export backend. public static Chart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) { if (variant is not ("wide" or "compact" or "sparse" or "options" or "compact-options")) throw new ArgumentOutOfRangeException(nameof(variant)); var items = variant == "sparse" ? new[] { new ChartHierarchyItem("independent", "Independent team", value: 100, colorValue: 7), new ChartHierarchyItem("reserve", "Reserve", value: 0) } : new[] { new ChartHierarchyItem("north", "North"), new ChartHierarchyItem("north-services", "Services", parentId: "north"), new ChartHierarchyItem("north-support", "Support", parentId: "north-services", value: 18, colorValue: -4), new ChartHierarchyItem("north-research", "Research", parentId: "north-services", value: 12, colorValue: 11), new ChartHierarchyItem("north-platform", "Platform", parentId: "north", value: 18, colorValue: 3), new ChartHierarchyItem("south", "South"), new ChartHierarchyItem("south-services", "Services", parentId: "south"), new ChartHierarchyItem("south-support", "Support", parentId: "south-services", value: 22, colorValue: 8), new ChartHierarchyItem("south-field", "Field", parentId: "south-services", value: 15, colorValue: 1), new ChartHierarchyItem("south-operations", "Operations", parentId: "south", value: 15), new ChartHierarchyItem("research", "Independent research", value: 8, colorValue: 14), new ChartHierarchyItem("reserve", "Reserve", value: 0) }; var colors = VisualTheme.Graphite().Resolve(mode); var low = mode == VisualThemeMode.Dark ? ChartColor.FromRgb(153, 138, 224) : ChartColor.FromRgb(101, 78, 169); var high = mode == VisualThemeMode.Dark ? ChartColor.FromRgb(238, 157, 98) : ChartColor.FromRgb(191, 92, 34); var scale = variant == "options" ? ChartColorScale.Discrete(new[] { new ChartColorBand(0, low, "Decline"), new ChartColorBand(10, colors.Border, "Steady"), new ChartColorBand(null, high, "Growth") }) : ChartColorScale.Diverging(low, colors.Border, high, 0).WithValueRange(-10, 15).WithLabels("Decrease", "No change", "Increase"); var allocation = ChartSeries.CreateTreemap(new ChartSeriesId("allocation-source"), "Allocated work", items); var chart = Chart.Create().WithDataLabels(true).AddSeries(allocation).ConfigureTreemap(options => { options.GroupPadding = variant == "options" ? 8 : 6; options.Gap = 3; options.ShowGroupLabels = true; options.ColorDimension.Name = "Change (%)"; options.ColorScale = scale.WithNoDataColor(colors.Surface); }); if (variant == "options") allocation.WithNodeState("south-support", ChartSeriesState.Warning); return chart.WithValueFormat(ChartValueFormat.Number("0.##", System.Globalization.CultureInfo.InvariantCulture)); } }