B型リアルタイムオペレーショングラフ

<FONT COLOR="BLUE">

※動作検証としてMPU使用率を表示している様子
![123.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/43297928-d390-a21f-685f-b378455563f5.jpeg)
※ 動画 WQHD 2560x1440,自作機 MPU i5-7600K 3.80GHz
<iframe width="640" height="315" src="https://www.youtube.com/embed/T2H_ru3XaTo?si=elUxilZWcieMf8gc" title="YouTube video player" frameborder="1" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

</FONT>



::: note info
・心電図に興味を持ち同じ物を作ってみました。
　(職務上、病棟に行くのでたまに見かける)
・左から表示して行き(緑色)、一番右に達するとまた一番左に戻りデータを
　上書きして行く。
・前周のデータは見やすいように薄青に変えて履歴として表示。
・現在の値は右上に数値表示。100を超えると点滅。
・その他アイコン類は飾り。
・更新間隔を1分にすれば5時間記録されます。
・測定器等の出力値を指定するだけでリアルタイム表示が可能。
・JPGファイルは提供していないのでXAMLのjpg部は適当に要修正。
・更新速度、色等の変更は先頭のconst値を変える。

:::

<FONT COLOR="BLUE">

#### 1.心電図等に利用する方法</FONT>

Ga関数内の a[c++] =(int) (((int)(pc.NextValue()))*1.25);　この行を修正して下さい。
・a配列にデータを順次入れて行けばグラフ化されます。
　(各種装置からのソケットデータ、DB-SELECT値を設定する等が想定される)
・左側へのリターンも自動的に行われます。
・扱う範囲は0～200なのでデータ補正またはコードを修正して下さい。

遊びで作ったこんな簡単なコードでも業者に発注、購入すると高価だったりします。

<FONT COLOR="BLUE">

#### 2.参考デモ A型グラフはこちら
</FONT>

https://qiita.com/inf102/items/18d7e903bc0147e33367

A型は左から表示して行き、右端に達すると既存グラフを左スクロールさせて新規データは常に右に追加されて行く物、としています。
B型の方が面倒でしたが個人的にスクロールするA型が好み。


<FONT COLOR="BLUE">

#### 3.WPF (C#)</FONT>
600ライン超えてくると重くなりますのでCANVAS.Children.Clear()が必要な様です。
初めこれ知らなくて難儀しました。

