diff --git a/app/MindWork AI Studio/Chat/ChartBlock.razor b/app/MindWork AI Studio/Chat/ChartBlock.razor index 48811bf8..5dc94672 100644 --- a/app/MindWork AI Studio/Chat/ChartBlock.razor +++ b/app/MindWork AI Studio/Chat/ChartBlock.razor @@ -7,7 +7,20 @@
@chart.Title - @if (chart.Type is ChartDefinitionType.PIE or ChartDefinitionType.DONUT) + @if (chart.Type is ChartDefinitionType.TIME_SERIES) + { +
+ +
+ } + else if (chart.Type is ChartDefinitionType.PIE or ChartDefinitionType.DONUT) {
diff --git a/app/MindWork AI Studio/Chat/ChartBlock.razor.cs b/app/MindWork AI Studio/Chat/ChartBlock.razor.cs index 5d627aec..da8e12f8 100644 --- a/app/MindWork AI Studio/Chat/ChartBlock.razor.cs +++ b/app/MindWork AI Studio/Chat/ChartBlock.razor.cs @@ -1,4 +1,6 @@ -using AIStudio.Components; +using System.Globalization; + +using AIStudio.Components; using Microsoft.AspNetCore.Components; namespace AIStudio.Chat; @@ -16,6 +18,14 @@ public partial class ChartBlock : MSGComponentBase ], }; + private ChartOptions HeatMapChartOptions { get; } = new() + { + ChartPalette = ["#236A50", "#79AE90", "#F2D264", "#C97857", "#6A233D"], + EnableSmoothGradient = true, + YAxisLabelPosition = YAxisLabelPosition.Right, + + }; + [Parameter] public ChartBlockParseResult Result { get; set; } = ChartBlockParseResult.Invalid(string.Empty, string.Empty); @@ -26,10 +36,64 @@ public partial class ChartBlock : MSGComponentBase ChartDefinitionType.LINE => ChartType.Line, ChartDefinitionType.PIE => ChartType.Pie, ChartDefinitionType.DONUT => ChartType.Donut, + ChartDefinitionType.HEATMAP => ChartType.HeatMap, _ => ChartType.Bar, }; private List ChartSeries => this.Result.Chart?.Series .Select(series => new ChartSeries { Name = series.Name, Data = series.Values.ToArray() }) .ToList() ?? []; + + private ChartOptions CategoryChartOptions => this.Result.Chart?.Type is ChartDefinitionType.HEATMAP + ? this.HeatMapChartOptions + : this.ChartOptions; + + private List TimeSeriesChartSeries => this.Result.Chart is not { } chart + ? [] + : chart.Series + .Select(series => new TimeSeriesChartSeries + { + Name = series.Name, + Data = chart.Categories + .Select((category, index) => new TimeSeriesChartSeries.TimeValue( + DateTimeOffset.Parse(category, CultureInfo.InvariantCulture).UtcDateTime, + series.Values[index])) + .ToList(), + IsVisible = true, + }) + .ToList(); + + private TimeSpan TimeLabelSpacing + { + get + { + var timestamps = this.GetTimeSeriesTimestamps(); + if (timestamps.Count < 2) + return TimeSpan.FromSeconds(1); + + var range = timestamps[^1] - timestamps[0]; + var intervalCount = Math.Min(timestamps.Count - 1, 8); + return TimeSpan.FromTicks(Math.Max(TimeSpan.TicksPerSecond, range.Ticks / intervalCount)); + } + } + + private string TimeLabelFormat + { + get + { + var timestamps = this.GetTimeSeriesTimestamps(); + if (timestamps.Count < 2) + return "yyyy-MM-dd HH:mm"; + + var range = timestamps[^1] - timestamps[0]; + if (range <= TimeSpan.FromDays(2)) + return "MM-dd HH:mm"; + + return range <= TimeSpan.FromDays(730) ? "yyyy-MM-dd" : "yyyy"; + } + } + + private List GetTimeSeriesTimestamps() => this.Result.Chart?.Categories + .Select(category => DateTimeOffset.Parse(category, CultureInfo.InvariantCulture).ToUniversalTime()) + .ToList() ?? []; }