using Schaad.Accounting; using Schaad.Accounting.Datasets.Charts; namespace Schaad.Accounting.UI.Components.Pages.Charts; /// /// Swiss (de-CH) formatting for chart labels/tooltips, plus the top-N + "Andere" /// folding used to keep pies and stacked series legible. Plotly's own d3-format /// tokens can't produce the apostrophe thousands separator, so values are /// pre-formatted here in C# and passed to Plotly as literal text. /// public static class ChartFormatting { private static readonly string[] MonthAbbreviations = [ "Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez" ]; public static string MonthLabel(DateOnly date) => $"{MonthAbbreviations[date.Month - 1]} {date.Year % 100:00}"; public static string Chf(decimal value) => $"{value.ToFormattedString()} CHF"; /// /// Sorts by magnitude descending and, past , /// collapses the remainder into a single "Andere" entry so a pie/legend never /// has to carry more slices than the categorical palette can distinguish. /// public static IReadOnlyList FoldTail(IReadOnlyList items) { var sorted = items.OrderByDescending(i => Math.Abs(i.Value)).ToList(); if (sorted.Count <= ChartTheme.MaxCategories) { return sorted; } var head = sorted.Take(ChartTheme.MaxCategories - 1).ToList(); var tailTotal = sorted.Skip(ChartTheme.MaxCategories - 1).Sum(i => i.Value); head.Add(new CategoryTotal(ChartTheme.OtherLabel, tailTotal)); return head; } /// /// Same idea as for a set of /// monthly series (e.g. a stacked bar chart): series are ranked by total magnitude /// across all months, and everything past the cap is summed month-by-month into /// a single "Andere" series. /// public static IReadOnlyList FoldTail(IReadOnlyList series) { if (series.Count <= ChartTheme.MaxCategories) { return series; } var ranked = series.OrderByDescending(s => s.Y.Sum(Math.Abs)).ToList(); var head = ranked.Take(ChartTheme.MaxCategories - 1).ToList(); var tail = ranked.Skip(ChartTheme.MaxCategories - 1).ToList(); var x = tail[0].X; var otherY = new decimal[x.Count]; foreach (var serie in tail) { for (var i = 0; i < x.Count; i++) { otherY[i] += serie.Y[i]; } } head.Add(new DataSerie(ChartTheme.OtherLabel, ChartTheme.OtherLabel, x, otherY)); return head; } }