@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() ?? [];
}