``` c#
////////////////////////////////////////////////////////////////
// RealTimeOperation GRAPH TYPEB (WPF+Windows.Shapes NameSpace)
// (c) inf102 S.H 2023-2024
////////////////////////////////////////////////////////////////

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace NDMC_LOAD {

    public partial class MainWindow : Window {
        
        /////////////////////////////////////////////
        static int[] a = new int[1000]; // グラフデータ保存用

        // データ 更新間隔(mmSEC) Ex 500= 0.5Sec ,　1200=1.2Sec
        const int INTER = 100;
        
        // 初回表示管理用
        static bool flg=false;

        static bool OVER=false;
        static bool sw=false;      
        
        // グラフX軸
        const int GRA=2;

        // 新規グラフと履歴部の空白幅
        const int SPACE=45;
         
        //////////////////////////////////////////////////////// グラフ部 背景色
        const int BACK_R=60;
        const int BACK_G=70;
        const int BACK_B=100;

        //////////////////////////////////////////////////////// グラフ 線
        // 新規グラフ線 太さ
        const int DATALINE = 1;

        // 新規グラフ線 色
        const int DATALINE_R=0;
        const int DATALINE_G=255;
        const int DATALINE_B=0;

        // 新規グラフ線 透過率
        const int DATALINE_A=254; // 254 == 100%

        // 履歴グラフ線 色
        const int RDATALINE_R=0;
        const int RDATALINE_G=200;
        const int RDATALINE_B=205;
        
        // 履歴グラフ線 太さ
        const int RDATALINE = 1;

        //////////////////////////////////////////////////////// 中央線
        // 中央線太さ
        const int CENTERLINE =2;

        // 中央線色
        const int CENTERLINE_R =254;
        const int CENTERLINE_G =0;
        const int CENTERLINE_B =0;    
        
        // 中央線透過率
        const int CENTERLINE_A=200;
        
        ////////////////////////////////////////////////////////        
      
        public MainWindow() {
            InitializeComponent();
        }
    
         private void Window_Loaded(object sender, RoutedEventArgs e) {

            DATA_CANVAS.Children.Clear();
            BACK_CANVAS.Children.Clear();   

            DATA_CANVAS.Background=new SolidColorBrush(Color.FromArgb(254,BACK_R,BACK_G,BACK_B));
            BACK_CANVAS.Background=new SolidColorBrush(Color.FromArgb(254,147,170,204));

            BACK_CANVAS.Children.Add(CreateText("200", 14d, Brushes.Black, 7d, -5d,   500.0d, 30.0d, HorizontalAlignment.Left, VerticalAlignment.Center));
            BACK_CANVAS.Children.Add(CreateText("100", 14d, Brushes.Black, 7d, 87d,   500.0d, 30.0d, HorizontalAlignment.Left, VerticalAlignment.Center));
            BACK_CANVAS.Children.Add(CreateText("0",   14d, Brushes.Black, 13d, 185d, 500.0d, 30.0d, HorizontalAlignment.Left, VerticalAlignment.Center));
            
            // 数値点滅
            Task.Run(() => Proc1());

            // MAIN LOOP
            Ga();          
        }

        private ContentControl CreateText(string text, double fontSize, Brush brush, double x, double y, double widh, double height, HorizontalAlignment hAlign, VerticalAlignment vAlign){
        
            ContentControl content = new ContentControl();
            Canvas.SetLeft(content, x);
            Canvas.SetTop(content, y);
            content.Width = widh;
            content.Height = height;

            TextBlock tb = new TextBlock();
            tb.Text = text;
            tb.FontSize = fontSize;
            tb.Foreground = brush;
            tb.HorizontalAlignment = hAlign;
            tb.VerticalAlignment = vAlign;
            content.Content = tb;

            return content;
        }

        // グラフ描画
        public async void Ga(){
            int vt=SPACE;  // 最左部分は新しい描画が入る為、2回目以降表示させないため
            PerformanceCounter pc = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);

            int c=0;
            while (true){

                // 最左から右方向へ描画
                for (int xc=0;xc<=326;xc++){

                    await Task.Delay(INTER); 
                    a[c++] =(int) (((int)(pc.NextValue()))*1.25);

                    if (c>=327 ) c=0;

                    //  Title = DATA_CANVAS.Children.Count.ToString();

                    // 右側全て描画 初回は非表示(false)
                    if (flg == true){
                        ALL(vt);
                        vt+=2; 
                    }
                    else {
                        DATA_CANVAS.Children.Clear();
                        Line line1 = new Line();
                        line1.Stroke = new SolidColorBrush(Color.FromArgb(CENTERLINE_A,CENTERLINE_R , CENTERLINE_G,CENTERLINE_B));
		                line1.X1 = 0;
		                line1.Y1 = 100;
		                line1.X2 = 652;
		                line1.Y2 = 100;
                        line1.StrokeThickness = CENTERLINE;
                        DATA_CANVAS.Children.Add(line1);
                    }

                    // 新規左側の描画
                    Ga2(xc);
                }
                vt=SPACE; 
                flg=true;
            }
        }
         
        // 先頭からshまで描画
        public void Ga2(int sh){

            int StartLine_X=0;
            int EndLine    =GRA;

            Line line1 = new Line();

            // 先頭からshまで描画
            for (int t=0;t < sh;t++){
                                      
                line1 = new Line();
                line1.SnapsToDevicePixels=true;
		        line1.X1 = StartLine_X;
		        line1.Y1 = 200-a[t];
		        line1.X2 = EndLine;
		        line1.Y2 = 200-a[t+1];

                line1.StrokeThickness = DATALINE; // 太さ
                line1.Stroke = new SolidColorBrush (Color.FromArgb(DATALINE_A,DATALINE_R,DATALINE_G,DATALINE_B));
                DATA_CANVAS.Children.Add(line1);
                
                DATA.Text=a[t].ToString();
                if (a[t] >=100 ) OVER=false; 
                else OVER=true;

                StartLine_X += GRA;
                EndLine     += GRA;
                
             }
        }

        // 履歴右部分表示
        public void ALL(int cx){
                               
            int StartLine_X =0;
            int EndLine     =GRA;
            
            DATA_CANVAS.Children.Clear();
            Line line1 = new Line();
            line1.SnapsToDevicePixels=true;
            line1.Stroke = new SolidColorBrush(Color.FromArgb(CENTERLINE_A,CENTERLINE_R , CENTERLINE_G,CENTERLINE_B));
		    line1.X1 = 0;
		    line1.Y1 = 100;
		    line1.X2 = 652;
		    line1.Y2 = 100;
            line1.StrokeThickness = CENTERLINE;
            DATA_CANVAS.Children.Add(line1);
 
            for (int t=0;t < 9999;t++){
                         
                line1 = new Line();
                line1.SnapsToDevicePixels=true;
                line1.Y1 = 200-a[t+(cx/2)];
		        line1.X1 = StartLine_X+cx-1;     //X1=100 -> t+50
		        line1.X2 = EndLine+cx-1;
		        line1.Y2 = 200-a[t+1+(cx/2)];

                line1.StrokeThickness = RDATALINE; // 太さ
                line1.Stroke = new SolidColorBrush (Color.FromArgb(DATALINE_A,RDATALINE_R,RDATALINE_G,RDATALINE_B));

                DATA_CANVAS.Children.Add(line1);
                
                if (StartLine_X+cx >= 651) break;
                
                StartLine_X += GRA;
                EndLine     += GRA;              
             }
        }

        // 数値点滅 別スレッド
        void  Proc1(){
            while (true) {
                System.Threading.Thread.Sleep (350);
               
                // 100以下
                if(OVER == true) {
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Background =new SolidColorBrush(Color.FromArgb(255,0,0,0));
                        DATA.Foreground =new SolidColorBrush(Color.FromArgb(255,0,255,0));
                    }));
                    continue;

                }
                else{
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Foreground =new SolidColorBrush(Color.FromArgb(255,0,0,0));
                    }));
                }

                if (sw == true){
                    sw = !sw;
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Background =new SolidColorBrush(Color.FromArgb(255,0,0,0));
                    }));
                }
                else{
                    sw = !sw;
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Background =new SolidColorBrush(Color.FromArgb(255,0,255,0));
                    }));
                }
            }
        }
    }
}
```

