@using TaskTrackingSystem.WebApp.Components.Shared.Charts
@if (!Items.Any() || Items.Sum(item => item.Value) <= 0) {
@EmptyText
} else {
@foreach (var slice in Slices) { if (slice.IsFullCircle) { } else { } }
@if (ShowLegend) {
@foreach (var item in Items) {
@item.Label
@AppLocalization.Number(item.Value, ValueFormat)
}
} }
@code { [Parameter] public IReadOnlyList Items { get; set; } = Array.Empty(); [Parameter] public bool ShowLegend { get; set; } = true; [Parameter] public string EmptyText { get; set; } = AppLocalization.Text("report.noChartData", "No data available."); [Parameter] public string ValueFormat { get; set; } = "0"; [Parameter] public string WrapperClass { get; set; } = string.Empty; private IReadOnlyList Slices => BuildSlices(); private IReadOnlyList BuildSlices() { const double center = 95; const double radius = 72; var total = Items.Sum(item => Math.Max(0, item.Value)); var startAngle = -90.0; var slices = new List(); foreach (var item in Items) { var value = Math.Max(0, item.Value); if (value <= 0 || total <= 0) { continue; } var sweep = 360 * value / total; var endAngle = startAngle + sweep; if (sweep >= 359.999) { slices.Add(new Slice(item.Color, string.Empty, true)); startAngle = endAngle; continue; } var start = PointOnCircle(center, center, radius, startAngle); var end = PointOnCircle(center, center, radius, endAngle); var largeArc = sweep > 180 ? 1 : 0; var path = $"M {center:0.##} {center:0.##} L {start.X:0.##} {start.Y:0.##} A {radius:0.##} {radius:0.##} 0 {largeArc} 1 {end.X:0.##} {end.Y:0.##} Z"; slices.Add(new Slice(item.Color, path, false)); startAngle = endAngle; } return slices; } private static (double X, double Y) PointOnCircle(double centerX, double centerY, double radius, double angleDegrees) { var radians = angleDegrees * Math.PI / 180; return (centerX + radius * Math.Cos(radians), centerY + radius * Math.Sin(radians)); } private sealed record Slice(string Color, string Path, bool IsFullCircle); }