LineChart Component mit Blazor

Da ich die letzten Wochen unser ASP.NET Webforms basiertes CRM mit Blazor neu geschrieben habe standen auch ein paar Veränderungen an. Gerade die Grafik mit der Blazor Seite ist etwas Stiefmütterlich. Für ASP.NET liefert Microsoft noch eine Chart Komponente. Auch Reporting Services findet keinen direkten Support in .NET core. Letzens habe ich gezeigt wie man ein Tortendiagramm auf Basis von SVG zeichnet. SVG ist für Blazor wie HTML und sehr angenehm zu programmieren. SVG als Sprache weniger.

Dieses mal setze ich auf das gute alte System.Drawing Bitmap und zeichne eine Liniengrafik. Diese zeigt die Zugriffe auf ppedv.de, deren Rohdaten per Logparsers aus den IIS Logs granuliert und dann als CSV gespeichert werden. Täglich neu.

liniengrafik

Das und noch viel mehr klappt aber nur im Blazor Server und nicht in WASM. In der WASM Variante fehlt der Sandbox so ziemlich alles ala SQL Zugriff oder eben Grafik.

Ein paar Gedanken zum Design meiner Komponente anhand der Verwendung in einer .Razor Seite. Das Styling und sonstige Attribute fasse ich nicht an sondern überlasse das später einem HTML Image Element.

   1:   <LineChartPPEDV class="card-img-top"
   2:      ChartWidth="300"
   3:      ChartHeight="100"
   4:      BackGroundColor="#F0FFFF" LineColor="#4876FF"
   5:      Liste="VM.TageZugriff.Liste">
</
LineChartPPEDV>

Die Parameter für Höhe und Weite benötige ich später in der Logik für die Berechnungen und werden als selbige in der LineChart Komponente per [Parameter] deklariert.
Auch die Farben steuern wir extern ein. Die Hex Werte müssen in RGB Color Typen umgewandelt werden.
Schlussendlich noch die Daten als Int Array. Natürlich sind noch andere Werte in der Liste denkbar um zb die Achsen beschriften zu können. Meine Anforderung ist recht einfach. 1 Jahr jeden Tag.

Nun zur eigentlichen Blazor Line Chart Komponente. So richtig viel C# Code ist es nicht. Der besondere Trick hier ist, das das Image Element eine Base64 codiertes png erhhält und so die Datei des dynamisch gerenderten Bitmaps nicht existiert. Alles in Memory. Zum Test habe ich den Bitmap Stream in eine Datei geschrieben. Sind nur 2kb.

Wegen der Reihenfolge der Blazor Page Events, habe ich ParameterSet gewählt um das Bild zu zeichnen. Ohne Daten gabs eine Exception

 

   1:  @using System.Drawing
   2:  <img src="data:image/png;base64,@base64Image" 
@attributes="AdditionalAttributes">
   3:  @code {
   4:  string base64Image;
   5:  [Parameter]
   6:  [EditorRequired]
   7:  public string BackGroundColor { get; set; }
   8:  [Parameter]
   9:  [EditorRequired]
  10:  public string LineColor { get; set; }
  11:  [Parameter]
  12:  public int[] Liste { get; set; }
  13:  [Parameter]
  14:  [EditorRequired]
  15:  public int ChartWidth { get; set; }
  16:  [Parameter]
  17:  [EditorRequired]
  18:  public int ChartHeight { get; set; }
  19:  [Parameter(CaptureUnmatchedValues = true)]
  20:  public IReadOnlyDictionary<string, object> AdditionalAttributes { get; set; }
  21:  private Color bgColor;
  22:  private Color obsColor;
  23:  double MaxWert;
  24:  double MinWert = Double.MaxValue;
  25:  async protected override Task OnInitializedAsync()
  26:  {
  27:      bgColor = ColorTranslator.FromHtml(BackGroundColor);
  28:      obsColor = ColorTranslator.FromHtml(LineColor);
  29:   }
  30:  async protected override Task OnParametersSetAsync()
  31:  {
  32:      foreach (var number in Liste)
  33:      {
  34:          if ( number > 0)
  35:          {
  36:              if (MaxWert < number) MaxWert = number;
  37:              if (number != 0 && MinWert > number) MinWert = number;
  38:          }
  39:      }
  40:      //Install-Package System.Drawing.Common -Version 7.0.0
  41:      using var ms = new MemoryStream();
  42:      using Bitmap bitmap = new 
Bitmap(ChartWidth, ChartHeight);
  43:      using Graphics graphics = 
Graphics.FromImage(bitmap);
  44:      graphics.FillRectangle(
new SolidBrush(bgColor), 0, 0, ChartWidth, ChartHeight);
  45:      int y, y1;
  46:      int Delta = 0; //mal weglassen die Verschiebung auf der Achse
  47:      using (Pen pen = new Pen(new SolidBrush(obsColor), 2))
  48:      {
  49:          for (int i = 1; i < 365; i++)
  50:          {
  51:              y = (int)((((Liste[i] / MaxWert * ChartHeight)) - Delta) - ChartHeight) * -1;
  52:              y1 = (int)((((Liste[i + 1] / MaxWert * ChartHeight)) - Delta) - ChartHeight) * -1;
  53:              graphics.DrawLine(pen, new Point(i, y), new Point(i, y1));
  54:          }
  55:      }
  56:      bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
  57:      base64Image = Convert.ToBase64String(ms.ToArray());
  58:  }
  59:  }

 

Für das zeichnen in Bitmap hab ich die Beschreibung hier im Blog weggelassen. Mein “Trick”:  Ich zeichne immer einen Linie vom aktuellen Punkt zum nächsten. Deswegen Zeile 52 Liste[i+1].

Kommentare sind geschlossen