<FONT COLOR="BLUE">

#### 4.WPF (XAML)</FONT>

```xml
<Window x:Class="NDMC_LOAD.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NDMC_LOAD"
        mc:Ignorable="d"
        Title="ﾘｱﾙﾀｲﾑｵﾍﾟﾚｰｼｮﾝ ｸﾞﾗﾌ ﾀｲﾌﾟB" Height="322" Width="860" Loaded="Window_Loaded" ResizeMode="NoResize">

    <Grid Height="319" VerticalAlignment="Top" Margin="0,1,0,0" HorizontalAlignment="Left" Width="860">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="690"/>
            <ColumnDefinition Width="121"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="212"/>
            <RowDefinition Height="55"/>
        </Grid.RowDefinitions>

        <Canvas x:Name="BACK_CANVAS" Grid.Column="0" Margin="1,0,0,0" Grid.Row="1" Grid.RowSpan="2" HorizontalAlignment="Left" Width="861" Grid.ColumnSpan="2" >
            <Rectangle  Panel.ZIndex="0"/>

        </Canvas>
        <Image Canvas.Left="777" Canvas.Top="136" Grid.Column="1" Margin="0,12,-26,23" Source="/DAT2.jpg"  Grid.RowSpan="2" Grid.Row="1" Stretch="None"/>
        <Canvas x:Name="DATA_CANVAS" Width="652" HorizontalAlignment="Left" Canvas.Left="10" Canvas.Top="10" Margin="31,0,0,0" Grid.Row="1" Height="202" VerticalAlignment="Center"  >
            <Rectangle  Panel.ZIndex="11"/>

        </Canvas>
        <Image  Grid.Column="0" Grid.ColumnSpan="2" Source="/TOP.jpg"  Height="24" VerticalAlignment="Center" Margin="1,0,-39,0"/>
        <TextBlock x:Name="DATA" Margin="53,20,-9,136" Grid.Row="1"  Foreground="Black" TextAlignment="Center"  Grid.Column="1" FontSize="43"/>
        <Image Height="42" Grid.Row="2" Grid.Column="0" Canvas.Left="147" Canvas.Top="187" VerticalAlignment="Top" Source="/DOWN.jpg" Margin="5,0,10,0"/>

    </Grid>
</Window>
```