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("options", mode);
var context = new VisualRenderContext(
new VisualLayoutOptions(new VisualSize(800, 440)), theme, mode,
new VisualFrame("How work is allocated across teams", "Explore configured marks, scales and labels", 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));
}
}