User
Update: Restructure dashboards and report chart views
917b070
Raw
History Blame Contribute Delete
4.08 kB
@using TaskTrackingSystem.WebApp.Components.Shared.Charts
<div class="@WrapperClass">
@if (!Groups.Any())
{
<div class="flex h-full min-h-[220px] items-center justify-center text-sm text-slate-400">@EmptyText</div>
}
else
{
<svg viewBox="0 0 760 280" class="h-full min-h-[260px] w-full overflow-visible">
@foreach (var tick in YTicks)
{
var y = TickToY(tick);
<g>
<line x1="@PlotLeft" y1="@y" x2="@PlotRight" y2="@y" stroke="#e2e8f0" stroke-width="1" stroke-dasharray="4 4" />
<text x="42" y="@(y + 4)" text-anchor="end" font-size="12" fill="#64748b">@tick.ToString("0")</text>
</g>
}
@for (var i = 0; i < Groups.Count; i++)
{
var group = Groups[i];
var slotWidth = (PlotRight - PlotLeft) / Groups.Count;
var centerX = PlotLeft + (slotWidth * i) + (slotWidth / 2);
var bars = group.Bars.Take(MaxBarsPerGroup).ToList();
var totalBarWidth = (bars.Count * BarWidth) + Math.Max(0, bars.Count - 1) * BarGap;
var startX = centerX - (totalBarWidth / 2);
<g>
@for (var j = 0; j < bars.Count; j++)
{
var bar = bars[j];
var height = ValueToHeight(bar.Value);
<rect x="@(startX + (j * (BarWidth + BarGap)))"
y="@(PlotBottom - height)"
width="@BarWidth"
height="@height"
rx="8"
fill="@bar.Color" />
}
<text x="@centerX" y="246" text-anchor="middle" font-size="13" fill="#64748b">@group.Label</text>
</g>
}
</svg>
@if (ShowLegend)
{
<div class="mt-4 flex flex-wrap items-center gap-4 text-xs text-slate-500">
@foreach (var item in LegendItems)
{
<div class="flex items-center gap-2">
<span class="h-3 w-3 rounded-full" style="background-color: @item.Color"></span>
@item.Label
</div>
}
</div>
}
}
</div>
@code {
private const double PlotLeft = 56;
private const double PlotRight = 724;
private const double PlotTop = 40;
private const double PlotBottom = 200;
private const double BarGap = 8;
[Parameter] public IReadOnlyList<BarChartGroup> Groups { get; set; } = Array.Empty<BarChartGroup>();
[Parameter] public string WrapperClass { get; set; } = "relative h-[280px]";
[Parameter] public string EmptyText { get; set; } = "No data available";
[Parameter] public bool ShowLegend { get; set; } = true;
[Parameter] public double BarWidth { get; set; } = 18;
[Parameter] public int MaxBarsPerGroup { get; set; } = 4;
private double MaxValue => Math.Max(1, Groups.SelectMany(group => group.Bars).Select(bar => bar.Value).DefaultIfEmpty(0).Max());
private IReadOnlyList<double> YTicks
{
get
{
var interval = Math.Max(1, Math.Ceiling(MaxValue / 4.0));
var highest = interval * 4;
return new[] { 0, highest * 0.25, highest * 0.5, highest * 0.75, highest };
}
}
private IReadOnlyList<ChartDataPoint> LegendItems => Groups
.SelectMany(group => group.Bars)
.GroupBy(bar => bar.Label)
.Select(group => group.First())
.ToList();
private double TickToY(double tickValue)
{
var chartHeight = PlotBottom - PlotTop;
return PlotBottom - (Math.Min(tickValue, MaxValue) / MaxValue * chartHeight);
}
private double ValueToHeight(double value)
{
var chartHeight = PlotBottom - PlotTop;
return Math.Round(Math.Min(value, MaxValue) / MaxValue * chartHeight, 2);
}
}