CG Library SkiaSharp「A型リアルタイムオペレーショングラフ(デモ)」

<font COLOR="blue">
--------------------------------------------------------------------------------------------<BR>
<B>
・心電図、脳波計等のデータ表示アプリです。<BR>
・閾値を超えると注意喚起として円グラフが赤くなり、数値も点滅する仕様。<BR>
・非同期スレッドを多用してて結構複雑なコードになり、面倒なので一部コードのみ<BR>
　記載してます。<BR>
・縦モニタに10個位並べて遊んでたら、妻子に「暇だなぁ」と言われました。。<BR>
</B>
--------------------------------------------------------------------------------------------<BR>
</font>
<B>WQHD 2560x1440,自作機 i5-7600K 3.80GHz</B>
 
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f323832313838322f39623165613037632d663662302d353937312d633066342d3565613133653939316439622e6a706567.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/fedcec31-ead6-a878-02c3-2a8f9fa7073d.jpeg)


<iframe width="560" height="315" src="https://www.youtube.com/embed/fBtR_Jr7jIM?si=ZNIkMfeRKrlgIhnm" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

以前、職場のLinuxメールサーバが不調で負荷監視にtopコマンドを使用してたが、数値でわかり辛いのでWinForms版を急遽作成。WPF+SkiaSharp版として作り直し。

::: note info
- 開発にあたり、新たに考案した描画アルゴリズムを使用。
- 各種機器からソケットでデータを受信してグラフ化も可能。
- アイコン類は飾りです。
- 試験用にプリセットしたデータで疑似心電図の他、正弦波(y=sin x)もでます。
- 描画は一気に行う為、例えば下記の円グラフ描画ルーチン内でTask.Deley()は使えません。
※円グラフは円周上のXY点を算出し円中心から1本1本線を引いてグラフにしています。データが200(真円)の場合は360本ひいてる事になります。
:::
・WPF(SkiaSharp) サンプルコード
```c#        
// 円グラフ
void  OnPaintCIRCLE(object sender, SKPaintSurfaceEventArgs e){

    // グラフ部背景色
    e.Surface.Canvas.Clear(SKColors.Black);

    var skPaint = new SKPaint() {
        FilterQuality = SKFilterQuality.High,
        IsAntialias = true
    };

    skPaint.TextSize = 13f;
    skPaint.Color = SKColors.White;
    skPaint.Typeface = SKTypeface.FromFamilyName("LINE Seed JP_OTF");

    e.Surface.Canvas.DrawText("0", 72, 12, skPaint);
    e.Surface.Canvas.DrawText("50", 128, 70, skPaint);
    e.Surface.Canvas.DrawText("100", 64, 129, skPaint);
    e.Surface.Canvas.DrawText("150", 0, 70, skPaint);

    // NOMAL
    SKPaint A_LINE1= new SKPaint{
        Style =  SKPaintStyle.StrokeAndFill,
		
        Color = new SKColor(0, 155, 0),
        //  StrokeCap = (SKStrokeCap)50,
        IsAntialias=true,
        StrokeWidth = 2
    };

    // OVER 
    SKPaint A_LINE2= new SKPaint{
        Style =  SKPaintStyle.StrokeAndFill,
		//Color = SKColors.Red,
        Color = new SKColor(155, 0, 0),
        //  StrokeCap = (SKStrokeCap)10,
        IsAntialias=true,
                  
        StrokeWidth = 2
    };

    // BLACK
    SKPaint A_LINE3= new SKPaint{
        Style =  SKPaintStyle.StrokeAndFill,
		//Color = SKColors.Red,
        Color = new SKColor(0, 0, 0),
        //  StrokeCap = (SKStrokeCap)10,
        IsAntialias=true,
        StrokeWidth = 2
    };

    double y, x;
    // 扇描画　x1.8 は 0->200のデータを0->360に換算
    if(GC.IsChecked == false) {
        for(double h = 0; h < cnt2 * 1.8; h++) {
            x = 75 + 50 * Math.Sin(h * Math.PI / 180);
            y = 67 - 50 * Math.Cos(h * Math.PI / 180);

            if(cnt2 < Y_LINEDAT.Value) {
                e.Surface.Canvas.DrawLine(75, 67, (int)x, (int)y, A_LINE1);
            }
            else {
                e.Surface.Canvas.DrawLine(75, 67, (int)x, (int)y, A_LINE2);
            }
        }
    }
    else {
        // 扇描画　x1.8 は 0->200のデータを0->360に換算 (グラデーション有り)
        int vc = 50;
        for(double h = 0; h < cnt2 * 1.8; h++) {
            x = 75 + 50 * Math.Sin(h * Math.PI / 180);
            y = 67 - 50 * Math.Cos(h * Math.PI / 180);

            if(cnt2 < Y_LINEDAT.Value) {
                if(vc >= 256) vc = 255;
                A_LINE1.Color = new SKColor(0, (byte)vc++, 0);
                e.Surface.Canvas.DrawLine(75, 67, (int)x, (int)y, A_LINE1);

            }
            else {
                if(vc >= 256) vc = 255;
                A_LINE2.Color = new SKColor((byte)vc++, 0, 0);
                e.Surface.Canvas.DrawLine(75, 67, (int)x, (int)y, A_LINE2);

            }

        }
     }
            
     // 円の中心に黒い円を描いてアナログ計を修飾する
    if (GC2.IsChecked == true) e.Surface.Canvas.DrawCircle(75,67,30,A_LINE3);
  }
}