From 03f016aa8513bdd56ae6efaf9958fe6b6f314c1e Mon Sep 17 00:00:00 2001 From: Sam Spencer Date: Fri, 15 Sep 2023 14:08:42 -0700 Subject: [PATCH] Basic charting for metrics using plotly.js rather than Mud Blazor. This removes the last dependency we have on mud blazor, so we have good alternatives. --- .../Components/DimensionedCounterView.razor | 3 +- .../DimensionedCounterView.razor.cs | 45 +++++++++++++++++-- OTLPView/Extensions/Helpers.cs | 6 +++ OTLPView/Pages/_Host.cshtml | 1 + 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/OTLPView/Components/DimensionedCounterView.razor b/OTLPView/Components/DimensionedCounterView.razor index 9fc62f6..b174e79 100644 --- a/OTLPView/Components/DimensionedCounterView.razor +++ b/OTLPView/Components/DimensionedCounterView.razor @@ -25,7 +25,8 @@ - + @* *@ + @( _graph)
Recent Values:
diff --git a/OTLPView/Components/DimensionedCounterView.razor.cs b/OTLPView/Components/DimensionedCounterView.razor.cs index f4f7e6f..9709b3d 100644 --- a/OTLPView/Components/DimensionedCounterView.razor.cs +++ b/OTLPView/Components/DimensionedCounterView.razor.cs @@ -1,15 +1,26 @@ +using Microsoft.JSInterop; +using static System.Runtime.InteropServices.JavaScript.JSType; + namespace OTLPView.Components; public sealed partial class DimensionedCounterView { + static int lastId = 0; + // Define the size of the graph based on the number of points and the duration of each point private const int GRAPH_POINT_COUNT = 18; // 3 minutes private const int GRAPH_POINT_SIZE = 10; // 10s + [Inject] + private IJSRuntime JSRuntime { get; set; } private DimensionScope _dimension; private string[] chartLabels; private List chartValues; + private readonly int _instanceID = ++lastId; + + private double[] _chartLabels; + private double[] _chartValues; [Parameter, EditorRequired] public required DimensionScope Dimension @@ -26,6 +37,7 @@ public required DimensionScope Dimension Data = CalcChartValues(_dimension, GRAPH_POINT_COUNT, GRAPH_POINT_SIZE) } }; + _chartValues = CalcChartValues(_dimension, GRAPH_POINT_COUNT, GRAPH_POINT_SIZE); } } @@ -35,6 +47,7 @@ public required DimensionScope Dimension protected override void OnInitialized() { chartLabels = CalcLabels(GRAPH_POINT_COUNT, GRAPH_POINT_SIZE); + _chartLabels = _CalcLabels(GRAPH_POINT_COUNT, GRAPH_POINT_SIZE); } private string[] CalcLabels(int pointCount, int pointSize) @@ -48,6 +61,17 @@ private string[] CalcLabels(int pointCount, int pointSize) return labels; } + private double[] _CalcLabels(int pointCount, int pointSize) + { + var duration = pointSize * pointCount; + var labels = new double[pointCount]; + for (var i = 0; i < pointCount; i++) + { + labels[i] = (pointSize * (i + 1)) - duration; + } + return labels; + } + // Graph is not based on x,y coordinates, but rather a series of data points with a value // Each point in the graph is the max value of all the values in that point's time range private double[] CalcChartValues(DimensionScope dimension, int pointCount, int pointSize) @@ -57,11 +81,11 @@ private double[] CalcChartValues(DimensionScope dimension, int pointCount, int p var now = DateTime.UtcNow; foreach (var point in dimension.Values) { - var start = CalcOffset(now-point.Start, pointCount, pointSize); - var end = CalcOffset(now-point.End, pointCount, pointSize); + var start = CalcOffset(now - point.Start, pointCount, pointSize); + var end = CalcOffset(now - point.End, pointCount, pointSize); if (start is not null && end is not null) { - for (var i = start.GetValueOrDefault(0); i <= end.GetValueOrDefault(pointCount-1); i++) + for (var i = start.GetValueOrDefault(0); i <= end.GetValueOrDefault(pointCount - 1); i++) { values[i] = point switch { @@ -95,6 +119,21 @@ private double[] CalcFakeValues(int pointCount) return values; } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + var data = new[]{ new { + x= _chartLabels, + y= _chartValues, + type= "scatter" + } }; + await JSRuntime.InvokeVoidAsync("Plotly.newPlot", $"lineChart{_instanceID}", data); + } + RenderFragment _graph => (builder) => + { + builder.AddMarkupContent(0, $$""" +
+"""); + }; } diff --git a/OTLPView/Extensions/Helpers.cs b/OTLPView/Extensions/Helpers.cs index 6beadb1..bb0d8b6 100644 --- a/OTLPView/Extensions/Helpers.cs +++ b/OTLPView/Extensions/Helpers.cs @@ -109,6 +109,12 @@ public static DateTime UnixNanoSecondsToDateTime(ulong unixTimeNanoSeconds) return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds).DateTime; } + public static string ToJSArray(this double[] values) => + $"[{string.Join(",", values)}]"; + + public static string ToJSArray(this string[] values) => + $"['{string.Join("','", values)}']"; + public static string ToHexString(this Google.Protobuf.ByteString bytes) { if (bytes is null or { Length: 0 }) diff --git a/OTLPView/Pages/_Host.cshtml b/OTLPView/Pages/_Host.cshtml index 8116a6e..64cbff6 100644 --- a/OTLPView/Pages/_Host.cshtml +++ b/OTLPView/Pages/_Host.cshtml @@ -36,5 +36,6 @@ +