1339 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1339 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Collections.Generic;
 | |
| using System;
 | |
| using System.Drawing;
 | |
| using System.Diagnostics;
 | |
| using System.Data;
 | |
| using System.Collections;
 | |
| using System.Windows.Forms;
 | |
| using System.Linq;
 | |
| using System.Data.Linq;
 | |
| using System.Runtime.InteropServices;
 | |
| using TrendCtrlII;
 | |
| using AR;
 | |
| using System.Windows.Media.Animation;
 | |
| using System.Threading.Tasks;
 | |
| using System.Collections.Concurrent;
 | |
| using System.Diagnostics.Eventing.Reader;
 | |
| using System.Windows.Forms.DataVisualization.Charting;
 | |
| using System.Text.RegularExpressions;
 | |
| using OpenTK.Graphics.ES20;
 | |
| using ScottPlot.WinForms;
 | |
| using ScottPlot.Control;
 | |
| 
 | |
| namespace vmsnet
 | |
| {
 | |
| 
 | |
|     public partial class Frm_trend
 | |
|     {
 | |
|         ChartListData[] ChartListData = new ChartListData[10];
 | |
|         string SelectedGRPChValue = "";
 | |
|         List<int> totalChlist = new List<int>();
 | |
|         DocumentElement.CHANNELDataTable DTCHLIST;
 | |
| 
 | |
|         readonly ScottPlot.WinForms.FormsPlot formsPlot1;
 | |
| 
 | |
|         /* 작성자: 이재웅, 작성일: 2024-09-26, 내용: 데이터그리드 행의 전체선택인지 결정하는 변수 선언 */
 | |
|         private bool selALL = true;
 | |
| 
 | |
|         List<string> LoadFileList = new List<string>();
 | |
|         List<int> LoadCHList = new List<int>();
 | |
|         ScottPlot.Plottables.Crosshair CrossHair;
 | |
|         ScottPlot.Plottables.Scatter[] myPlots;
 | |
|         int RecordCount = 0;
 | |
|         ScottPlot.Plottables.VerticalLine[] CursorLine;
 | |
|         ScottPlot.Plottables.AxisLine PlottableBeingDragged = null;
 | |
|         List<DateTime>[] myPlotDataX = new List<DateTime>[0];
 | |
|         List<float>[] myPlotDataY = new List<float>[0];
 | |
| 
 | |
|         public Frm_trend()
 | |
|         {
 | |
|             // 디자이너에서 이 호출이 필요합니다.
 | |
|             InitializeComponent();
 | |
| 
 | |
|             PUB.INIT(out List<string> message);
 | |
| 
 | |
|             //차트 채널 및 파일데이터 변수
 | |
|             for (int i = 0; i < ChartListData.Length; i++)
 | |
|                 ChartListData[i] = new ChartListData();
 | |
| 
 | |
|             CursorLine = new ScottPlot.Plottables.VerticalLine[2];
 | |
| 
 | |
|             formsPlot1 = new ScottPlot.WinForms.FormsPlot() { Dock = DockStyle.Fill };
 | |
|             formsPlot1.MouseDown += FormsPlot1_MouseDown;
 | |
|             formsPlot1.MouseUp += FormsPlot1_MouseUp;
 | |
|             formsPlot1.MouseMove += FormsPlot1_MouseMove;
 | |
| 
 | |
|             panel8.Controls.Add(formsPlot1);
 | |
| 
 | |
|             // 초기 데이터 설정
 | |
|             FormsPlot_Init(formsPlot1); /* 작성자: 이재웅, 작성일: 2024-09-09 */
 | |
| 
 | |
|             /* 작성자: 이재웅, 작성일: 2024-09-26, 내용: 사용자에 의한 셀수정 차단 */
 | |
|             this.dv_chlist.EditMode = DataGridViewEditMode.EditProgrammatically;
 | |
|         }
 | |
| 
 | |
|         public void Frm_trend_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
 | |
|         {
 | |
|             if (this.dv_grp.SelectedRows.Count > 0)
 | |
|             {
 | |
|                 PUB.TREND.tv_selectgroup0 = this.cmb_group.SelectedIndex.ToString();
 | |
|                 PUB.TREND.tv_selectgroup = this.bs_grp.Position.ToString();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void Frm_trend_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
 | |
|         {
 | |
|             switch (e.KeyCode)
 | |
|             {
 | |
|                 case Keys.D:
 | |
|                     if (e.Control) this.formsPlot1.Refresh();
 | |
|                     break;
 | |
|                 case Keys.F10:
 | |
|                     this.bt_cursor1.PerformClick();
 | |
|                     break;
 | |
|                 case Keys.F11:
 | |
|                     this.bt_cursor2.PerformClick();
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|         public void Frm_trend_Load(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             this.Show();
 | |
|             Application.DoEvents();
 | |
| 
 | |
|             ////화면좌측의 그룹목록을 갱신
 | |
|             RefreshGroupList();
 | |
| 
 | |
|             ////마지막으로 선택한 그룹을 선택해준다.
 | |
|             var selidx0 = 0;
 | |
|             int.TryParse(PUB.TREND.tv_selectgroup0, out selidx0);
 | |
|             if (selidx0 < cmb_group.Items.Count)
 | |
|                 this.cmb_group.SelectedIndex = selidx0;
 | |
|             else
 | |
|                 this.cmb_group.SelectedIndex = this.cmb_group.Items.Count > 0 ? 0 : -1;
 | |
| 
 | |
|             var selidx = 0;
 | |
|             int.TryParse(PUB.TREND.tv_selectgroup, out selidx); // XMl.Data("trendview", "selectgroup", "0")
 | |
|             this.bs_grp.Position = selidx;
 | |
| 
 | |
|             ////모든채널정보를 가져온다.
 | |
|             PUB.smsg("Refresh GroupName");
 | |
|             DTCHLIST = new DocumentElement.CHANNELDataTable();// pub.DS.CHANNEL.Clone(); // DBC.GetTable("Select * from CHANNEL ORDER BY IDX")
 | |
|             DTCHLIST.Merge(PUB.DS.CHANNEL);
 | |
|             //DTCHLIST.Columns.Add("GRPNAME");
 | |
|             foreach (DocumentElement.CHANNELRow Dr in DTCHLIST.Rows)
 | |
|             {
 | |
|                 Dr.GRPNAME = PUBC.GetGrpName(Dr.GIDX);
 | |
|             }
 | |
|             DTCHLIST.AcceptChanges();
 | |
|             PUB.smsg("");
 | |
|             toolStripLabel3.Text = $"<PATH:{PUB.CONFIG.GetDatabasePath()}>";
 | |
| 
 | |
|             //scootplot();
 | |
|         }
 | |
| 
 | |
|         private ScottPlot.Plottables.AxisLine GetLineUnderMouse(float x, float y)
 | |
|         {
 | |
|             ScottPlot.CoordinateRect rect = formsPlot1.Plot.GetCoordinateRect(x, y, radius: 10);
 | |
| 
 | |
|             foreach (var axLine in formsPlot1.Plot.GetPlottables<ScottPlot.Plottables.AxisLine>().Reverse())
 | |
|             {
 | |
|                 if (axLine.IsUnderMouse(rect))
 | |
|                     return axLine;
 | |
|             }
 | |
| 
 | |
|             return null;
 | |
|         }
 | |
|         private void FormsPlot1_MouseDown(object sender, MouseEventArgs e)
 | |
|         {
 | |
|             var lineUnderMouse = GetLineUnderMouse(e.X, e.Y);
 | |
|             if (lineUnderMouse != null)
 | |
|             {
 | |
|                 PlottableBeingDragged = lineUnderMouse;
 | |
|                 formsPlot1.Interaction.Disable(); // disable panning while dragging
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void FormsPlot1_MouseUp(object sender, MouseEventArgs e)
 | |
|         {
 | |
|             PlottableBeingDragged = null;
 | |
|             formsPlot1.Interaction.Enable(); // enable panning again
 | |
|             formsPlot1.Refresh();
 | |
|             this.UpdateCursorValue();
 | |
|         }
 | |
| 
 | |
|         private void FormsPlot1_MouseMove(object sender, MouseEventArgs e)
 | |
|         {
 | |
|             // update cross line
 | |
|             ScottPlot.Pixel mousePixel = new ScottPlot.Pixel(e.X, e.Y);
 | |
|             ScottPlot.Coordinates mouseCoordinates = formsPlot1.Plot.GetCoordinates(mousePixel);
 | |
|             //this.Text = $"X={mouseCoordinates.X:N3}, Y={mouseCoordinates.Y:N3}";
 | |
|             if (CrossHair != null)
 | |
|             {
 | |
|                 CrossHair.Position = mouseCoordinates;
 | |
|                 var time = DateTime.FromOADate(mouseCoordinates.X);
 | |
| 
 | |
|                 CrossHair.VerticalLine.Text = $"{time:yy-MM-dd\nHH:mm:ss}";
 | |
|                 CrossHair.HorizontalLine.Text = $"{mouseCoordinates.Y:N2}v";
 | |
|                 formsPlot1.Refresh();
 | |
|             }
 | |
| 
 | |
| 
 | |
| 
 | |
|             // this rectangle is the area around the mouse in coordinate units
 | |
|             ScottPlot.CoordinateRect rect = formsPlot1.Plot.GetCoordinateRect(e.X, e.Y, radius: 10);
 | |
| 
 | |
|             // set cursor based on what's beneath the plottable
 | |
|             var lineUnderMouse = GetLineUnderMouse(e.X, e.Y);
 | |
| 
 | |
|             if (PlottableBeingDragged is null)
 | |
|             {
 | |
|                 if (lineUnderMouse is null) Cursor = Cursors.Default;
 | |
|                 else if (lineUnderMouse.IsDraggable && lineUnderMouse is ScottPlot.Plottables.VerticalLine) Cursor = Cursors.SizeWE;
 | |
|                 else if (lineUnderMouse.IsDraggable && lineUnderMouse is ScottPlot.Plottables.HorizontalLine) Cursor = Cursors.SizeNS;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // update the position of the plottable being dragged
 | |
|                 if (PlottableBeingDragged is ScottPlot.Plottables.HorizontalLine hl)
 | |
|                 {
 | |
|                     hl.Y = rect.VerticalCenter;
 | |
|                     hl.Text = $"{hl.Y:0.00}v";
 | |
|                 }
 | |
|                 else if (PlottableBeingDragged is ScottPlot.Plottables.VerticalLine vl)
 | |
|                 {
 | |
|                     vl.X = rect.HorizontalCenter;
 | |
|                     var time = DateTime.FromOADate(vl.X);
 | |
|                     //vl.Text = $"{vl.X:0.00}";
 | |
|                     if (lineUnderMouse == CursorLine[0])
 | |
|                         vl.Text = $"[C1] {time:yy-MM-dd\nHH:mm:ss}";
 | |
|                     else if (lineUnderMouse == CursorLine[1])
 | |
|                         vl.Text = $"[C2] {time:yy-MM-dd\nHH:mm:ss}";
 | |
|                     else
 | |
|                         vl.Text = $"{time:yy-MM-dd\nHH:mm:ss}";
 | |
|                 }
 | |
|                 formsPlot1.Refresh();
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 그룹목록을 추가합니다.
 | |
|         /// </summary>
 | |
|         /// <param name="name">표시그룸명(사용자구분추가)</param>
 | |
|         /// <param name="value">표시채널목록(comma)</param>
 | |
|         /// <param name="idx">일련번호</param>
 | |
|         /// <param name="rname">그룹명</param>
 | |
|         /// <remarks></remarks>
 | |
|         private void AddGroupRow(string name, int idx, string value, string rname)
 | |
|         {
 | |
|             ////최대idx를 찾아서 그보다 크게한다.
 | |
|             var dr = this.dS1.group.NewgroupRow(); // Me.DataSet1.Tables("group").NewRow
 | |
|             dr.cname = name;
 | |
|             dr.value = value;
 | |
|             dr.idx = idx;
 | |
|             dr.rname = rname;
 | |
|             dS1.group.AddgroupRow(dr);
 | |
|             dS1.group.AcceptChanges();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 표시그룹목록을 갱신합니다. 좌측하단
 | |
|         /// </summary>
 | |
|         /// <remarks></remarks>
 | |
|         private void RefreshGroupList()
 | |
|         {
 | |
| 
 | |
|             ////상단 그룹목록
 | |
|             //Dim sql As String = "Select * from GRP where USE=1 order by TITLE"
 | |
|             var DT = PUB.DS.GRP.Where(t => t.USE == 1).OrderBy(t => t.TITLE).ToList();//.CopyToDataTable();//.Select("use=1", "title") as DocumentElement.GRPRow[]; // DBC.GetTable(sql)
 | |
|             this.cmb_group.DataSource = DT;
 | |
|             this.cmb_group.DisplayMember = "TITLE";
 | |
|             this.cmb_group.ValueMember = "IDX";
 | |
|             if (DT.Count() > 0)
 | |
|             {
 | |
|                 this.cmb_group.SelectedIndex = 0;
 | |
|             }
 | |
| 
 | |
|             ////현재의 그룹목록을 삭제
 | |
|             dS1.group.Clear();
 | |
| 
 | |
|             ////사용자그룹추가
 | |
|             //sql = "select * from VIEWGROUP order by TITLE,IDx"
 | |
|             foreach (DocumentElement.VIEWGROUPRow dr in PUB.DS.VIEWGROUP.Select("", "title,idx")) //  DBC.GetTable(sql).Rows
 | |
|             {
 | |
|                 string v = dr.VAL.Trim();
 | |
|                 if (string.IsNullOrEmpty(v))
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 string newgrpname = "[사용자] " + dr.TITLE;
 | |
|                 AddGroupRow(newgrpname, dr.IDX, v, dr.GNAME);
 | |
|             }
 | |
| 
 | |
|             ////시스템그룹추가
 | |
|             // sql = "select * from GRP where USE=1"
 | |
|             totalChlist.Clear();
 | |
| 
 | |
|             foreach (DocumentElement.GRPRow Dr in PUB.DS.GRP.Select("use=1")) // DBC.GetTable(sql).Rows
 | |
|             {
 | |
|                 ////이그룹을 사용하는 채널중 사용채널을 찾는다.
 | |
|                 string v = "";
 | |
|                 foreach (DocumentElement.CHANNELRow Dr2 in PUB.DS.CHANNEL.Select("gidx=" + Dr.IDX.ToString() + " and enable=1", "idx")) // DBC.GetTable("select * from CHANNEL where GIDX=" & Dr("IDX") & " AND ENABLE=1 ORDER BY IDX").Rows
 | |
|                 {
 | |
|                     v += System.Convert.ToString((string.IsNullOrEmpty(v) ? "" : ",") + Dr2.IDX.ToString());
 | |
| 
 | |
|                     if (totalChlist.Contains(Dr2.IDX) == false)
 | |
|                     {
 | |
|                         totalChlist.Add(Dr2.IDX);
 | |
|                     }
 | |
|                 }
 | |
|                 if (!string.IsNullOrEmpty(v))
 | |
|                 {
 | |
|                     //AddGroupRow("[시스템]" + Dr.TITLE, Dr.IDX, v, Dr.TITLE);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             short AllIDX = (short)dS1.group.Rows.Count; ////전체보기메뉴의 인덱스
 | |
|             AddGroupRow("모든채널표시", -1, "", "전체");
 | |
|         }
 | |
| 
 | |
|         #region 우측 채널 목록
 | |
| 
 | |
|         ////우측채널목록을 갱신합니다.
 | |
|         private void RefreshChannelList()
 | |
|         {
 | |
|             this.dS1.channel.Rows.Clear();
 | |
|             this.dS1.channel.AcceptChanges();
 | |
| 
 | |
|             //파일목록가져온다
 | |
|             GrabFilelist();
 | |
| 
 | |
|             foreach (var charr in this.ChartListData)
 | |
|             {
 | |
|                 foreach (var ch in charr.ChannelList)
 | |
|                 {
 | |
|                     //전체채널목록에 포함되어있는 대상중 채널목록에 존재하지 않는 경우에만 처리한다.
 | |
|                     if (DTCHLIST.Where(t => t.IDX == ch).Any() && this.dS1.channel.Where(t => t.idx == ch).Any() == false)
 | |
|                     {
 | |
|                         //전체채널정보에서 데이터 수집
 | |
|                         var CHDataRow = DTCHLIST.Rows[ch - 1] as DocumentElement.CHANNELRow;
 | |
|                         if (CHDataRow == null) continue;
 | |
| 
 | |
|                         //채널목록에도 추가한다.
 | |
|                         var activeCount = this.dS1.channel.Where(t => t.use == true).Count();
 | |
|                         var Dr = this.dS1.channel.NewchannelRow();
 | |
|                         Dr.use = activeCount < PUB.CONFIG.MaxChCount;
 | |
|                         Dr.cname = CHDataRow.TITLE;
 | |
|                         Dr.idx = ch;
 | |
|                         Dr.cc = CHDataRow.COLOR;
 | |
|                         Dr.tidx = this.dS1.channel.Rows.Count; //// chinof 의 index번호를 설정해야한다.
 | |
|                         this.dS1.channel.Rows.Add(Dr);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             this.dS1.channel.AcceptChanges();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
| 
 | |
| 
 | |
|         void GrabFilelist()
 | |
|         {
 | |
|             /* 주석날짜: 2024-09-20 | 주석내용: VIEWGROUP.xml 파일내용 | 주석자: 이재웅
 | |
|              * 
 | |
|              * <VIEWGROUUP>
 | |
|              *   <IDX>9</IDX>
 | |
|              *   <GNAME>EL2500A</GNAME>
 | |
|              *   <TITLE>GRP(1...10)</TITLE>
 | |
|              *   <VAL>1,2,3,4,5,6,7,8,9,10</VAL>
 | |
|              * </VIEWGROUUP>
 | |
|              * 
 | |
|              **************************************
 | |
|              *
 | |
|              * DRGRP.idx = 9
 | |
|              * DRGRP.mame = "EL2500A"
 | |
|              * DRGRP.cname = "[사용자] GRP(1...10)"
 | |
|              * DRGRP.value = "1,2,3,4,5,6,7,8,9,10"
 | |
|              */
 | |
| 
 | |
|             var sttdate = PUB.TREND.graph_time_start;
 | |
|             var enddate = PUB.TREND.graph_time_end;
 | |
|             //각 파일 그룹별 대상 파일을 수집합니다.
 | |
|             Parallel.For(0, this.ChartListData.Length - 1, i =>
 | |
|             {
 | |
|                 var DataFileName = $"DATAB{i + 1}";
 | |
|                 if (ChartListData[i].ChannelList.Any() == true) this.ChartListData[i].FileList = PUB.DB.GetfileS(DataFileName, sttdate, enddate);
 | |
|                 else this.ChartListData[i].FileList = new List<string>();
 | |
| 
 | |
|                 Console.WriteLine($"Processing index {i} on thread {Task.CurrentId}");
 | |
|             });
 | |
| 
 | |
|         }
 | |
| 
 | |
|         private void FormsPlot_Init(ScottPlot.WinForms.FormsPlot plot)
 | |
|         {
 | |
|             plot.Plot.Clear();
 | |
| 
 | |
|             // 초기 데이터 설정
 | |
|             plot.Plot.Add.Palette = new ScottPlot.Palettes.Penumbra();
 | |
|             // change figure colors
 | |
|             plot.Plot.FigureBackground.Color = ScottPlot.Color.FromHex("#181818");
 | |
|             plot.Plot.DataBackground.Color = ScottPlot.Color.FromHex("#1f1f1f");
 | |
| 
 | |
|             // change axis and grid colors
 | |
|             plot.Plot.Axes.Color(ScottPlot.Color.FromHex("#d7d7d7"));
 | |
|             plot.Plot.Grid.MajorLineColor = ScottPlot.Color.FromHex("#404040");
 | |
| 
 | |
|             // change legend colors
 | |
|             plot.Plot.Legend.BackgroundColor = ScottPlot.Color.FromHex("#404040");
 | |
|             plot.Plot.Legend.FontColor = ScottPlot.Color.FromHex("#d7d7d7");
 | |
|             plot.Plot.Legend.OutlineColor = ScottPlot.Color.FromHex("#d7d7d7");
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 데이터를 조회합니다.
 | |
|         /// </summary>
 | |
|         /// <param name="SearchFileList">파일목록을 다시 갱신합니다.</param>
 | |
|         /// <remarks></remarks>
 | |
|         private void ShowData(bool AllClear = true)
 | |
|         {
 | |
|             //return;
 | |
|             Console.WriteLine("Enter : ShowData");
 | |
|             this.Text = $"TrendViewer ({cmb_group.Text})";
 | |
|             this.lb_selgroup.Text = $"[{cmb_group.Text}]";
 | |
| 
 | |
|             DateTime SDTotal = DateTime.Now;
 | |
|             var chcount2 = this.dS1.channel.Rows.Count;
 | |
|             if (chcount2 == 0)
 | |
|             {
 | |
|                 UTIL.MsgE($"선택된 채널목록이 없습니다\n채널그룹이 손상되었거나 다시 선택하세요");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             GrabFilelist();
 | |
| 
 | |
|             TimeSpan Tsing = DateTime.Now - SDTotal;
 | |
|             Console.WriteLine($"[ShowData] Title And Ch : {Tsing.TotalMilliseconds}ms");
 | |
| 
 | |
| 
 | |
|             DateTime fsd = DateTime.Now;
 | |
|             var FileCount = ChartListData.Sum(t => t.FileList.Count);
 | |
|             Tsing = DateTime.Now - SDTotal;
 | |
|             Console.WriteLine($"[ShowData] {FileCount} Files Checked : {Tsing.TotalMilliseconds}");
 | |
|             TimeSpan fts = DateTime.Now - fsd;
 | |
|             lb_filesearchtime.Text = $"[Search : {fts.TotalMilliseconds}ms]";
 | |
| 
 | |
|             ////Record Count Check
 | |
|             var avdate = PUB.DB.GetAvailableDates();    //변수선언 이동
 | |
|             if (FileCount == 0)
 | |
|             {
 | |
|                 Console.WriteLine("ShowData : FileCount 0 Refresh");
 | |
|                 PUB.smsg("");
 | |
| 
 | |
|                 //var avdate = PUB.DB.GetAvailableDates();  //전위치
 | |
|                 if (avdate.Any() == false)
 | |
|                 {
 | |
|                     UTIL.MsgE("지정된 폴더내에 저장된 자료가 없습니다");
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     UTIL.MsgI("기간내 조회된 자료가 없습니다\n\n조회 가능 범위\n\n" +
 | |
|                         $"{avdate.First().Year}-{avdate.First().Month}~" +
 | |
|                         $"{avdate.Last().Year}-{avdate.Last().Month}");
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             Tsing = DateTime.Now - SDTotal;
 | |
|             Console.WriteLine($"[ShowData] Set Date Area : {Tsing.TotalMilliseconds}");
 | |
| 
 | |
|             //채널수만큼 데이터버퍼를 확보한다.
 | |
|             var maxchno = this.dS1.channel.Max(t => t.idx); //idx는 실제 채널번호가 들어있다(1~
 | |
|             this.myPlotDataX = new List<DateTime>[maxchno];
 | |
|             this.myPlotDataY = new List<float>[maxchno];
 | |
| 
 | |
|             // 채널 개수만큼 Scatter 그래프 생성
 | |
|             this.myPlots = new ScottPlot.Plottables.Scatter[maxchno];
 | |
| 
 | |
|             //커서삭제
 | |
|             this.CursorLine[0] = null;
 | |
|             this.CursorLine[1] = null;
 | |
| 
 | |
|             ////데이터를 모두 초기화하는경우
 | |
|             if (AllClear)
 | |
|             {
 | |
|                 LoadFileList.Clear();
 | |
|                 LoadCHList.Clear();
 | |
|                 Tsing = DateTime.Now - SDTotal;
 | |
|                 Console.WriteLine($"[ShowData] Clear Data : {Tsing.TotalMilliseconds}");
 | |
|             }
 | |
| 
 | |
|             //커서데이터 삭제
 | |
|             foreach (DS1.channelRow dr in this.dS1.channel)
 | |
|             {
 | |
|                 dr.c1 = "";
 | |
|                 dr.c2 = "";
 | |
|             }
 | |
|             this.dS1.channel.AcceptChanges();
 | |
| 
 | |
| 
 | |
|             ////추가된채널목록을 가진다.
 | |
|             DateTime STime = DateTime.Now;
 | |
| 
 | |
|             int totalchcount = this.dS1.channel.Rows.Count;
 | |
|             if (totalchcount > PUB.CONFIG.MaxChCount)
 | |
|             {
 | |
|                 UTIL.MsgE($"채널 수({totalchcount})가 {PUB.CONFIG.MaxChCount}을 초과 합니다. [{PUB.CONFIG.MaxChCount}]이하로 사용자 채널을 생성하여 조회 하세요");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             /* 주석날짜: 2024-09-20 | 주석자: 이재웅
 | |
|              * 
 | |
|              * ParseChDataToChart() : 채널데이터를 차트데이터로 변환 
 | |
|              */
 | |
| 
 | |
|             //대상파일의 자료를 읽어와서 차트데이터를 구축한다.
 | |
|             RecordCount = 0;
 | |
|             Parallel.For(0, this.ChartListData.Length, i =>
 | |
|             {
 | |
|                 ParseChDataToChart(i, ChartListData[i], DTCHLIST);
 | |
|             });
 | |
| 
 | |
|             Tsing = DateTime.Now - SDTotal;
 | |
|             Console.WriteLine($"[ShowData] Pase Data Complete : {Tsing.TotalMilliseconds}");
 | |
| 
 | |
|             var sttdate = PUB.TREND.graph_time_start;
 | |
|             var enddate = PUB.TREND.graph_time_end;
 | |
|             TimeSpan term = DateTime.Now - STime;
 | |
| 
 | |
|             ////조회영역 및 쿼리시간표시
 | |
|             this.lb_Area.Text = "[ " + sttdate.ToString("yy-MM-dd HH:mm:ss") + "~" + enddate.ToString("yy-MM-dd HH:mm:ss") + " ]";
 | |
|             this.lb_querytime.Text = $"[Loading : {term.TotalMilliseconds:#0.0}ms ]";
 | |
| 
 | |
|             ////SET OK
 | |
|             STime = DateTime.Now;
 | |
|             Console.WriteLine("ShowData : Chart Refresh");
 | |
| 
 | |
|             term = DateTime.Now - STime;
 | |
|             this.lb_charttime.Text = $"[Chart : {term.TotalMilliseconds:#0.0}ms ]";
 | |
| 
 | |
|             Tsing = DateTime.Now - SDTotal;
 | |
|             //Console.WriteLine($"[ShowData] Chart Refresh : {Tsing.TotalMilliseconds:#0.0}");
 | |
| 
 | |
|             TimeSpan Tstotal = DateTime.Now - SDTotal;
 | |
|             this.lb_totaltime.Text = $"[total : {Tstotal.TotalMilliseconds:#0.0}ms]";
 | |
| 
 | |
|             Tsing = DateTime.Now - SDTotal;
 | |
|             //Console.WriteLine($"[ShowData] Complete : {Tsing.TotalMilliseconds:#0.0}");
 | |
| 
 | |
| 
 | |
| 
 | |
|             // 초기 데이터 생성
 | |
|             //this.formsPlot1.Plot.Clear();
 | |
|             FormsPlot_Init(formsPlot1);
 | |
| 
 | |
|             #region 이전 코드 주석처리
 | |
|             //formsPlot1.Plot.Add.Palette = new ScottPlot.Palettes.Penumbra();
 | |
|             //// change figure colors
 | |
|             //formsPlot1.Plot.FigureBackground.Color = ScottPlot.Color.FromHex("#181818");
 | |
|             //formsPlot1.Plot.DataBackground.Color = ScottPlot.Color.FromHex("#1f1f1f");
 | |
| 
 | |
|             //// change axis and grid colors
 | |
|             //formsPlot1.Plot.Axes.Color(ScottPlot.Color.FromHex("#d7d7d7"));
 | |
|             //formsPlot1.Plot.Grid.MajorLineColor = ScottPlot.Color.FromHex("#404040");
 | |
| 
 | |
|             //// change legend colors
 | |
|             //formsPlot1.Plot.Legend.BackgroundColor = ScottPlot.Color.FromHex("#404040");
 | |
|             //formsPlot1.Plot.Legend.FontColor = ScottPlot.Color.FromHex("#d7d7d7");
 | |
|             //formsPlot1.Plot.Legend.OutlineColor = ScottPlot.Color.FromHex("#d7d7d7");
 | |
|             #endregion
 | |
| 
 | |
|             /* 주석날짜: 2024-09-20 | 주석내용: 채널별 데이터 그리기 | 주석자: 이재웅
 | |
|              * 
 | |
|              * xs : x축 List<DateTime>[] 형식의 데이터
 | |
|              * ys : y축 List<float>[] 형식의 데이터
 | |
|              * myScatter : x,y 좌표를 가지는 ScottPlot.Plottables.Scatter 형식의 데이터
 | |
|              * 
 | |
|              * 명시적선언時: List<DateTime>[] myPlotDataX
 | |
|              * 명시적선언時: List<float>[] myPlotDataY
 | |
|              * 명시적선언時: ScottPlot.Plottables.Scatter myScatter
 | |
|              */
 | |
| 
 | |
|             for (int i = 0; i < this.myPlots.Length; i++)
 | |
|             {
 | |
|                 var xs = myPlotDataX[i];
 | |
|                 if (xs == null || xs.Any() == false) continue;
 | |
|                 var ys = myPlotDataY[i];
 | |
|                 var myScatter = formsPlot1.Plot.Add.Scatter(xs, ys);
 | |
| 
 | |
|                 //if (i > 2) break;
 | |
|                 //채널정보에서 색상을 가져온다.
 | |
|                 var chinfo = this.dS1.channel.Where(t => t.idx == i + 1).FirstOrDefault();    //idx에 실제 채널정보가 들어있으니 -1 해야함
 | |
|                 if (chinfo != null)
 | |
|                 {
 | |
|                     var linecolor = Color.FromArgb(chinfo.cc);
 | |
|                     myScatter.LineColor = new ScottPlot.Color(linecolor.R, linecolor.G, linecolor.B);
 | |
|                 }
 | |
|                 else myScatter.LineColor = ScottPlot.Colors.Red;
 | |
|                 myScatter.Color = myScatter.LineColor;
 | |
|                 /* 작성자: 이재웅, 작성일: 2024-11-27, 내용: 변경한 셀이름으로 차트범례 표시 */
 | |
|                 myScatter.LegendText = chinfo.ItemArray[1].ToString(); //$"CH{i + 1}";
 | |
|                 this.myPlots[i] = myScatter;    //visible 변경 및 데이터 접근을 위해 변수에 따로 저장해둔다.
 | |
|             }
 | |
|             formsPlot1.Plot.Axes.DateTimeTicksBottom();
 | |
| 
 | |
|             //1번항목을 가져와서 x,y축 range 값 설정
 | |
|             var plot = this.myPlots.Where(t => t != null).FirstOrDefault();
 | |
|             if (plot != null)
 | |
|             { // 파일이 있더라도 해당하는 데이터가 없을때 Error 발생
 | |
|                 var ymin = plot.Data.GetLimitsY().Min;
 | |
|                 var ymax = plot.Data.GetLimitsY().Max;
 | |
|                 var xmin = plot.Data.GetLimitsX().Min;
 | |
|                 var xmax = plot.Data.GetLimitsX().Max;
 | |
|                 var maxdate = DateTime.FromOADate(xmin);
 | |
|                 var mindate = DateTime.FromOADate(xmax);
 | |
|             }
 | |
|             this.lb_datatcnt.Text = $"[ {FileCount} Files / {RecordCount} Records ]";
 | |
|             CrossHair = formsPlot1.Plot.Add.Crosshair(0, 0);
 | |
|             CrossHair.TextColor = ScottPlot.Colors.Red;
 | |
|             CrossHair.TextBackgroundColor = CrossHair.HorizontalLine.Color;
 | |
| 
 | |
|             //축설정
 | |
|             formsPlot1.Plot.Axes.AutoScaleX();
 | |
|             if (PUB.TREND.y_scale_auto)
 | |
|                 formsPlot1.Plot.Axes.AutoScaleY();
 | |
|             else
 | |
|                 formsPlot1.Plot.Axes.SetLimitsY(PUB.TREND.graph_y_start, PUB.TREND.graph_y_end);
 | |
| 
 | |
|             formsPlot1.Plot.YLabel("VOLTAGE");
 | |
| 
 | |
| 
 | |
|             //X축 바닥 여백 변경
 | |
|             formsPlot1.Plot.Axes.Bottom.MinimumSize = PUB.TREND.graph_bottom_minsize;
 | |
| 
 | |
|             //십자선추가
 | |
|             CrossHair = formsPlot1.Plot.Add.Crosshair(0, 0);
 | |
|             CrossHair.TextColor = ScottPlot.Colors.White;
 | |
|             CrossHair.TextBackgroundColor = CrossHair.HorizontalLine.Color;
 | |
| 
 | |
|             //X축 날짜시간형태로 표시
 | |
|             formsPlot1.Plot.RenderManager.RenderStarting += (s1, e1) =>
 | |
|             {
 | |
|                 ScottPlot.Tick[] ticks = formsPlot1.Plot.Axes.Bottom.TickGenerator.Ticks;
 | |
|                 for (int i = 0; i < ticks.Length; i++)
 | |
|                 {
 | |
|                     DateTime dt = DateTime.FromOADate(ticks[i].Position);
 | |
|                     string label = $"{dt:yy-MM-dd\nHH:mm:ss}";
 | |
|                     ticks[i] = new ScottPlot.Tick(ticks[i].Position, label);
 | |
|                 }
 | |
|             };
 | |
| 
 | |
|             // the Style object contains helper methods to style many items at once
 | |
|             formsPlot1.Plot.Axes.Color(ScottPlot.Color.FromHex("#a0acb5"));
 | |
|             formsPlot1.Refresh();
 | |
| 
 | |
|             if (RecordCount == 0)
 | |
|             {
 | |
|                 string msg = $"[{sttdate.ToString("yyyy-MM-dd")} ~ {enddate.ToString("yyyy-MM-dd")}] : 데이터가 존재하지 않습니다.";
 | |
|                 PUB.log.Add(msg);
 | |
|                 UTIL.MsgE(msg);
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|         }
 | |
| 
 | |
|         private void ParseChDataToChart(int idx, ChartListData chlist, DocumentElement.CHANNELDataTable DTCHList)
 | |
|         { // 지정한 날짜구간 내의 파일들을 읽음 (채널데이터 → 차트데이터)
 | |
| 
 | |
|             //데이터가 없는 경우 빠져 나감
 | |
|             if (chlist.ChannelList.Any() == false || chlist.FileList.Any() == false)
 | |
|             {
 | |
|                 if (chlist.ChannelList.Any() || chlist.FileList.Any())
 | |
|                     PUB.log.Add($"Load Skip Ch:{chlist.ChannelList.Count},file:{chlist.FileList.Count}");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             //지정된 기간의 데이터를 취해야 하므로 날짜 정보를 가져온다.
 | |
|             long SDtime = PUB.TREND.graph_time_start.ToFileTime();//  SttDate.ToFileTime();
 | |
|             long EDtime = PUB.TREND.graph_time_end.ToFileTime();// EndDate.ToFileTime();
 | |
| 
 | |
|             //속해있는채널정보를 가져온다.
 | |
| 
 | |
|             //대상 파일 전체를 확인하여, 지정된 기간내라면 자료를 수집힌다.
 | |
|             foreach (string file in chlist.FileList)
 | |
|             {
 | |
|                 ////이파일명이 로딩되었다면 불러오지 않는다.
 | |
|                 if (LoadFileList.Contains(file) == true) continue;// TrendCtrl1.Files.IndexOf(file) == -1)
 | |
|                 else LoadFileList.Add(file); //불러온기록에 추가
 | |
| 
 | |
| 
 | |
|                 ////해당파일의 지정시간내의 데이터를 모두 읽어온다.
 | |
|                 using (var FS = new System.IO.FileStream(file, System.IO.FileMode.Open))
 | |
|                 using (var SR = new System.IO.StreamReader(FS, System.Text.Encoding.Default))
 | |
|                     while (SR.Peek() != 0)
 | |
|                     {
 | |
|                         string Line = SR.ReadLine();
 | |
|                         if (Line == null) break; //null값이 오는 경우가 있다, 오류 혹은 파일끝에서 발생되었음, 더이상 처리하지 않는다.
 | |
|                         if (Line.Trim() == "") continue;  //빈 줄은 무시한다.
 | |
| 
 | |
|                         string[] buf = Line.Split('\t'); //각 데이터는 탭으로 분리 되어있다.
 | |
|                         if (buf.Length < 8 || buf[1].ToUpper() == "TIME") continue; //제목줄 처리하지 않는다.
 | |
| 
 | |
|                         if (long.TryParse(buf[1], out long TIme) == false) continue;  //1번항목은 시간이고, 그 이후에 채널 데이터가 들어있다.
 | |
| 
 | |
|                         ////속해있는 채널정보를 모두 가져온다.
 | |
|                         foreach (var c in chlist.ChannelList) ////채널목록을 이용하여 데이터를 가져온다.
 | |
|                         {
 | |
|                             //채널정보 확인
 | |
|                             string GRP_NAME, GRP_TITLE;
 | |
|                             Color GRP_COLOR;
 | |
|                             if (LoadCHList.Contains(c) == false)
 | |
|                             {
 | |
|                                 var CHDataRow = DTCHList.Where(t => t.IDX == c).FirstOrDefault();
 | |
|                                 if (CHDataRow == null) continue; //데이터가없다면 처리하지 않는다.
 | |
|                                 else LoadCHList.Add(c);
 | |
|                                 GRP_NAME = CHDataRow.GRPNAME;
 | |
|                                 GRP_TITLE = CHDataRow.TITLE;
 | |
|                                 GRP_COLOR = Color.FromArgb(CHDataRow.COLOR);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 GRP_NAME = "";
 | |
|                                 GRP_TITLE = "";
 | |
|                                 GRP_COLOR = Color.Black;
 | |
|                             }
 | |
| 
 | |
|                             //각 파일당 160개씩 저장되어있으므로 채널번호를 통해서 파일의 위치를 파악해야한다.
 | |
|                             var chIndexFromFile = PUB.GetChannelIndexFromFileBuffer(c);
 | |
| 
 | |
|                             //숫자값에 문제가 있다면 처리하지 않는다.(0번버퍼는 항상 blank 이기 때문에 인덱스+1해야 데이터인덱스가 맞다)
 | |
|                             if ((chIndexFromFile + 1) >= buf.Length || float.TryParse(buf[chIndexFromFile + 1], out float valueS) == false) continue;
 | |
| 
 | |
|                             //Decpos 데이터가 있다면 적용한다
 | |
|                             if (PUB.CONFIG.datadiv != 0 && PUB.CONFIG.datadiv != 1)
 | |
|                                 valueS = (valueS / PUB.CONFIG.datadiv);
 | |
| 
 | |
|                             //데이터추가
 | |
|                             //TrendCtrl1.AddData(TIme, c, valueS, GRP_NAME, GRP_TITLE, GRP_COLOR);
 | |
|                             if (c > myPlotDataX.GetUpperBound(0))
 | |
|                             {
 | |
|                                 Array.Resize(ref myPlotDataX, c);
 | |
|                                 Array.Resize(ref myPlotDataY, c);
 | |
| 
 | |
|                             }
 | |
|                             if (myPlotDataX[c - 1] == null)
 | |
|                             {
 | |
|                                 myPlotDataX[c - 1] = new List<DateTime>();
 | |
|                                 myPlotDataY[c - 1] = new List<float>();
 | |
|                             }
 | |
|                             myPlotDataX[c - 1].Add(DateTime.FromFileTime(TIme));
 | |
|                             myPlotDataY[c - 1].Add(valueS);
 | |
| 
 | |
|                             RecordCount += 1;
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void LinkLabel5_LinkClicked(System.Object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
 | |
|         {
 | |
|             addnewGroup();
 | |
|         }
 | |
|         private void SaveViewGroup()
 | |
|         {
 | |
|             string[] BackTables = new string[] { "VIEWGROUP" };
 | |
|             foreach (string tabname in BackTables)
 | |
|             {
 | |
|                 PUB.DS.Tables[tabname].AcceptChanges();
 | |
|                 var file = System.IO.Path.Combine(PUB.CONFIG.GetDatabasePath(), "Database", "Config", $"{tabname}.xml");
 | |
|                 var fi = new System.IO.FileInfo(file);
 | |
|                 if (fi.Directory.Exists == false) fi.Directory.Create();
 | |
|                 PUB.DS.Tables[tabname].WriteXml(fi.FullName, XmlWriteMode.IgnoreSchema);
 | |
|             }
 | |
|         }
 | |
|         private void addnewGroup()
 | |
|         {
 | |
|             ////전체채널목록을 생성한다.
 | |
|             var group_name = this.cmb_group.Text;
 | |
|             var drGRP = PUB.DS.GRP.Where(t => t.TITLE.Equals(group_name)).FirstOrDefault();
 | |
|             if (drGRP == null) return;
 | |
| 
 | |
|             //그룹에 속한 채널 데이터
 | |
|             var chlist = PUB.DS.CHANNEL.Where(t => t.GIDX == drGRP.IDX).OrderBy(t => t.IDX);
 | |
|             var chlistdata = chlist.Where(t => t.ENABLE == 1).Select(t => t.IDX).ToList();
 | |
|             var chinfos = chlistdata.Select(t => new CChinfo { Show = false, TITLE = $"#{t:0000}", Idx = (ushort)t }).ToList();
 | |
| 
 | |
|             List<int> chnolist = new List<int>();
 | |
|             using (var f = new Frm_SelectCH(chinfos.ToArray()))
 | |
|                 if (f.ShowDialog() == DialogResult.OK)
 | |
|                 {
 | |
|                     foreach (ListViewItem item in f.CheckedListBox1.CheckedItems)
 | |
|                         chnolist.Add(int.Parse(item.Tag.ToString()));
 | |
|                 }
 | |
| 
 | |
|             //선택된 채널 갯수 확인
 | |
|             if (chnolist.Any() == false || chnolist.Count > PUB.CONFIG.MaxChCount)
 | |
|             {
 | |
|                 UTIL.MsgE("채널 선택은 (최소 1개 부터 {PUB.CONFIG.MaxChCount}개)까지 가능합니다");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             //최종저장 그룹명
 | |
|             var name = UTIL.InputBox($"그룹명을 입력하세요\n\n그룹생성({chnolist.Count}건)", $"GRP({chnolist.Min()}...{chnolist.Max()})");
 | |
|             if (name.Item1 == false || name.Item2.isEmpty()) return;
 | |
| 
 | |
|             group_name = name.Item2.Replace("'", "");
 | |
|             var value = string.Join(",", chnolist);
 | |
|             short rlt_maxid = PUBC.AddviewGroup(group_name, value, this.cmb_group.Text);
 | |
|             if (rlt_maxid != -1)
 | |
|             {
 | |
|                 AddGroupRow("[사용자] " + group_name, rlt_maxid, value, this.cmb_group.Text);
 | |
|                 SaveViewGroup();
 | |
|             }
 | |
|         }
 | |
|         public void LinkLabel4_LinkClicked(System.Object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
 | |
|         {
 | |
|             DelteGroup();
 | |
|         }
 | |
|         private void DelteGroup()
 | |
|         {
 | |
|             var drv = this.bs_grp.Current as DataRowView;
 | |
|             if (drv == null) return;
 | |
|             var dr = drv.Row as DS1.groupRow;
 | |
| 
 | |
|             if (dr.cname.IndexOf("사용자") == -1)
 | |
|             {
 | |
|                 UTIL.MsgE("사용자 그룹만 삭제가 가능합니다");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (UTIL.MsgQ($"선택된 사용자 그룹을 삭제하시겠습니까?\n\n{dr.cname}") != DialogResult.Yes) return;
 | |
| 
 | |
|             if (PUBC.DeleteViewGroup(dr.idx, this.cmb_group.Text))
 | |
|             {
 | |
|                 UTIL.MsgI("데이터가 삭제되었습니다");
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 UTIL.MsgI("삭제가 실패되었습니다");
 | |
|             }
 | |
|             drv.Delete();
 | |
|             dS1.group.AcceptChanges();
 | |
|             SaveViewGroup();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 우측 그리드뷰에 표시되는 커서 값을 표시한다.
 | |
|         /// </summary>
 | |
|         private void UpdateCursorValue()
 | |
|         {
 | |
|             //미사용채널데이터의 커서값 삭제
 | |
|             this.dS1.channel.Where(t => t.IsuseNull() == false && t.use == false).ToList().ForEach(t =>
 | |
|             {
 | |
|                 t.c1 = t.c2 = "";
 | |
|             });
 | |
| 
 | |
|             UpdateCursorValueData(0);
 | |
|             UpdateCursorValueData(1);
 | |
| 
 | |
|             dv_chlist.AutoResizeColumns();
 | |
|         }
 | |
| 
 | |
|         void UpdateCursorValueData(int idx)
 | |
|         {
 | |
|             var c1 = this.CursorLine[idx];
 | |
|             if (c1 != null)
 | |
|             {
 | |
|                 var time = DateTime.FromOADate(c1.X);
 | |
|                 foreach (DS1.channelRow dr in this.dS1.channel.Rows)
 | |
|                 {
 | |
|                     var chno = dr.idx;
 | |
| 
 | |
|                     //그래프 플롯이 준비되어있지 않는 경우
 | |
|                     if (chno > myPlotDataX.Length || this.myPlots[chno - 1] == null)
 | |
|                     {
 | |
|                         if (idx == 0) dr.c1 = "ERR";
 | |
|                         else dr.c2 = "ERR";
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     var plot = this.myPlots[chno - 1];
 | |
|                     var times = this.myPlotDataX[chno - 1];
 | |
| 
 | |
|                     //해당 데이터 포인트에 값이 있다.
 | |
|                     var samedate = times.Where(t => t == time).FirstOrDefault();
 | |
|                     if (samedate != default(DateTime))
 | |
|                     {
 | |
|                         var index = times.IndexOf(samedate);
 | |
|                         var volt1 = myPlotDataY[chno][index];
 | |
|                         if (idx == 0) dr.c1 = $"{volt1:#0.00}";
 | |
|                         else dr.c2 = $"{volt1:#0.00}"; ;
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     //가장자리 데이터 확인
 | |
|                     var leftdata = times.Where(t => t < time).LastOrDefault();
 | |
|                     var rightdata = times.Where(t => t > time).FirstOrDefault();
 | |
|                     if (leftdata == null || rightdata == null)
 | |
|                     {
 | |
|                         if (idx == 0) dr.c1 = "ERR";
 | |
|                         else dr.c2 = "ERR";
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     //시간내의 데이터를 찾는다
 | |
|                     var indexL = times.IndexOf(leftdata);
 | |
|                     var indexR = times.IndexOf(rightdata);
 | |
|                     if (indexL == -1 || indexR == -1)
 | |
|                     {
 | |
|                         if (idx == 0) dr.c1 = $"ERR";
 | |
|                         else dr.c2 = $"ERR";
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     var voltL = myPlotDataY[chno - 1][indexL];
 | |
|                     var voltR = myPlotDataY[chno - 1][indexR];
 | |
|                     /* 작성자: 이재웅, 작성일: 2024-09-26, 작성내용: volt 차이값 수식 변경 */
 | |
|                     // [이전내용] :  var diffvolt = Math.Abs(voltL - voltR);
 | |
|                     var diffvolt = (voltR - voltL);
 | |
|                     if (diffvolt == 0)  //Y축 변화가 없다면 그 중간의 데이터는 동일하다
 | |
|                     {
 | |
|                         if (idx == 0) dr.c1 = $"{voltL:#0.00}";
 | |
|                         else dr.c2 = $"{voltL:#0.00}";
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     //X축이 변화량의 어디쯤에 있는지 확인
 | |
|                     var XTotal = (rightdata - leftdata).TotalSeconds;
 | |
|                     var xPosition = (time - leftdata).TotalSeconds / XTotal;
 | |
|                     var volt = voltL + (diffvolt * xPosition);
 | |
|                     if (idx == 0) dr.c1 = $"{volt:#0.00}";
 | |
|                     else dr.c2 = $"{volt:#0.00}";
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void Ch_AllOrNothing(bool sel)
 | |
|         { /* 작성자: 이재웅, 작성일: 2024-09-26, 내용: 데이터그리드 데이터 All/Nothing 함수 */
 | |
| 
 | |
|             if (this.myPlots == null || this.myPlots.Any() == false) return;     //null check
 | |
|             PUB.smsg("채널정보를 변경하는중");
 | |
| 
 | |
|             this.myPlots.ToList().ForEach(t => t.IsVisible = sel);
 | |
|             this.dS1.channel.ToList().ForEach(t =>
 | |
|             {
 | |
|                 t.use = sel;
 | |
|                 if (sel == false) { t.c1 = t.c2 = ""; }
 | |
|             });
 | |
|             this.dS1.channel.AcceptChanges();
 | |
|             this.formsPlot1.Refresh();
 | |
| 
 | |
|             PUB.smsg("");
 | |
|         }
 | |
|         private void dv_chlist_CellContentClick(object sender, DataGridViewCellEventArgs e)
 | |
|         { /* 작성자: 이재웅, 작성일: 2024-09-26, 내용: 데이터그리드 데이터 행 관련 처리 */
 | |
| 
 | |
|             if (e.RowIndex < 0)
 | |
|             { // 데이터그리드 Title 행을 클릭
 | |
|                 if (e.ColumnIndex == 0)
 | |
|                 { // checkbox 컬럼을 클릭
 | |
|                     selALL = !selALL;
 | |
|                     Ch_AllOrNothing(selALL);
 | |
|                     if (selALL) UpdateCursorValue();    // 전체표시 조건일때 실행
 | |
|                     return;
 | |
|                 }
 | |
|                 else
 | |
|                     return;
 | |
|             }
 | |
|             else // 데이터그리드 Data 행의 checkbox 컬럼을 클릭
 | |
|                 if (e.ColumnIndex != 0) return;
 | |
| 
 | |
| 
 | |
|             this.dv_chlist.EndEdit();
 | |
|             this.dv_chlist.SuspendLayout();
 | |
| 
 | |
|             var Drv = this.bs_Channel.Current as DataRowView;
 | |
|             var dr = Drv.Row as DS1.channelRow;
 | |
|             if (Drv == null) return;
 | |
| 
 | |
|             //해당채널의 표시상태를 반전한다.
 | |
|             var ch = dr.idx;
 | |
| 
 | |
|             var plot = this.myPlots[ch - 1];
 | |
|             dr.use = plot.IsVisible = !plot.IsVisible;
 | |
| 
 | |
|             if (dr.use == false)
 | |
|             {
 | |
|                 dr.c1 = dr.c2 = string.Empty;
 | |
|             }
 | |
|             dr.EndEdit();
 | |
| 
 | |
|             this.formsPlot1.Refresh();
 | |
|             UpdateCursorValue();
 | |
| 
 | |
|             this.dv_chlist.ResumeLayout();
 | |
|         }
 | |
|         private void dv_chlist_MouseLeave(object sender, EventArgs e)
 | |
|         { /* 작성자: 이재웅, 작성일: 2024-09-26, 내용: 데이터그리드를 벗어나면 Cursors.Default 처리 */
 | |
|             this.Cursor = Cursors.Default;
 | |
|         }
 | |
|         private void dv_chlist_MouseMove(object sender, MouseEventArgs e)
 | |
|         { /* 작성자: 이재웅, 작성일: 2024-09-26, 내용: 첫번째 checkbox 컬럼일때 Cursors.Hand 처리 */
 | |
|             // 마우스 위치의 HitTest 호출
 | |
|             DataGridView.HitTestInfo hitTestInfo = dv_chlist.HitTest(e.X, e.Y);
 | |
| 
 | |
|             // 행과 열의 인덱스를 가져옴
 | |
|             //int rowIndex = hitTestInfo.RowIndex;
 | |
|             int columnIndex = hitTestInfo.ColumnIndex;
 | |
|             if (columnIndex == 0)
 | |
|                 this.Cursor = Cursors.Hand;
 | |
|             else
 | |
|                 this.Cursor = Cursors.Default;
 | |
|         }
 | |
| 
 | |
|         public void DataGridView1_CellFormatting(object sender, System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
 | |
|         {
 | |
|             var dr = this.dS1.channel.Rows[e.RowIndex] as DS1.channelRow;
 | |
|             if (dr == null) return;
 | |
|             this.dv_chlist.Rows[e.RowIndex].Cells[1].Style.BackColor = Color.FromArgb(dr.cc);
 | |
|             if (dr.use) this.dv_chlist.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;
 | |
|             else this.dv_chlist.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LightGray;
 | |
|         }
 | |
| 
 | |
|         public void ToolStripMenuItem1_Click(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             addnewGroup();
 | |
|         }
 | |
|         public void ToolStripMenuItem2_Click(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             DelteGroup();
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public void PrintDocument1_PrintPage(System.Object sender, System.Drawing.Printing.PrintPageEventArgs e)
 | |
|         {
 | |
|             Graphics G = e.Graphics;
 | |
| 
 | |
|             var pagesize = new SizeF(PrintDocument1.DefaultPageSettings.PaperSize.Height, PrintDocument1.DefaultPageSettings.PaperSize.Width);
 | |
| 
 | |
|             ////리포트제목표시
 | |
|             var title = "Historical Trend Display Report";
 | |
|             var titlefont = new Font("나눔고딕", 30, FontStyle.Bold);
 | |
|             var fontsize = G.MeasureString(title, titlefont);
 | |
|             var Y = 50f;
 | |
|             var X = (float)((pagesize.Width - fontsize.Width) / 2);
 | |
|             G.DrawString(title, titlefont, Brushes.Black, X, Y);
 | |
|             Y = Y + fontsize.Height + 70;
 | |
| 
 | |
|             int bottommargin = 50;
 | |
|             var WindowRect = new RectangleF(30, Y, (float)(pagesize.Width * 0.7), pagesize.Height - Y - bottommargin);
 | |
|             var ChartRect = new RectangleF(WindowRect.Left, WindowRect.Top, WindowRect.Width, WindowRect.Height);
 | |
| 
 | |
|             var 상호명 = PUB.CONFIG.sangho.Trim();
 | |
|             var 상호font = new Font("나눔고딕", 18, FontStyle.Bold);
 | |
|             var 상호size = G.MeasureString(상호명, 상호font);
 | |
|             G.DrawString(상호명, 상호font, Brushes.Black, WindowRect.Left, WindowRect.Top - 상호size.Height - 10);
 | |
| 
 | |
|             title = "C1";
 | |
|             fontsize = G.MeasureString(title, this.Font);
 | |
| 
 | |
|             var valuestr = "00.025";
 | |
|             var valuefontsizew = G.MeasureString(valuestr, this.Font).Width * 1.1F;
 | |
|             var valuefontsizeh = G.MeasureString(valuestr, this.Font).Height;
 | |
| 
 | |
|             var chtitle = new Rectangle(System.Convert.ToInt32(WindowRect.Left + WindowRect.Width + 20), System.Convert.ToInt32(WindowRect.Top), System.Convert.ToInt32(pagesize.Width - WindowRect.Width - 150), System.Convert.ToInt32(fontsize.Height * 2)); ////제목영역
 | |
|             var ChRect = new RectangleF(chtitle.Left, chtitle.Top + chtitle.Height, chtitle.Width, pagesize.Height - (chtitle.Top + chtitle.Height) - bottommargin); ////본문영역
 | |
|             var chinforect = new Rectangle(chtitle.Left, chtitle.Top, chtitle.Width, System.Convert.ToInt32(chtitle.Height + ChRect.Height)); ////총영역
 | |
| 
 | |
|             var chtitlewidth = ChRect.Width - (valuefontsizew * 2); ////채널정보를 표시하는 영역의 너비
 | |
|             var chc1valueleft = chinforect.Left + chtitlewidth;
 | |
|             var chc2valueleft = chc1valueleft + valuefontsizew;
 | |
| 
 | |
|             //차트영역에 이미지를 그린다.
 | |
|             G.DrawRectangle(Pens.Black, ChartRect.X, ChartRect.Y, ChartRect.Width, ChartRect.Height);
 | |
| 
 | |
|             using (var img = this.formsPlot1.Plot.GetImage((int)ChartRect.Width, (int)ChartRect.Height))
 | |
|                 G.DrawImage(img.GetBitmap(), ChartRect.X, ChartRect.Y, ChartRect.Width, ChartRect.Height);
 | |
| 
 | |
| 
 | |
|             var displayfont = new Font("나눔고딕", 10, FontStyle.Bold);
 | |
|             var displayfont2 = new Font("나눔고딕", 10);
 | |
|             ////채널정보칸 표시 (바로 이미지를 복제한다?) 제목표시
 | |
|             G.DrawRectangle(Pens.Gray, chtitle);
 | |
|             G.DrawString("Cell", displayfont, Brushes.Black, chtitle.Left + 5, (float)(chtitle.Top + (chtitle.Height - valuefontsizeh) / 2));
 | |
|             G.DrawString("C1", displayfont, Brushes.Black, (float)(chc1valueleft + (valuefontsizew - fontsize.Width) / 2), (float)(chtitle.Top + (chtitle.Height - valuefontsizeh) / 2));
 | |
|             G.DrawString("C2", displayfont, Brushes.Black, (float)(chc2valueleft + (valuefontsizew - fontsize.Width) / 2), (float)(chtitle.Top + (chtitle.Height - valuefontsizeh) / 2));
 | |
| 
 | |
|             ////세로줄그리기
 | |
|             G.DrawLine(Pens.Gray, chc1valueleft, chinforect.Top, chc1valueleft, chinforect.Top + chinforect.Height);
 | |
|             G.DrawLine(Pens.Gray, chc2valueleft, chinforect.Top, chc2valueleft, chinforect.Top + chinforect.Height);
 | |
|             //G.DrawRectangle(Pens.Red, chinforect)
 | |
| 
 | |
|             ////체크된 채널의 목록값을 보여준다. 그리고 c1,c2값을 보여준다.
 | |
|             var fsize = G.MeasureString("#11", this.Font);
 | |
|             var gridheight = ChRect.Height / 25;
 | |
|             var idx = (short)0;
 | |
|             Y = ChRect.Top + 10;
 | |
|             X = ChRect.Left + 10;
 | |
| 
 | |
|             var gridcnt = (int)(Math.Floor((decimal)(ChRect.Height / gridheight)));
 | |
|             for (int i = 0; i <= gridcnt + 1; i++)
 | |
|             {
 | |
|                 float newy = ChRect.Top + (i * gridheight);
 | |
|                 G.DrawLine(Pens.Gray, ChRect.Left, newy, ChRect.Left + ChRect.Width, newy);
 | |
|             }
 | |
| 
 | |
|             foreach (var ch in this.dS1.channel.Where(t => t.use))
 | |
|             {
 | |
|                 fsize = G.MeasureString(ch.cname, displayfont2);
 | |
|                 Y = (float)(ChRect.Top + (idx * gridheight) + ((gridheight - fsize.Height) / 2));
 | |
| 
 | |
|                 ////지정역역의 색상을 표시함
 | |
|                 RectangleF ColorRect = new RectangleF(X - 5, Y, chc1valueleft - X - 5, fsize.Height);
 | |
|                 G.FillRectangle(new SolidBrush(Color.FromArgb(ch.cc)), ColorRect);
 | |
|                 G.DrawString(ch.cname, displayfont2, Brushes.Black, X, Y);
 | |
|                 G.DrawString(ch.c1, displayfont2, Brushes.Black, chc1valueleft + 5, Y);
 | |
|                 G.DrawString(ch.c2, displayfont2, Brushes.Black, chc2valueleft + 5, Y);
 | |
|                 idx++;
 | |
|             }
 | |
|             ChRect.Height = gridheight * (gridcnt + 0);
 | |
|             G.DrawRectangle(Pens.Gray, chinforect.Left, chinforect.Top, chinforect.Width, chinforect.Height);
 | |
| 
 | |
|             displayfont2.Dispose();
 | |
|             displayfont.Dispose();
 | |
| 
 | |
|             G.Dispose();
 | |
|         }
 | |
|         public void Button1_Click(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             this.PrintDocument1.DefaultPageSettings.Landscape = true;
 | |
|             try
 | |
|             {
 | |
|                 this.PrintPreviewDialog1.ShowDialog();
 | |
|             }
 | |
|             catch (Exception ex) { UTIL.MsgE($"인쇄실패\n\n{ex.Message}"); }
 | |
|         }
 | |
| 
 | |
|         public void DataGridView2_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
 | |
|         { // 불러오기
 | |
|             if (this.bs_grp.Current == null)
 | |
|             {
 | |
|                 UTIL.MsgE("선택된 그룹이 없습니다");
 | |
|                 return;
 | |
|             }
 | |
|             bt_run.PerformClick();
 | |
|         }
 | |
|         public void ToolStripMenuItem3_Click(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             var drv = this.bs_grp.Current as DataRowView;
 | |
|             if (drv == null) return;
 | |
|             var dr = drv.Row as DS1.groupRow;
 | |
|             MessageBox.Show($"Channel List\n\n{dr.value}");
 | |
|         }
 | |
|         public void bt_run_Click(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             PUB.smsg("Loading");
 | |
|             var bt = sender as Button;
 | |
|             bt.Enabled = false;
 | |
| 
 | |
|             //GroupName = "";
 | |
|             foreach (var ch in this.ChartListData)
 | |
|                 ch.Clear();
 | |
| 
 | |
|             //그룹선택확인
 | |
|             var DRVGRP = this.bs_grp.Current as DataRowView;
 | |
|             if (DRVGRP == null) return;
 | |
|             var DRGRP = DRVGRP.Row as DS1.groupRow;
 | |
| 
 | |
|             /* 주석날짜: 2024-09-20 | 주석내용: VIEWGROUP.xml 파일내용 | 주석자: 이재웅
 | |
|              * 
 | |
|              * <VIEWGROUUP>
 | |
|              *   <IDX>9</IDX>
 | |
|              *   <GNAME>EL2500A</GNAME>
 | |
|              *   <TITLE>GRP(1...10)</TITLE>
 | |
|              *   <VAL>1,2,3,4,5,6,7,8,9,10</VAL>
 | |
|              * </VIEWGROUUP>
 | |
|              * 
 | |
|              **************************************
 | |
|              *
 | |
|              * DRGRP.idx = 9
 | |
|              * DRGRP.mame = "EL2500A"
 | |
|              * DRGRP.cname = "[사용자] GRP(1...10)"
 | |
|              * DRGRP.value = "1,2,3,4,5,6,7,8,9,10"
 | |
|              */
 | |
| 
 | |
|             var CHLIST = DRGRP.value.Trim();// ["value"].ToString().Trim(); ////표시채널목록
 | |
|             var CHArray = CHLIST.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
 | |
| 
 | |
|             //채널번호를 채널그룹에 맞게 분리작업을 합니다.
 | |
|             //채널데이터는 160개를 기준으로 1~10까지 분리되어 저장됩니다.
 | |
|             //채널번호에 맞는 기준의 번호를 찾아야 합니다.
 | |
|             foreach (var C in CHArray)
 | |
|             {
 | |
|                 if (C.isEmpty() || C.IsNumeric() == false) continue;
 | |
| 
 | |
|                 var ch = int.Parse(C);
 | |
|                 var ValueIdx = ch;// int.Parse(C);
 | |
|                 int quotient = ValueIdx / 160; // 몫
 | |
|                 int remainder = ValueIdx % 160; // 나머지
 | |
|                 if (remainder == 0) ValueIdx = quotient - 1;
 | |
|                 else ValueIdx = quotient;
 | |
| 
 | |
|                 if (this.ChartListData[ValueIdx].ChannelList.Contains(ch) == false)
 | |
|                     this.ChartListData[ValueIdx].ChannelList.Add(ch);
 | |
|             }
 | |
| 
 | |
|             //우측채널목록갱신(한번만 하면되므로 채널정보가 바뀌었을때만 처리한다.)
 | |
|             if (CHLIST != SelectedGRPChValue)
 | |
|             {
 | |
|                 bt_cursor1.BackColor = Color.Empty;
 | |
|                 bt_cursor2.BackColor = Color.Empty;
 | |
| 
 | |
|                 RefreshChannelList();
 | |
|                 SelectedGRPChValue = CHLIST;
 | |
|             }
 | |
| 
 | |
|             using (var fd = new Frm_GraphSetup())
 | |
|                 if (fd.ShowDialog() == DialogResult.OK) ShowData();
 | |
| 
 | |
|             ////UpdateChannelInfo()
 | |
|             bt.Enabled = true;
 | |
|             PUB.smsg("");
 | |
|         }
 | |
| 
 | |
|         public void Button2_Click_2(object sender, EventArgs e)
 | |
|         {
 | |
|             using (var f = new Frm_GraphSetup())
 | |
|             {
 | |
|                 if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
 | |
|                     ShowData(true);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void cmb_group_SelectedIndexChanged(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             if (cmb_group.SelectedIndex < 0) return;
 | |
| 
 | |
|             //기존에 선택된 채널의 활성화를 모두 해제 한다.
 | |
|             this.dS1.channel.ToList().ForEach(t => t.use = false);
 | |
|             this.ChartListData.ToList().ForEach(t => t.Clear());
 | |
| 
 | |
|             SelectedGRPChValue = "";
 | |
|             RefreshChannelList();
 | |
| 
 | |
|             string title = cmb_group.Text;
 | |
|             this.bs_grp.Filter = "rname='" + title + "'";
 | |
|             this.formsPlot1.Plot.Clear();
 | |
|             this.formsPlot1.Refresh();
 | |
|         }
 | |
|         public void Button1_Click_1(System.Object sender, System.EventArgs e)
 | |
|         {
 | |
|             using (var sd = new SaveFileDialog())
 | |
|             {
 | |
|                 sd.Filter = "png file|*.png";
 | |
|                 sd.FilterIndex = 0;
 | |
|                 sd.FileName = $"GraphCapture_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.png";
 | |
|                 sd.RestoreDirectory = true;
 | |
|                 if (sd.ShowDialog() == DialogResult.OK)
 | |
|                 {
 | |
|                     var fn = sd.FileName;
 | |
|                     this.formsPlot1.Plot.SavePng(fn, formsPlot1.Width, formsPlot1.Height);
 | |
|                     var dlg = UTIL.MsgQ("생성된 파일을 확인할까요?");
 | |
|                     if (dlg == DialogResult.Yes) UTIL.RunExplorer(fn);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         public void ToolStripButton1_Click_1(object sender, EventArgs e)
 | |
|         {
 | |
|             string dir = PUB.CONFIG.GetDatabasePath() + "\\DataBase\\volt";
 | |
|             UTIL.RunExplorer(dir);//.Shell("explorer " + dir, AppWinStyle.NormalFocus);
 | |
|         }
 | |
| 
 | |
|         public void bt_cursor_Click(object sender, EventArgs e)
 | |
|         {
 | |
|             var bt = sender as Button;
 | |
|             var idx = int.Parse(bt.Tag.ToString());
 | |
|             CreateCursor(idx);
 | |
|         }
 | |
|         void CreateCursor(int idx)
 | |
|         {
 | |
|             if (this.myPlots == null) return;   /* 작성자: 이재웅, 작성일: 2024-09-25, 내용: 'myPlots == null' 조건일때 오류발생 */
 | |
|             var plot = this.myPlots.Where(t => t != null).FirstOrDefault();
 | |
|             if (plot == null) return;
 | |
| 
 | |
|             //화면에 보이는 영역의 데이터를 확인
 | |
|             var viewx = plot.Axes.XAxis;
 | |
|             var viewy = plot.Axes.YAxis;
 | |
|             var xmin = viewx.Min;
 | |
|             var xmax = viewx.Max;
 | |
|             var datestep = (xmax - xmin) * 0.33f;
 | |
| 
 | |
|             //기존에 등록된 것이 있다면 그것을 제거하고 다시 추가한다.
 | |
|             if (CursorLine[idx] != null) formsPlot1.Plot.Remove(CursorLine[idx]);
 | |
| 
 | |
|             var timedata = xmin + datestep * (idx + 1);
 | |
|             var timeval = DateTime.FromOADate(timedata);
 | |
|             var axLine = formsPlot1.Plot.Add.VerticalLine(timedata);
 | |
|             axLine.Text = $"[C{idx + 1}] {timeval:yy-MM-dd\nHH:mm:ss}";
 | |
|             axLine.LabelAlignment = ScottPlot.Alignment.UpperRight;
 | |
|             axLine.IsDraggable = true;
 | |
|             this.CursorLine[idx] = axLine;
 | |
| 
 | |
|             this.formsPlot1.Refresh();
 | |
|             UpdateCursorValue();
 | |
|         }
 | |
| 
 | |
|         // DataGridView의 모든 행의 column 데이터 지우기
 | |
|         private void ClearColumnData(DataGridView dataGridView, int idx)
 | |
|         {
 | |
|             // DataGridView의 모든 행을 반복
 | |
|             foreach (DataGridViewRow row in dataGridView.Rows)
 | |
|             {
 | |
|                 // 해당 열의 데이터 지우기
 | |
|                 if (!row.IsNewRow) // 새 행이 아닌 경우에만
 | |
|                 {
 | |
|                     row.Cells[idx + 2].Value = null; // 또는 string.Empty로 설정 가능
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void bt_Hide_Click(object sender, EventArgs e)
 | |
|         {
 | |
|             //기존에 등록된 것이 있다면 그것을 제거한다.
 | |
|             if (CursorLine[0] != null)
 | |
|             {
 | |
|                 formsPlot1.Plot.Remove(CursorLine[0]);
 | |
|                 CursorLine[0] = null;
 | |
|                 ClearColumnData(dv_chlist, 0);
 | |
|             }
 | |
|             if (CursorLine[1] != null)
 | |
|             {
 | |
|                 formsPlot1.Plot.Remove(CursorLine[1]);
 | |
|                 CursorLine[1] = null;
 | |
|                 ClearColumnData(dv_chlist, 1);
 | |
|             }
 | |
|             this.formsPlot1.Refresh();
 | |
|         }
 | |
| 
 | |
|         private void btConfig_Click(object sender, EventArgs e)
 | |
|         {
 | |
|             if (UTIL.ShowPropertyDialog(PUB.TREND) == DialogResult.OK)
 | |
|             {
 | |
|                 PUB.TREND.Save();
 | |
| 
 | |
|                 formsPlot1.Plot.Axes.Bottom.MinimumSize = PUB.TREND.graph_bottom_minsize;
 | |
|                 if (PUB.TREND.y_scale_auto)
 | |
|                     formsPlot1.Plot.Axes.AutoScaleY();
 | |
|                 else
 | |
|                     formsPlot1.Plot.Axes.SetLimitsY(PUB.TREND.graph_y_start, PUB.TREND.graph_y_end);
 | |
| 
 | |
|                 formsPlot1.Refresh();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| }
 | 
