1807 lines
73 KiB
C#
1807 lines
73 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Data;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Linq;
|
|
using System.Security.Authentication.ExtendedProtection;
|
|
using System.Security.Policy;
|
|
|
|
namespace TrendCtrlII
|
|
{
|
|
public enum EDRAGTYPE
|
|
{
|
|
SCREEN,
|
|
ZOOM,
|
|
UC,
|
|
NONE
|
|
}
|
|
|
|
public enum ESCREENMODE
|
|
{
|
|
INIT,
|
|
TEMPDATA,
|
|
GRAPH
|
|
}
|
|
|
|
public enum EBUTTONTYPE
|
|
{
|
|
LEFTMON,
|
|
RIGHTMON
|
|
}
|
|
|
|
public enum EALIGN
|
|
{
|
|
LEFT,
|
|
CENTER,
|
|
RIGHT
|
|
}
|
|
|
|
public partial class TrendCtrlII : UserControl
|
|
{
|
|
private ChartStyle _Style = new ChartStyle();
|
|
public CMouseinfo Mouseinfo; //마우스위치정보
|
|
|
|
public Boolean Refresh_BackGround = true;
|
|
public Boolean Refresh_Grpah = true;
|
|
|
|
//화면이동모드
|
|
public Boolean ScreenMove = false;
|
|
|
|
//Boolean Make_BackT = false;
|
|
|
|
Bitmap layer_bakT; //전체영역의 배경
|
|
Bitmap layer_bak;
|
|
|
|
Bitmap layer_graph;
|
|
Bitmap layer_graphT; //전체영역의 그래프
|
|
|
|
public float MaxValueY { get; set; } = 15;
|
|
|
|
|
|
|
|
public Single LineWidth = 1;
|
|
private Rectangle UserZoom; //사용자줌영역
|
|
|
|
//실값
|
|
public Single[] values;
|
|
// public int[] times;
|
|
private CChinfo[] chinfo;
|
|
|
|
public Boolean Key_Control = false;
|
|
|
|
// private Rectangle Cursorrect;
|
|
|
|
//2015-02-17 : 시간정보를 chinfo 에서 분리
|
|
public Dictionary<UInt32, Int64> Time;
|
|
|
|
public void RemoveAt(int idx)
|
|
{
|
|
//배열갯수를 벗어나면 처리하지 않는다.
|
|
if (idx >= this.Time.Count) return;
|
|
|
|
//삭제대상의 키를 확인한다.
|
|
var timeKey = this.Time.Take(idx).First().Key;
|
|
|
|
//시간정보삭제
|
|
this.Time.Remove(timeKey);
|
|
|
|
//채널정보 중 타임키를 공유하는 자료를 삭제한다.
|
|
this.chinfo.ToList().ForEach(t => t.Value.Remove(timeKey));
|
|
|
|
}
|
|
|
|
public void AddData(long val_time, int ch, float val_volt, string ch_grp, string ch_title, Color ch_color)
|
|
{
|
|
//존재하지 않는 시간이라면 추가한다.
|
|
var ttime = Time.Where(t => t.Value == val_time).FirstOrDefault();
|
|
if (ttime.Key is default(UInt32) && ttime.Value is default(Int64)) // 기존에 값이 존재하지 않는경우
|
|
{
|
|
this.Time.Add((uint)this.Time.Count + 1, val_time);
|
|
ttime = Time.Where(t => t.Value == val_time).FirstOrDefault();
|
|
}
|
|
|
|
//해당 채널이 존재하는지 확인한다
|
|
var chdata = this.CHInfo.Where(t => t.CH == ch).FirstOrDefault();
|
|
if (chdata == null)
|
|
{
|
|
Array.Resize(ref chinfo, chinfo.Length + 1);
|
|
chdata = new CChinfo
|
|
{
|
|
CH = ch,
|
|
Idx = (ushort)ch,
|
|
GROUP = ch_grp,
|
|
TITLE = ch_title,
|
|
Color = ch_color,
|
|
Show = true,
|
|
};
|
|
chinfo[chinfo.Length - 1] = chdata;
|
|
}
|
|
|
|
//해당 시간대의 데이터가 없다면 추가한다.
|
|
if (chdata.Value.ContainsKey(ttime.Key) == false)
|
|
chdata.Value.Add(ttime.Key, val_volt);
|
|
}
|
|
|
|
public void AddData(long val_time, int ch, float val_volt)
|
|
{
|
|
//존재하지 않는 시간이라면 추가한다.
|
|
var ttime = Time.Where(t => t.Value == val_time).FirstOrDefault();
|
|
if (ttime.Key is default(UInt32))
|
|
{
|
|
this.Time.Add((uint)this.Time.Count + 1, val_time);
|
|
}
|
|
|
|
//해당 채널이 존재하는지 확인한다
|
|
var chdata = this.CHInfo.Where(t => t.CH == ch).FirstOrDefault();
|
|
if (chdata != null)
|
|
{
|
|
//해당 시간대의 데이터가 없다면 추가한다.
|
|
if (chdata.Value.ContainsKey(ttime.Key) == false)
|
|
chdata.Value.Add(ttime.Key, val_volt);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private Boolean init; //그리드초기화완료여부
|
|
public String initmsg = "initializing...";
|
|
public int initpercent = 0;
|
|
|
|
public List<CUserCursor> uc = new List<CUserCursor>(0); //사용자커서 최대2개까지한다.
|
|
|
|
//미정리
|
|
|
|
//MY EVENT
|
|
//public event OnClickProbeSensorHandlerL OnClickLEFT; //셀클릭
|
|
//public delegate void OnClickProbeSensorHandlerL();
|
|
//public event OnClickProbeSensorHandlerR OnClickRIGHT; //셀클릭
|
|
//public delegate void OnClickProbeSensorHandlerR();
|
|
public event OnUpdateUserControlHandler OnUpdateUserCursor; //UPDATE USER CURSOR
|
|
public delegate void OnUpdateUserControlHandler(int idx);
|
|
|
|
|
|
//화면디자인관련
|
|
private Cursor cursor = Cursors.Default; //현재커서의모양
|
|
|
|
private StringBuilder Warn_msg = new StringBuilder(""); //경고메세지(화면 최상단중앙에 표시됨)
|
|
private Font Warn_Font;
|
|
|
|
//기타설정'
|
|
public RectangleF WindowRect; //머릿부분
|
|
public RectangleF ChartRect;
|
|
|
|
/// <summary>
|
|
/// 현재데이터중 가장 마지막의 시간정보를 반환합니다. (없는경우 1900년도가 반화노딤)
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Int64 LastDate()
|
|
{
|
|
if (Time == null) return DateTime.Parse("1900-01-01").ToFileTime();
|
|
if (Time.Count < 1) return DateTime.Parse("1900-01-01").ToFileTime();
|
|
return Time.Last().Value;// [Time.Count - 1].Value;
|
|
}
|
|
|
|
public Int64 FirstDate()
|
|
{
|
|
if (Time == null) return DateTime.Parse("1900-01-01").ToFileTime();
|
|
if (Time.Count < 1) return DateTime.Parse("1900-01-01").ToFileTime();
|
|
return Time.First().Value;
|
|
}
|
|
|
|
public TrendCtrlII()
|
|
{
|
|
InitializeComponent();
|
|
|
|
// Initialize Variables
|
|
|
|
// Set Optimized Double Buffer to reduce flickering
|
|
this.SetStyle(ControlStyles.UserPaint, true);
|
|
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
|
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
|
|
|
// Redraw when resized
|
|
this.SetStyle(ControlStyles.ResizeRedraw, true);
|
|
|
|
this.Font = SystemInformation.MenuFont;
|
|
this.Warn_Font = new Font("나눔고딕", 20, FontStyle.Bold);
|
|
this.Warn_msg.Append("메세지가 없습니다");
|
|
this.Mouseinfo = new CMouseinfo(new PointF(0, 0));
|
|
Time = new Dictionary<uint, long>();
|
|
}
|
|
|
|
public ChartStyle Style
|
|
{
|
|
get { return this._Style; }
|
|
set { this._Style = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws the background gradient and the grid into Graphics <paramref name="g"/>
|
|
/// </summary>
|
|
/// <param name="g">Graphic</param>
|
|
public void DrawBackgroundWindow(Graphics g, RectangleF crect, RectangleF winrect)
|
|
{
|
|
//using (Brush gradientBrush = new LinearGradientBrush(this.WindowRect, Style.design_backcolor_start, Style.design_backcolor_bottom, LinearGradientMode.Vertical))
|
|
//{
|
|
// g.FillRectangle(gradientBrush, this.WindowRect);
|
|
//}
|
|
//g.FillRectangle(Brushes.Black, this.WindowRect);
|
|
|
|
//전체창에대한 보더
|
|
RectangleF borderrect = new RectangleF(winrect.Left, winrect.Top, winrect.Width - 1, winrect.Height - 1);
|
|
g.DrawRectangle(Pens.Gray, borderrect.Left, borderrect.Top, borderrect.Width, borderrect.Height);
|
|
|
|
|
|
//실제차트정보
|
|
//g.FillRectangle(Brushes.Gray, ChartRect.Left + 2, ChartRect.Top + 2, ChartRect.Width, ChartRect.Height);
|
|
//g.FillRectangle(Brushes.Black, ChartRect);
|
|
|
|
|
|
//Display Collection TIME
|
|
//String Str = "Collection Time : " + GetDateTimeStr(startview, false) + " - " + GetDateTimeStr(endview, false);
|
|
//SizeF fontszie = g.MeasureString(Str, this.Font);
|
|
//// Rectangle rect = new Rectangle((int)winrect.Left, (int)winrect.Top, (int)winrect.Width, (int)(fontszie.Height * 2));
|
|
// g.DrawString(Str, this.Font, Brushes.Black, rect.Left + 10, 3+rect.Top + (rect.Height - fontszie.Height) / 2);
|
|
// //g.DrawLine(Pens.Black, winrect.Left, fontszie.Height * 2, winrect.Left + winrect.Width, fontszie.Height * 2);
|
|
|
|
//CHART BORDER
|
|
g.DrawRectangle(new Pen(Color.Black, 2), crect.Left, crect.Top, crect.Width, crect.Height);
|
|
|
|
}
|
|
|
|
public void Set_Refresh()
|
|
{
|
|
Console.WriteLine("Graph : Set_Refresh");
|
|
Refresh_BackGround = true;
|
|
Refresh_Grpah = true;
|
|
}
|
|
|
|
/// Override OnPaint method
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
base.OnPaint(e);
|
|
// this.SuspendLayout();
|
|
|
|
// AntiAliasing
|
|
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
|
|
|
//표시아이템이없다면 오류를 낸다.
|
|
if (!init || chinfo == null)
|
|
{
|
|
//progress
|
|
int bw = (int)(this.Width * 0.8);
|
|
int bh = (int)(this.Height * 0.05);
|
|
Rectangle rr = new Rectangle((this.Width - bw) / 2, (this.Height - bh) / 2 + 10, bw, bh);
|
|
|
|
//Display Initial Message
|
|
Font nf = new Font("나눔고딕", 20, FontStyle.Bold);
|
|
Rectangle FullRect = new Rectangle(0, 0, this.Width, this.Height);
|
|
SizeF initsize = e.Graphics.MeasureString(initmsg, nf);
|
|
e.Graphics.DrawString(initmsg, nf, Brushes.Black, this.Width / 2 - initsize.Width / 2, this.Height / 2 - initsize.Height / 2 - bh);
|
|
|
|
//Display progress Bar
|
|
if (initpercent > 100) initpercent = 100;
|
|
int perc = (int)(rr.Width * initpercent / 100);
|
|
e.Graphics.FillRectangle(Brushes.Green, new Rectangle(rr.Left, rr.Top, perc, rr.Height));
|
|
|
|
//Display Control Border
|
|
e.Graphics.DrawRectangle(Pens.DarkGray, rr);
|
|
|
|
//using (Brush gradientBrush = new LinearGradientBrush(FullRect, Color.Gray, Color.Gray, LinearGradientMode.Vertical))
|
|
//{
|
|
//
|
|
// e.Graphics.FillRectangle(gradientBrush, FullRect);
|
|
// // String initstr = "initializing...";
|
|
// //if (initmsg != "") initstr += "\n\n" + initmsg;
|
|
//}
|
|
|
|
//LinearGradientBrush lb = new LinearGradientBrush(rr, Color.Gray, Color.WhiteSmoke,LinearGradientMode.Vertical);
|
|
//lb.Dispose();
|
|
//e.Graphics.DrawRectangle(Pens.DarkGoldenrod, FullRect.Left, FullRect.Top, FullRect.Width - 1, FullRect.Height - 1);
|
|
|
|
//this.ResumeLayout();
|
|
return;
|
|
}
|
|
|
|
Graphics g_bak;
|
|
Graphics g_graph;
|
|
|
|
if (Style.XV1 == Style.X1 && Style.XV2 == Style.X2)
|
|
{
|
|
//전체영역이면(전체용 비트맵을 사용함)
|
|
g_bak = Graphics.FromImage(this.layer_bakT);
|
|
g_graph = Graphics.FromImage(this.layer_graphT);
|
|
}
|
|
else
|
|
{
|
|
g_bak = Graphics.FromImage(this.layer_bak);
|
|
g_graph = Graphics.FromImage(this.layer_graph);
|
|
}
|
|
|
|
// e.Graphics.CompositingMode = CompositingMode.SourceOver;
|
|
|
|
if (Refresh_BackGround)
|
|
{
|
|
// g_bak.CompositingMode = CompositingMode.SourceOver;
|
|
g_bak.Clear(Color.White);
|
|
DrawBackgroundWindow(g_bak, ChartRect, WindowRect);
|
|
Draw_Grid(g_bak, ChartRect); //x축,y축의 눈금과 그리드표시
|
|
Refresh_BackGround = false;
|
|
}
|
|
|
|
if (Refresh_Grpah)
|
|
{
|
|
// g_graph.CompositingMode = CompositingMode.SourceOver;
|
|
g_graph.Clear(Color.Transparent);
|
|
Draw_channel(g_graph, ChartRect, WindowRect);
|
|
Refresh_Grpah = false;
|
|
}
|
|
|
|
g_bak.Dispose();
|
|
g_graph.Dispose();
|
|
|
|
//전체영역의경우 별도 할당된 이미지를 사용한ㄷ(최초 1번만 그리게된다)
|
|
if (Style.XV1 == Style.X1 && Style.XV2 == Style.X2)
|
|
{
|
|
e.Graphics.DrawImage(layer_bakT, 0, 0);
|
|
e.Graphics.DrawImage(layer_graphT, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.DrawImage(layer_bak, 0, 0);
|
|
e.Graphics.DrawImage(layer_graph, 0, 0);
|
|
}
|
|
|
|
|
|
|
|
//기타정보그림
|
|
Draw_ZoomSelect(e.Graphics);
|
|
Draw_Cursor(e.Graphics, ChartRect);
|
|
Draw_MouseInfo(e.Graphics);
|
|
Draw_Debug(e.Graphics);
|
|
if (ShowLegend) Draw_legend(e.Graphics);
|
|
g_bak.Dispose();
|
|
g_graph.Dispose();
|
|
|
|
|
|
//StringBuilder sb = new StringBuilder();
|
|
//sb.AppendLine("Startv View : " + startview.ToString() + "/" + endview.ToString());
|
|
//sb.AppendLine("Start Time : " + starttime.ToString() + "/" + endtime.ToString());
|
|
//sb.AppendLine("Start View O : " + Style.XV1.ToString() + "/" + endviewo.ToString());
|
|
//sb.AppendLine("Start Volt : " + Style.Y1.ToString() + "/" + Style.Y2.ToString());
|
|
//sb.AppendLine("Start Volt O : " + Style.Y1o.ToString() + "/" + Style.Y2o.ToString());
|
|
//e.Graphics.DrawString(sb.ToString(), this.Font, Brushes.Black, 100, 100);
|
|
|
|
//e.Graphics.DrawRectangle(Pens.Red, ChartRect.Left, ChartRect.Top, ChartRect.Width, ChartRect.Height);
|
|
//e.Graphics.DrawRectangle(Pens.Blue, LegendRect.Left, LegendRect.Top, LegendRect.Width, LegendRect.Height);
|
|
//this.Update();
|
|
//this.ResumeLayout();
|
|
}
|
|
|
|
public bool ShowLegend { get; set; } = false;
|
|
void Draw_legend(Graphics g)
|
|
{
|
|
if (chinfo == null || chinfo.Any() == false) return;
|
|
var maxcnt = 10;
|
|
var h = LegendRect.Height / maxcnt;
|
|
var w = LegendRect.Width;
|
|
var showitem = this.chinfo.Where(t => t.Show).ToList();
|
|
var itemcnt = Math.Min(10, showitem.Count());
|
|
for (int i = 0; i < itemcnt; i++)
|
|
{
|
|
var y = LegendRect.Y + i * h;
|
|
var item = showitem[i];
|
|
var rect = new RectangleF(LegendRect.X, y, w, h);
|
|
var rectflag = new RectangleF(rect.X, rect.Y, rect.Width * 0.15f, rect.Height);
|
|
var rectttitle = new RectangleF(rectflag.Right + 3, rect.Y, rect.Width - rectflag.Width - 3, rect.Height);
|
|
using (var bgcolor = new SolidBrush(item.Color))
|
|
g.FillRectangle(bgcolor, rectflag);
|
|
var title = $"{item.TITLE}";
|
|
if (item.Value.Any())
|
|
title = $"{item.TITLE} ({item.Value.Last().Value}v)";
|
|
|
|
g.DrawString(title, this.Font, Brushes.Black, rectttitle, new StringFormat
|
|
{
|
|
Alignment = StringAlignment.Near,
|
|
LineAlignment = StringAlignment.Center
|
|
}); ;
|
|
g.DrawRectangle(Pens.Black, rect.X, rect.Y, rect.Width, rect.Height);
|
|
}
|
|
}
|
|
public void Draw_Cursor(Graphics g, RectangleF Crect)
|
|
{
|
|
|
|
|
|
if (this.uc.Count == 0) return;
|
|
Font cfont = new Font("나눔고딕", 10, FontStyle.Bold);
|
|
|
|
//커서는 기본 2개를 둔다(전체사이즈를 측정하기위해서 임시로 크기를 테스트한다.)
|
|
String cursorstr = "▦ C1 2012-00-00- 00:00:00 ▦ C1 2012-00-00- 00:00:00 ▦ C1 2012-00-00- 00:00:00";
|
|
SizeF FontSize = g.MeasureString(cursorstr.ToString(), cfont);
|
|
|
|
//커서가표시될영역
|
|
|
|
//Cursorrect = new Rectangle(0, 0, 50,50);
|
|
//Cursorrect.X = (int)(Crect.Left + Crect.Width - FontSize.Width * 1.1) - 1;
|
|
//Cursorrect.Y = (int)(Crect.Top - 2 - FontSize.Height);
|
|
//Cursorrect.Width = (int)(FontSize.Width * 1.1);
|
|
//Cursorrect.Height = (int)(FontSize.Height * 1.3);
|
|
|
|
//g.FillRectangle(Brushes.DimGray, Cursorrect);
|
|
//g.DrawRectangle(Pens.Gray, Cursorrect);
|
|
|
|
//Single newy = Cursorrect.Top + ((Cursorrect.Height - FontSize.Height)/2) ;
|
|
//Single Maxwidth = 0;
|
|
|
|
//String fulltext = "";
|
|
|
|
var qry = from CUserCursor cs in uc
|
|
orderby cs.Idx
|
|
select cs;
|
|
|
|
|
|
cursorstr = "";
|
|
foreach (CUserCursor uctl in qry)
|
|
{
|
|
Single newx = GetXfromTime(uctl.Time, Crect);
|
|
uctl.Newx = newx;
|
|
|
|
Single imgsizew = Properties.Resources.down_16.Width;
|
|
Single imgsizeh = Properties.Resources.down_16.Height;
|
|
|
|
cursorstr += " ▦ C" + (uctl.Idx + 1).ToString() + " " + GetTimeStr(uctl.Time, true, true, true, true);
|
|
|
|
FontSize = g.MeasureString(cursorstr.ToString(), cfont);
|
|
// if (FontSize.Width > Maxwidth) Maxwidth = FontSize.Width;
|
|
|
|
if (uctl.Idx < 1)
|
|
{
|
|
g.DrawImage(Properties.Resources.down_16, (newx - imgsizew / 2) - 1, Crect.Top - imgsizeh - 5);
|
|
g.DrawLine(new Pen(Color.Green, 1), newx, Crect.Top, newx, Crect.Top + Crect.Height);
|
|
|
|
// fulltext = cursorstr;
|
|
|
|
}
|
|
else
|
|
{
|
|
TimeSpan ts = DateTime.FromFileTime(uctl.Time) - DateTime.FromFileTime(uc[0].Time);
|
|
cursorstr += " △t " + ts.Days.ToString() + "d " + ts.Hours.ToString() + ":" + ts.Minutes.ToString() + ":" + ts.Seconds.ToString();
|
|
|
|
g.DrawImage(Properties.Resources.down_orange, (newx - imgsizew / 2) - 1, Crect.Top - imgsizeh - 5);
|
|
g.DrawLine(new Pen(Color.Orange, 1), newx, Crect.Top, newx, Crect.Top + Crect.Height);
|
|
// if (fulltext == "") fulltext = cursorstr;
|
|
// else fulltext += "\n" + cursorstr;
|
|
|
|
}
|
|
// newy += FontSize.Height + 1;
|
|
}
|
|
|
|
if (cursorstr != "")
|
|
{
|
|
FontSize = g.MeasureString(cursorstr, cfont);
|
|
g.DrawString(cursorstr, cfont, Brushes.Black, Crect.Right - FontSize.Width - 2, Crect.Top - FontSize.Height - 2);
|
|
}
|
|
|
|
//
|
|
// Cursorrect = new Rectangle((int)(ChartRect.Left + ChartRect.Width - Maxwidth), (int)ChartRect.Top, (int)Maxwidth, (int)(newy - FontSize.Height));
|
|
}
|
|
|
|
public void Draw_MouseInfo(Graphics g)
|
|
{
|
|
if (this.Mouseinfo.Showinfo) //마웃위치정보를 화면에 표시를 한다.
|
|
{
|
|
String tm = GetTimeStr(Mouseinfo.Time, true, true, true, true) + "\n" + Mouseinfo.Volt.ToString("#0.00") + "v";
|
|
if (Style.Show_DebugMsg) tm += "\n" + Mouseinfo.Time.ToString();
|
|
|
|
SizeF tmsize = g.MeasureString(tm, Style._mouseinfofont);
|
|
|
|
RectangleF rect = new RectangleF(Mouseinfo.Position.X + 5, Mouseinfo.Position.Y + 5, tmsize.Width + 10, tmsize.Height + 10);
|
|
if (Mouseinfo.Position.X >= (this.ChartRect.Left + ChartRect.Width / 2))
|
|
{
|
|
//마우스위치에따라서 표시정보 위치를 좌/우 교환한다 150223
|
|
rect = new RectangleF(Mouseinfo.Position.X - (tmsize.Width + 10) - 5, Mouseinfo.Position.Y + 5, tmsize.Width + 10, tmsize.Height + 10);
|
|
}
|
|
//g.FillRectangle(new SolidBrush(Color.FromArgb(140,Color.Green)), rect);
|
|
g.DrawRectangle(Pens.Black, rect.Left, rect.Top, rect.Width, rect.Height);
|
|
|
|
g.DrawString(tm, Style._mouseinfofont, new SolidBrush(Style.design_mouseinfocolor), rect.Left + (rect.Width - tmsize.Width) / 2, rect.Top + (rect.Height - tmsize.Height) / 2);
|
|
}
|
|
}
|
|
|
|
public void Draw_Grid(Graphics g, RectangleF crect)
|
|
{
|
|
|
|
DateTime SDVDate = DateTime.FromFileTime(Style.XV1);
|
|
DateTime SDate = DateTime.FromFileTime(Style.XV1);
|
|
DateTime EDate = DateTime.FromFileTime(Style.XV2);
|
|
|
|
var (normalizedStart, normalizedEnd) = NormalizeTimeRangeHalfHourIntervals(SDate, EDate);
|
|
SDVDate = normalizedStart;
|
|
SDate = normalizedStart;
|
|
EDate = normalizedEnd;
|
|
|
|
TimeSpan TS = EDate - SDate; //timespan
|
|
|
|
if (TS.TotalSeconds > Style.MaxZoomX)
|
|
{
|
|
//표시간격 최소 10초
|
|
int tm = 10;
|
|
|
|
if (Style.XGap == 0)
|
|
{
|
|
tm = (int)(TS.TotalSeconds / 5);
|
|
}
|
|
else
|
|
{
|
|
tm = Style.XGap;
|
|
}
|
|
|
|
var termcnt = (int)(TS.TotalSeconds / tm);
|
|
if (termcnt < 10)
|
|
{
|
|
tm = (int)(TS.TotalSeconds / 10f);
|
|
}
|
|
else if (termcnt > 10) //간격이 너무 크다
|
|
{
|
|
tm = (int)(TS.TotalSeconds / 10f);
|
|
}
|
|
tm = GetClosestInterval(tm);
|
|
|
|
for (Int64 i = 0; i <= TS.TotalSeconds; i += tm)
|
|
{
|
|
DateTime NewDate = SDVDate.AddSeconds(i); //시작시간에서
|
|
if (SDate.Day != NewDate.Day)
|
|
{
|
|
//일자가 바귀엇으므로 해당 일즤 세로축을 표시
|
|
DateTime LineDay = DateTime.Parse(NewDate.ToString("yyyy-MM-dd 00:00:00"));
|
|
Single newx2 = GetXfromTime(LineDay.ToFileTime(), crect);
|
|
g.DrawLine(new Pen(Color.FromArgb(50, Color.Black)), newx2, crect.Top, newx2, crect.Top + crect.Height);
|
|
SDate = NewDate;
|
|
}
|
|
|
|
Single newx = GetXfromTime(NewDate.ToFileTime(), crect);
|
|
String timestr = "";
|
|
|
|
if (i == 0) timestr = GetDateTimeStr(NewDate.ToFileTime(), true);
|
|
else timestr = GetTimeStr(NewDate.ToFileTime(), i == 0 ? true : false, false);
|
|
|
|
timestr = NewDate.ToString("yy-MM-dd") + "\n" + NewDate.ToString("HH:mm:ss");
|
|
|
|
DrawString(g, timestr, Style.FontX, Brushes.Black, new PointF(newx, crect.Top + crect.Height + 5), EALIGN.CENTER);
|
|
if (i > 0) g.DrawLine(new Pen(Color.Gray), newx, crect.Top, newx, crect.Top + crect.Height);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//Y축 값을 표시할 값이 없으면 오류를 표시한다.
|
|
DrawString(g, "ERRX", Style.FontX, Brushes.Black, new PointF(crect.Left - 2, crect.Bottom), EALIGN.RIGHT, EALIGN.CENTER);
|
|
}
|
|
|
|
|
|
|
|
//세로(VOLT)표시
|
|
//g.DrawString("start="+Style._startvolt.ToString(), this.Font, Brushes.Red, 100, 100);
|
|
//g.DrawString("end="+Style._endvolt.ToString(), this.Font, Brushes.Red, 100, 120);
|
|
|
|
//g.DrawString("최소="+Style.최소값.ToString(), this.Font, Brushes.Red, 100, 140);
|
|
//g.DrawString("최대="+Style.최대값.ToString(), this.Font, Brushes.Red, 100, 160);
|
|
|
|
if (Math.Abs(Style.YV2 - Style.YV1) >= Style.MaxZoomY)
|
|
{
|
|
Single term;
|
|
if (Style.YGap == 0)
|
|
{
|
|
term = (Style.YV2 - Style.YV1) / 10;
|
|
}
|
|
else
|
|
{
|
|
term = Style.YGap;
|
|
}
|
|
|
|
for (Single i = Style.YV1; i <= Style.YV2; i += term)
|
|
{
|
|
// 세로길이 = 10v :
|
|
Single newy = GetYfromVolt(i, crect);
|
|
if (Style.YV1 == 0 && i == 0)
|
|
{
|
|
|
|
}
|
|
else g.DrawLine(new Pen(Color.Gray), crect.Left, newy, crect.Left + crect.Width, newy);
|
|
|
|
//소수점없는경우에눈금표시한다.
|
|
DrawString(g, i.ToString("#0.00"), Style.FontY, Brushes.Black, new PointF(crect.Left - 2, newy), EALIGN.RIGHT, EALIGN.CENTER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Y축 값을 표시할 값이 없으면 오류를 표시한다.
|
|
DrawString(g, "ERRY", Style.FontY, Brushes.Black, new PointF(crect.Left - 2, crect.Top + 2), EALIGN.RIGHT, EALIGN.CENTER);
|
|
}
|
|
}
|
|
|
|
public (DateTime normalizedStart, DateTime normalizedEnd) NormalizeTimeRangeHalfHourIntervals(DateTime start, DateTime end)
|
|
{
|
|
const int intervalInSeconds = 1800; // 30 minutes
|
|
|
|
DateTime normalizedStart = NormalizeTimeToInterval(start, intervalInSeconds, roundDown: true);
|
|
DateTime normalizedEnd = NormalizeTimeToInterval(end, intervalInSeconds, roundDown: false);
|
|
|
|
return (normalizedStart, normalizedEnd);
|
|
}
|
|
|
|
private DateTime NormalizeTimeToInterval(DateTime time, int intervalInSeconds, bool roundDown)
|
|
{
|
|
long ticks = time.Ticks / TimeSpan.TicksPerSecond;
|
|
if (roundDown)
|
|
{
|
|
ticks = (ticks / intervalInSeconds) * intervalInSeconds; // Round down
|
|
}
|
|
else
|
|
{
|
|
ticks = ((ticks + intervalInSeconds - 1) / intervalInSeconds) * intervalInSeconds; // Round up
|
|
}
|
|
return new DateTime(ticks * TimeSpan.TicksPerSecond);
|
|
}
|
|
|
|
|
|
private readonly int[] TimeIntervals = new int[]
|
|
{
|
|
1, 10, 30, 60, 300, 600, 1800, 3600, 21600, 43200, 86400, 432000, 864000, 2592000
|
|
};
|
|
public int GetClosestInterval(int seconds)
|
|
{
|
|
// Handle cases where seconds is less than the smallest interval or more than the largest interval
|
|
if (seconds <= TimeIntervals[0])
|
|
return TimeIntervals[0];
|
|
if (seconds >= TimeIntervals[TimeIntervals.Length - 1])
|
|
return TimeIntervals[TimeIntervals.Length - 1];
|
|
|
|
// Find the closest interval
|
|
int closestInterval = TimeIntervals[0];
|
|
int minDifference = Math.Abs(seconds - closestInterval);
|
|
|
|
foreach (int interval in TimeIntervals)
|
|
{
|
|
int difference = Math.Abs(seconds - interval);
|
|
if (difference < minDifference)
|
|
{
|
|
minDifference = difference;
|
|
closestInterval = interval;
|
|
}
|
|
}
|
|
|
|
return closestInterval;
|
|
}
|
|
|
|
public void Draw_Debug(Graphics g)
|
|
{
|
|
if (!Style.Show_DebugMsg) return;
|
|
|
|
//Single newy = 50;
|
|
//String newstr = "";
|
|
SizeF fontsize;
|
|
|
|
StringBuilder DebugMsg = new StringBuilder();
|
|
|
|
DebugMsg.AppendLine("Mouseinfo=" + this.Mouseinfo.Position.ToString() + " " + this.Mouseinfo.Showinfo.ToString());
|
|
DebugMsg.AppendLine("Mouseinfo0=" + this.Mouseinfo.Position0.ToString() + " idx=" + this.Mouseinfo.DragIndex.ToString());
|
|
DebugMsg.AppendLine("Mouse Volt =" + this.Mouseinfo.Volt.ToString() + " ,Time=" + DateTime.FromFileTime(Mouseinfo.Time).ToString());
|
|
DebugMsg.AppendLine("Mouse Drag=" + Mouseinfo.Drag.ToString() + " " + Mouseinfo.DragType.ToString());
|
|
DebugMsg.AppendLine("Mouse DragStart=" + Mouseinfo.DragStart.ToString());
|
|
DebugMsg.AppendLine("TimeCount =" + Time.Count.ToString());
|
|
|
|
TimeSpan NowTerm = DateTime.FromFileTime(Style.X2) - DateTime.FromFileTime(Style.X1);
|
|
DebugMsg.AppendLine("XGap =" + Style.XGap.ToString() + ",YGap=" + Style.YGap.ToString() + ",Xterm=" + Style.X표시범위.ToString() + ",NowTerm=" + NowTerm.ToString());
|
|
|
|
foreach (String file in Files)
|
|
{
|
|
DebugMsg.AppendLine("File = " + file);
|
|
}
|
|
foreach (CUserCursor ucitem in uc)
|
|
{
|
|
DebugMsg.AppendLine("uc" + ucitem.Idx.ToString() + ",x=" + ucitem.Newx.ToString() + ",time=" + ucitem.Time.ToString());
|
|
}
|
|
|
|
DebugMsg.AppendLine("======================");
|
|
DebugMsg.AppendLine("시간축=" + Style.X1.ToString() + "~" + Style.X2.ToString() + " : " + DateTime.FromFileTime(Style.X1).ToString("yy-MM-dd HH:mm:ss") + "~" + DateTime.FromFileTime(Style.X2).ToString("yy-MM-dd HH:mm:ss"));
|
|
DebugMsg.AppendLine("시간축V=" + Style.XV1.ToString() + "/" + Style.XV2.ToString() + " : " + DateTime.FromFileTime(Style.XV1).ToString("yy-MM-dd HH:mm:ss") + "~" + DateTime.FromFileTime(Style.XV2).ToString("yy-MM-dd HH:mm:ss"));
|
|
DebugMsg.AppendLine("시간축VO=" + Style.XV1o.ToString() + "/" + Style.XV2o.ToString() + " : " + DateTime.FromFileTime(Style.XV1o).ToString("yy-MM-dd HH:mm:ss") + "~" + DateTime.FromFileTime(Style.XV2o).ToString("yy-MM-dd HH:mm:ss"));
|
|
DebugMsg.AppendLine("======================");
|
|
DebugMsg.AppendLine("전압축=" + Style.Y1.ToString() + "~" + Style.Y2.ToString());
|
|
DebugMsg.AppendLine("전압축V=" + Style.YV1.ToString() + "~" + Style.YV2.ToString());
|
|
DebugMsg.AppendLine("전압축VO=" + Style.YV1o.ToString() + "~" + Style.YV2o.ToString());
|
|
DebugMsg.AppendLine("======================");
|
|
|
|
DebugMsg.AppendLine("UserZoom=" + UserZoom.ToString());
|
|
|
|
// newstr = "CHinfo=" + chinfo.GetUpperBound(0);
|
|
|
|
foreach (CChinfo ch in chinfo)
|
|
{
|
|
DebugMsg.AppendLine("idx=" + ch.Idx.ToString() + ",visible:" + ch.Show.ToString() + ",cnt=" + ch.Value.Count.ToString() + ",Color=" + ch.Color.ToString());
|
|
}
|
|
|
|
fontsize = g.MeasureString(DebugMsg.ToString(), this.Font);
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(180, Color.Black)), new Rectangle(100, 100, (int)(fontsize.Width * 1.3), (int)(fontsize.Height * 1.3)));
|
|
g.DrawString(DebugMsg.ToString(), this.Font, Brushes.Tomato, 110, 110);
|
|
}
|
|
|
|
public List<String> Files = new List<string>();
|
|
|
|
public void DataClear()
|
|
{
|
|
if (uc != null) uc.Clear();
|
|
if (chinfo != null) Array.Clear(chinfo, 0, chinfo.Length);
|
|
if (Time != null) this.Time.Clear();
|
|
if (Files != null) Files.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 지정된 시간값이 현재 존재하는가?
|
|
/// </summary>
|
|
/// <param name="value">int64 : time value</param>
|
|
/// <returns></returns>
|
|
public Boolean ExistTime(Int64 _value)
|
|
{
|
|
// if (Time.Count < 1) return false;
|
|
|
|
return Time.Select(t => t.Value).ToList().Contains(_value);
|
|
//for (int i = 1; i <= Time.Count; i++)
|
|
//{
|
|
// if (_value == Time[i - 1].Value) return true;
|
|
//}
|
|
//return false;
|
|
}
|
|
|
|
public void ScaleFitX()
|
|
{
|
|
var xrange = this.RangeX;
|
|
this.Style.XV1 = xrange.min;
|
|
this.Style.XV2 = xrange.max;
|
|
this.Invalidate();
|
|
}
|
|
public void ScaleFitY()
|
|
{
|
|
var xrange = this.RangeY;
|
|
this.Style.YV1 = xrange.min;
|
|
this.Style.YV2 = xrange.max;
|
|
this.Invalidate();
|
|
}
|
|
public void ScaleFitXY()
|
|
{
|
|
ScaleFitX();
|
|
ScaleFitY();
|
|
}
|
|
|
|
|
|
public void Draw_channel(Graphics g, RectangleF crect, RectangleF wrect)
|
|
{
|
|
//지정된 시간에 속한 타임만 취듯한다.
|
|
var rangeX = this.RangeX;
|
|
var minTime = this.Time[rangeX.min];
|
|
var maxTime = this.Time[rangeX.max];
|
|
|
|
var qry = Time
|
|
.Where(t => t.Value >= Style.XV1 && t.Value <= Style.XV2)
|
|
.OrderBy(t => t.Value)
|
|
.ToDictionary(t => t.Key, t => t.Value);
|
|
|
|
|
|
|
|
if (qry.Any() == false) return;
|
|
|
|
//지정된 시간영역의 자료의 범위를 측정
|
|
var time_min = qry.Min(t => t.Key); //최소시간정보
|
|
var time_max = qry.Max(t => t.Key); //최대시간정보
|
|
|
|
//각채널의 데이터를 확인한다(시간정보[최소~최대]에 포함된것만 표시한다)
|
|
var chlist = chinfo.Where(t => t != null && t.Show
|
|
&& (t.Value.Max(s => s.Key) >= time_min && t.Value.Min(s => s.Key) <= time_max)).ToList();
|
|
|
|
foreach (var ch in chinfo)
|
|
{
|
|
if (ch == null || ch.Show == false) continue;
|
|
//var minX = ch.Value.Min(s => s.Key);
|
|
//var maxX = ch.Value.Max(s => s.Key);
|
|
|
|
//해당채널내에서 지정된 영역의 자료만 가져온다.
|
|
var valueList = ch.Value.Where(t => t.Key >= time_min && t.Key <= time_max).ToDictionary(t => t.Key, t => t.Value);
|
|
if (valueList.Any() == false) continue;
|
|
|
|
List<PointF> linearrya = new List<PointF>(0);
|
|
|
|
Single PreX = 0;
|
|
Single PreY = 0;
|
|
Boolean fc1 = false, fc2 = false;
|
|
int idx = 0;
|
|
|
|
//저장된 모든 값을 출력한다.
|
|
foreach (var cdata in valueList)
|
|
{
|
|
//시간정보는 동일하다면 조회하지 않게한다.
|
|
var time = qry[cdata.Key];
|
|
var volt = cdata.Value;
|
|
|
|
//좌표계산
|
|
Single newx = GetXfromTime(time, crect) - 1;
|
|
Single newy = GetYfromVolt(volt, crect) - 1;
|
|
|
|
//커서값확인
|
|
foreach (CUserCursor cs in uc)
|
|
{
|
|
if (cs.Idx == 0 && time >= cs.Time && fc1 == false)
|
|
{
|
|
if (volt > 60) ch.C1value = "OVER";
|
|
else ch.C1value = volt.ToString();
|
|
fc1 = true;
|
|
}
|
|
else if (cs.Idx == 1 && time >= cs.Time && fc2 == false)
|
|
{
|
|
if (volt > 60) ch.C2value = "OVER";
|
|
else ch.C2value = volt.ToString();
|
|
fc2 = true;
|
|
}
|
|
}
|
|
|
|
//너무가까운데이터는 그리지 않는다.
|
|
//if (Math.Abs(newx - PreX) < 1 && Math.Abs(newy - PreY) < 1)
|
|
//{
|
|
// //Console.WriteLine("SKip Pixel");
|
|
// continue;
|
|
//}
|
|
//else
|
|
//{
|
|
PreX = newx;
|
|
PreY = newy;
|
|
//}
|
|
|
|
if (newx >= wrect.Left && newx <= wrect.Left + wrect.Width) //y축은 구분없이 모두 그리게한다.
|
|
linearrya.Add(new PointF(newx, newy));
|
|
|
|
if (Style.Show_DataPoint)
|
|
{
|
|
var size = 2;
|
|
g.FillEllipse(new SolidBrush(Color.FromArgb(180, ch.Color)), new RectangleF(newx - size, newy - size, size * 2, size * 2));
|
|
g.DrawEllipse(Pens.Black, new RectangleF(newx - size, newy - size, size * 2, size * 2));
|
|
}
|
|
|
|
|
|
idx += 1;
|
|
|
|
}
|
|
if (linearrya.Count > 1)
|
|
g.DrawLines(new Pen(ch.Color, 10), linearrya.ToArray());
|
|
}
|
|
}
|
|
|
|
public void Draw_ZoomSelect(Graphics g)
|
|
{
|
|
//사용자줌영역표시
|
|
if (this.UserZoom.Width != 0)
|
|
{
|
|
int x, y, w, h;
|
|
|
|
w = Math.Abs(UserZoom.Width);
|
|
h = Math.Abs(UserZoom.Height);
|
|
|
|
if (UserZoom.Width > 0) x = UserZoom.Left;
|
|
else x = UserZoom.Width + UserZoom.Left;
|
|
|
|
if (UserZoom.Height > 0) y = UserZoom.Top;
|
|
else y = UserZoom.Height + UserZoom.Top;
|
|
|
|
//Y축 줌을 사용하지 않으므로 높이부분은 모두로 처리한다.
|
|
if (!Style.UseZoomY)
|
|
{
|
|
y = (int)ChartRect.Top;
|
|
h = (int)ChartRect.Height;
|
|
}
|
|
|
|
Rectangle rect = new Rectangle(x, y, w, h);
|
|
|
|
Int64 startx = GetTimeFromX(rect.Left - this.ChartRect.Left, ChartRect); //줌영역의 시작시간정보
|
|
Int64 endx = GetTimeFromX(rect.Left + rect.Width - ChartRect.Left, ChartRect); //줌영역의 종료시간정보
|
|
|
|
Single starty = (Single)GetVoltfromY(rect.Top, ChartRect);
|
|
Single endy = (Single)GetVoltfromY(rect.Top + rect.Height, ChartRect);
|
|
|
|
String ZommMsg = "";
|
|
|
|
//선택된 영역 Drawing
|
|
TimeSpan zoomts = DateTime.FromFileTime(startx) - DateTime.FromFileTime(endx);
|
|
if (Math.Abs(zoomts.TotalSeconds) >= Style.MaxZoomX && Math.Abs(starty - endy) >= Style.MaxZoomY && rect.Width > 20) //150224 줌영역자체의 크기는 10px를 넘도록
|
|
{
|
|
//시간은 최소1분 , 전압값은 최소 1v
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(150, Color.Lime)), rect);
|
|
ZommMsg = Math.Abs(zoomts.TotalSeconds).ToString("N0") + Style.UnitX;
|
|
}
|
|
else
|
|
{
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(150, Color.Red)), rect);
|
|
|
|
if (rect.Width <= 20)
|
|
{
|
|
ZommMsg = "줌 선택영역을 넓게 지정하세요";
|
|
}
|
|
else
|
|
{
|
|
if (Math.Abs(zoomts.TotalSeconds) < Style.MaxZoomX)
|
|
{
|
|
ZommMsg = "줌을 활성화 하려면 최소(" + Style.MaxZoomX.ToString() + Style.UnitX + "의 구간을 선택해야합니다";
|
|
}
|
|
else
|
|
{
|
|
ZommMsg = "줌을 활성화 하려면 최소(" + Style.MaxZoomY.ToString() + Style.UnitY + "의 구간을 선택해야합니다";
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
g.DrawRectangle(Pens.Black, rect);
|
|
|
|
//시간정보 Display
|
|
g.DrawString(GetTimeStr(startx, true, true) + "," + (Style.Y2 - starty).ToString("#0.00") + Style.UnitY, this.Font, Brushes.Black, rect.Left, rect.Top);
|
|
String fontstr = GetTimeStr(endx, true, true) + "," + (Style.Y2 - endy).ToString("#0.00") + Style.UnitY;
|
|
SizeF fontsize = g.MeasureString(fontstr, this.Font);
|
|
g.DrawString(fontstr, this.Font, Brushes.Black, rect.Left - 5 + rect.Width - fontsize.Width, rect.Top + rect.Height - fontsize.Height);
|
|
|
|
if (ZommMsg != "")
|
|
DrawString(g, ZommMsg, this.Font, Brushes.Black, new PointF(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2), EALIGN.CENTER, EALIGN.CENTER);
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 화면의 좌,우 측에 존재하는 이돈버튼(월을 움직이는 버튼이며 월 이동을위해서 이벤트를 발생한다)
|
|
/// </summary>
|
|
/// <param name="G"></param>
|
|
//public void Draw_NaviLR(Graphics G, RectangleF crect)
|
|
//{
|
|
// return;
|
|
|
|
// //LEFT NAVI
|
|
// Single x, y, xw = 30;
|
|
// x = crect.Left - 3;
|
|
// y = crect.Top + crect.Height / 2 - xw / 2;
|
|
|
|
// PointF[] aa = new PointF[4];
|
|
// aa[0] = new PointF(x, y);
|
|
// aa[1] = new PointF(x - xw, y + xw);
|
|
// aa[2] = new PointF(x, y + xw + xw);
|
|
// aa[3] = new PointF(x, y);
|
|
|
|
// PointF[] aa1 = new PointF[4];
|
|
// aa1[0] = new PointF(x + 2, y + 2);
|
|
// aa1[1] = new PointF(x + 2 - xw, y + xw + 2);
|
|
// aa1[2] = new PointF(x + 2, y + xw + xw + 2);
|
|
// aa1[3] = new PointF(x + 2, y + 2);
|
|
// G.FillPolygon(Brushes.Black, aa1);
|
|
// G.FillPolygon(Brushes.DarkRed, aa);
|
|
// G.DrawPolygon(Pens.Black, aa);
|
|
|
|
// Buttons.Add(new RectangleF(x - xw, y, xw, xw*2));
|
|
// Buttonstag.Add("LBUTTON");
|
|
// Buttonstype.Add(EBUTTONTYPE.LEFTMON);
|
|
|
|
// //RIGHT NAVI
|
|
// x = crect.Left + crect.Width + 3;
|
|
// y = crect.Top + crect.Height / 2 - xw / 2;
|
|
|
|
// aa = new PointF[4];
|
|
// aa[0] = new PointF(x, y);
|
|
// aa[1] = new PointF(x + xw, y + xw);
|
|
// aa[2] = new PointF(x, y + xw + xw);
|
|
// aa[3] = new PointF(x, y);
|
|
|
|
// aa1 = new PointF[4];
|
|
// aa1[0] = new PointF(x + 2, y + 2);
|
|
// aa1[1] = new PointF(x + 2 + xw, y + xw + 2);
|
|
// aa1[2] = new PointF(x + 2, y + xw + xw + 2);
|
|
// aa1[3] = new PointF(x + 2, y + 2);
|
|
// G.FillPolygon(Brushes.Black, aa1);
|
|
// G.FillPolygon(Brushes.DarkRed, aa);
|
|
// G.DrawPolygon(Pens.Black, aa);
|
|
// Buttons.Add(new RectangleF(x, y, xw, xw*2));
|
|
// Buttonstag.Add("RBUTTON");
|
|
// Buttonstype.Add(EBUTTONTYPE.RIGHTMON);
|
|
//}
|
|
|
|
|
|
public String GetDateTimeStr(Int64 Filetime, Boolean linefeed)
|
|
{
|
|
DateTime TimeDate = DateTime.FromFileTime(Filetime);
|
|
String timestr = "";
|
|
if (linefeed) timestr = TimeDate.ToShortDateString() + "\n" + TimeDate.ToShortTimeString(); //' yymm + "-" + day.ToString("00") + "\n" + hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");
|
|
else timestr = TimeDate.ToString();// yymm + "-" + day.ToString("00") + " " + hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");
|
|
|
|
return timestr;
|
|
}
|
|
|
|
public String GetTimeStr(Int64 Filetime, Boolean withday, Boolean withseconed, Boolean nolf = false, Boolean showyear = false)
|
|
{
|
|
if (Filetime < 0D) return "-Err-";
|
|
|
|
DateTime TimeDate = DateTime.FromFileTime(Filetime);
|
|
String timestr = "";
|
|
|
|
if (TimeDate.Second == 0 || !withseconed)
|
|
timestr = TimeDate.ToString("HH:mm");// TimeDate.Hour.ToString("00") + ":" + TimeDate.Minute.ToString("00");
|
|
else
|
|
timestr = TimeDate.ToString("HH:mm:ss"); // hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");
|
|
|
|
if (withday)
|
|
{
|
|
if (showyear)
|
|
{
|
|
timestr = TimeDate.ToString("yy-MM-dd") + " " + timestr;
|
|
}
|
|
else
|
|
{
|
|
if (nolf) timestr = TimeDate.ToString("dd") + "일 " + timestr;
|
|
else timestr = timestr + "\n" + TimeDate.ToString("dd") + "일";
|
|
}
|
|
}
|
|
return timestr;
|
|
}
|
|
|
|
/// <summary>
|
|
/// (전체시간 * 현재X) / 전체너비
|
|
/// </summary>
|
|
/// <param name="t"></param>
|
|
/// <returns></returns>
|
|
public Int64 GetTimeFromX(Single X, RectangleF crect)
|
|
{
|
|
DateTime sd = DateTime.FromFileTime(Style.XV1);
|
|
DateTime ed = DateTime.FromFileTime(Style.XV2);
|
|
TimeSpan ts = ed - sd;
|
|
|
|
Int64 gap = (Int64)((ts.TotalMilliseconds * X) / crect.Width);
|
|
return sd.AddMilliseconds(gap).ToFileTime();
|
|
}
|
|
public Single GetXfromTime(Int64 t)
|
|
{
|
|
return (((this.ChartRect.Width) * (t - Style.XV1)) / (Style.XV2 - Style.XV1)) + ChartRect.Left;
|
|
}
|
|
public Single GetXfromTime(Int64 t, RectangleF crect)
|
|
{
|
|
return (((crect.Width) * (t - Style.XV1)) / (Style.XV2 - Style.XV1)) + crect.Left;
|
|
}
|
|
public Single GetVoltfromY(Single Y, RectangleF crect)
|
|
{
|
|
|
|
return ((Style.Y2 - Style.Y1) * Y) / crect.Height;
|
|
|
|
}
|
|
public Single GetYfromVolt(Single volt, RectangleF crect)
|
|
{
|
|
//volt = (Style._endvolt - Style._startvolt) - volt; 150223 : Y값도 X축처럼 표시변수 YV 값으로 수정함
|
|
return (crect.Height - ((crect.Height * (volt - Style.YV1)) / (Style.YV2 - Style.YV1))) + crect.Top;
|
|
}
|
|
|
|
private void DrawString(Graphics G, String str, Font font, Brush br, PointF ops, EALIGN XCenter = EALIGN.LEFT, EALIGN YCenter = EALIGN.LEFT)
|
|
{
|
|
SizeF fsize = G.MeasureString(str, font);
|
|
Single newx = ops.X;
|
|
Single newy = ops.Y;
|
|
|
|
if (XCenter == EALIGN.CENTER) newx = ops.X - fsize.Width / 2;
|
|
else if (XCenter == EALIGN.RIGHT) newx = ops.X - fsize.Width;
|
|
|
|
if (YCenter == EALIGN.CENTER) newy = ops.Y - fsize.Height / 2;
|
|
else if (YCenter == EALIGN.RIGHT) newy = ops.Y - fsize.Height;
|
|
|
|
G.DrawString(str, font, br, newx, newy);
|
|
}
|
|
|
|
public Boolean INIT
|
|
{
|
|
get { return this.init; }
|
|
set { this.init = value; }
|
|
}
|
|
public CChinfo[] CHInfo
|
|
{
|
|
get { return this.chinfo; }
|
|
set { this.chinfo = value; }
|
|
}
|
|
|
|
public (uint min, uint max) RangeX
|
|
{
|
|
get
|
|
{
|
|
var min = (CHInfo.Min(t => t.Value.Where(s => s.Key > 0).Min(v => v.Key)));
|
|
var max = (CHInfo.Max(t => t.Value.Where(s => s.Key > 0).Max(v => v.Key)));
|
|
return (min, max);
|
|
}
|
|
}
|
|
public (float min, float max) RangeY
|
|
{
|
|
get
|
|
{
|
|
//100을 초과한 범위는 제한한다
|
|
var min = CHInfo.Min(t => t.Value.Where(s => s.Value < MaxValueY && s.Value > -MaxValueY).Min(u => u.Value));
|
|
var max = CHInfo.Max(t => t.Value.Where(s => s.Value < MaxValueY && s.Value > -MaxValueY).Max(u => u.Value));
|
|
return (min, max);
|
|
}
|
|
}
|
|
|
|
|
|
public int LegendWidth { get; set; } = 200;
|
|
public RectangleF LegendRect { get; private set; }
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
base.OnResize(e);
|
|
LegendWidth = 100;
|
|
this.WindowRect = new RectangleF(0, 0, this.Width, this.Height);
|
|
if (ShowLegend)
|
|
{
|
|
this.ChartRect = new RectangleF(Padding.Left, Padding.Top,
|
|
this.Width - (Padding.Left + 10) - LegendWidth - 20,
|
|
(Single)(this.Height - (Padding.Top + Padding.Bottom)));
|
|
LegendRect = new RectangleF(ChartRect.Right + 10, ChartRect.Y, LegendWidth + 10, ChartRect.Height);
|
|
}
|
|
else
|
|
{
|
|
this.ChartRect = new RectangleF(Padding.Left, Padding.Top,
|
|
this.Width - (Padding.Left + Padding.Right) - 20,
|
|
(Single)(this.Height - (Padding.Top + Padding.Bottom)));
|
|
LegendRect = RectangleF.Empty; // new RectangleF(ChartRect.Right + 20, ChartRect.Y, LegendWidth, ChartRect.Height);
|
|
|
|
}
|
|
|
|
int SW = this.Width;
|
|
int SH = this.Height;
|
|
if (this.Width == 0 || this.Height == 0)
|
|
{
|
|
SW = 600;
|
|
SH = 600;
|
|
}
|
|
|
|
layer_bak = new Bitmap(SW, SH);
|
|
layer_graph = new Bitmap(SW, SH);
|
|
layer_bakT = new Bitmap(SW, SH);
|
|
layer_graphT = new Bitmap(SW, SH);
|
|
|
|
Graphics.FromImage(layer_bak).Clear(Color.White);
|
|
Graphics.FromImage(layer_bakT).Clear(Color.White);
|
|
|
|
Set_Refresh();
|
|
Invalidate();
|
|
}
|
|
|
|
private int check_userpoint(MouseEventArgs e)
|
|
{
|
|
if (this.uc.Count == 0) return -1;
|
|
for (int i = 0; i < this.uc.Count; i++)
|
|
{
|
|
CUserCursor uuc = this.uc[i];
|
|
|
|
//현재위치가 해당 Rectagle 안이라면 속해있다.
|
|
if ((int)this.Mouseinfo.Position.X >= (int)uuc.Newx - 2 && (int)this.Mouseinfo.Position.X <= (int)(uuc.Newx) + 2 && this.Mouseinfo.Position.Y <= ChartRect.Top)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//private int check_buttons(MouseEventArgs e)
|
|
//{
|
|
// if (this.Buttons == null) return -1;
|
|
// for (int i = 0; i < this.Buttons.Count; i++)
|
|
// {
|
|
// RectangleF rect = this.Buttons[i];
|
|
|
|
// //현재위치가 해당 Rectagle 안이라면 속해있다.
|
|
// if (e.X > rect.X && e.X < rect.X + rect.Width)
|
|
// {
|
|
// if (e.Y > rect.Y && e.Y < rect.Y + rect.Height) return i;
|
|
// }
|
|
// }
|
|
// return -1;
|
|
//}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
this.SuspendLayout();
|
|
//
|
|
// TrendCtrl
|
|
//
|
|
this.Name = "TrendCtrl";
|
|
this.Size = new System.Drawing.Size(287, 321);
|
|
this.Load += new System.EventHandler(this.DispCtrl_Load);
|
|
this.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.TrendCtrl_MouseDoubleClick);
|
|
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TrendCtrl_MouseDown);
|
|
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.TrendCtrl_MouseMove);
|
|
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TrendCtrl_MouseUp);
|
|
this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.TrendCtrl_MouseWhell);
|
|
this.ResumeLayout(false);
|
|
}
|
|
|
|
public void Graph_Reset()
|
|
{
|
|
Style.ResetXxis();
|
|
Style.ResetYxis();
|
|
Set_Refresh();
|
|
Console.WriteLine("Graph : Graph_Reset");
|
|
}
|
|
|
|
private void TrendCtrl_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
|
|
|
|
switch (e.Button)
|
|
{
|
|
case System.Windows.Forms.MouseButtons.Left:
|
|
|
|
//드래그판단을위한 위치값을 저장한다.
|
|
Mouseinfo.DragStart = new PointF(e.X - this.WindowRect.Left, e.Y - WindowRect.Top);
|
|
|
|
//화면이동모드일때는 좌측버튼도 중앙버튼처럼 처리해야한다.
|
|
if (ScreenMove)
|
|
{
|
|
//X축 줌을 사용한경우에만 가능하게 한다.
|
|
if (Style.UseZoomX)
|
|
{
|
|
//아무것도없는 빈공간이라면 화면이동(=줌시작)으로 대체한다.
|
|
if (e.X >= ChartRect.Left && e.X <= ChartRect.Left + ChartRect.Width && e.Y >= ChartRect.Top && e.Y <= ChartRect.Top + ChartRect.Height)
|
|
{
|
|
if (Style.XV2 == Style.X2 && Style.XV1 == Style.X1)
|
|
{
|
|
//데이터영역과 표시영역이 동일하다(이동할 영역이 없는경우이다)
|
|
Mouseinfo.DragType = EDRAGTYPE.NONE;
|
|
}
|
|
else
|
|
{
|
|
//이동할영역이 존재하므로 이동시킨다.
|
|
Mouseinfo.DragType = EDRAGTYPE.SCREEN;
|
|
this.UserZoom = new Rectangle(0, 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
//사용자포인트관련
|
|
int idx = check_userpoint(e);
|
|
if (idx != -1)
|
|
{
|
|
Mouseinfo.DragType = EDRAGTYPE.UC;
|
|
Mouseinfo.DragIndex = idx;
|
|
return;
|
|
}
|
|
|
|
//아무것도없는 빈공간이라면 화면이동(=줌시작)으로 대체한다.
|
|
if (idx == -1 && e.X >= ChartRect.Left && e.X <= ChartRect.Left + ChartRect.Width && e.Y >= ChartRect.Top && e.Y <= ChartRect.Top + ChartRect.Height)
|
|
{
|
|
//좌측버튼은 항상 줌영역을 활성화한다
|
|
if (Style.UseZoomX)
|
|
{
|
|
Mouseinfo.DragType = EDRAGTYPE.ZOOM;
|
|
this.UserZoom = new Rectangle(e.X, e.Y, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
//줌을 사용하지 않기로 하여 ㅆ다면?
|
|
Mouseinfo.DragType = EDRAGTYPE.NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case System.Windows.Forms.MouseButtons.Middle:
|
|
|
|
//X축 줌을 사용한경우에만 가능하게 한다.
|
|
if (Style.UseZoomX)
|
|
{
|
|
//아무것도없는 빈공간이라면 화면이동(=줌시작)으로 대체한다.
|
|
if (e.X >= ChartRect.Left && e.X <= ChartRect.Left + ChartRect.Width && e.Y >= ChartRect.Top && e.Y <= ChartRect.Top + ChartRect.Height)
|
|
{
|
|
if (Style.XV2 == Style.X2 && Style.XV1 == Style.X1)
|
|
{
|
|
//데이터영역과 표시영역이 동일하다(이동할 영역이 없는경우이다)
|
|
Mouseinfo.DragType = EDRAGTYPE.NONE;
|
|
}
|
|
else
|
|
{
|
|
//이동할영역이 존재하므로 이동시킨다.
|
|
Mouseinfo.DragType = EDRAGTYPE.SCREEN;
|
|
this.UserZoom = new Rectangle(0, 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case System.Windows.Forms.MouseButtons.Right: // 줌 초기화
|
|
// if (Message != null) Message("줌영역을 초기화합니다");
|
|
Style.XV1 = Style.XV1o;
|
|
Style.XV2 = Style.XV2o;
|
|
Style.Y1 = Style.YV1o;
|
|
Style.Y2 = Style.YV2o;
|
|
Set_Refresh(); //전체화면용 데이터를 바로 사용하면된다)
|
|
|
|
Console.WriteLine("Mouse R Click : REFRESH");
|
|
Refresh();
|
|
//if(Message != null) Message("");
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
private void TrendCtrl_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
//마우스의 위치가 실시간 저장된다.
|
|
if (this.Mouseinfo == null) this.Mouseinfo = new CMouseinfo(new PointF(e.X - this.WindowRect.Left, e.Y - this.WindowRect.Top));
|
|
else this.Mouseinfo.Position = new PointF(e.X - this.WindowRect.Left, e.Y - this.WindowRect.Top);
|
|
|
|
this.Mouseinfo.Time = GetTimeFromX(Mouseinfo.Position.X - ChartRect.Left, ChartRect); // +this.startview;
|
|
this.Mouseinfo.Volt = this._Style.Y2 - GetVoltfromY(Mouseinfo.Position.Y - ChartRect.Top, ChartRect);
|
|
this.Mouseinfo.Showinfo = false;
|
|
|
|
//MouseStatus initialize...
|
|
Mouseinfo.Hand = false;
|
|
Mouseinfo.Cross = false;
|
|
Mouseinfo.Move = false;
|
|
Mouseinfo.ChangePos = false;
|
|
|
|
//
|
|
if (e.X >= ChartRect.X && e.X <= ChartRect.X + ChartRect.Width)
|
|
if (e.Y >= ChartRect.Top && e.Y <= ChartRect.Top + ChartRect.Height) Mouseinfo.Showinfo = true;
|
|
else Mouseinfo.Showinfo = false;
|
|
|
|
//이동중인데 마우스가 눌려있다면 DRAG다
|
|
if (e.Button == MouseButtons.Left) Mouseinfo.Drag = true;
|
|
else Mouseinfo.Drag = false;
|
|
|
|
|
|
if (Mouseinfo.Drag) //드래그중이다
|
|
{
|
|
Mouseinfo.Move = true; //화면이동으로
|
|
}
|
|
else
|
|
{
|
|
if (e.X >= ChartRect.Left && e.X <= ChartRect.Left + ChartRect.Width)
|
|
{
|
|
if (e.Y >= ChartRect.Top && e.Y <= ChartRect.Top + ChartRect.Height)
|
|
{
|
|
Mouseinfo.Cross = true; //화면내부라면 크로스
|
|
}
|
|
else Mouseinfo.Cross = false;
|
|
}
|
|
else Mouseinfo.Cross = false;
|
|
}
|
|
|
|
//사용자포인터위라면?
|
|
int idx = this.check_userpoint(e);
|
|
if (idx != -1)
|
|
{
|
|
Mouseinfo.Cross = false;
|
|
Mouseinfo.Hand = false;
|
|
Mouseinfo.Drag = false;
|
|
Mouseinfo.ChangePos = true;
|
|
Mouseinfo.DragType = EDRAGTYPE.UC;
|
|
}
|
|
|
|
//드래그중판단
|
|
if (Mouseinfo.Drag)
|
|
{
|
|
switch (Mouseinfo.DragType)
|
|
{
|
|
case EDRAGTYPE.NONE:
|
|
break;
|
|
case EDRAGTYPE.UC:
|
|
Single newx = (e.X);
|
|
Int64 newtime = GetTimeFromX(newx - ChartRect.Left, ChartRect);
|
|
if (Mouseinfo.DragIndex < uc.Count)
|
|
{
|
|
//데이터가 없는경우이다.
|
|
this.uc[Mouseinfo.DragIndex].Newx = newx;
|
|
this.uc[Mouseinfo.DragIndex].Time = newtime;
|
|
}
|
|
break;
|
|
case EDRAGTYPE.ZOOM:
|
|
this.UserZoom.Width = (int)(e.X - WindowRect.X - Mouseinfo.DragStart.X);
|
|
if (Key_Control || Style.UseZoomY) //컨트롤이 눌려져있다면 줌을 사용한다.
|
|
{
|
|
this.UserZoom.Height = (int)(e.Y - WindowRect.Y - Mouseinfo.DragStart.Y);
|
|
}
|
|
else
|
|
{
|
|
this.UserZoom.Height = (int)ChartRect.Height;// (int)(e.Y - Mouseinfo.DragStart.Y - ChartRect.Left);
|
|
}
|
|
|
|
if (Mouseinfo.Cross) this.Cursor = Cursors.Cross;
|
|
break;
|
|
case EDRAGTYPE.SCREEN:
|
|
|
|
if (Mouseinfo.Move)
|
|
{
|
|
this.Cursor = Cursors.NoMove2D;
|
|
Mouseinfo.Showinfo = false;
|
|
}
|
|
|
|
|
|
//이동한pixcel을 시간정보로 변환한다.
|
|
//현재마우스위치값 - 드래그시작마우스위치값을 뺸 픽셀을 초로환산한다.
|
|
Single term = Mouseinfo.DragStart.X - Mouseinfo.Position.X; //양수라면 오른쪽으로 이동했다.
|
|
TimeSpan termtime = DateTime.FromFileTime(GetTimeFromX(Mouseinfo.Position.X, ChartRect)) - DateTime.FromFileTime(GetTimeFromX(Mouseinfo.DragStart.X, ChartRect));
|
|
|
|
|
|
Int64 NewSD = DateTime.FromFileTime(Style.XV1).AddSeconds(-1 * termtime.TotalSeconds).ToFileTime();// + (int)mstime;
|
|
Int64 NewED = DateTime.FromFileTime(Style.XV2o).AddSeconds(-1 * termtime.TotalSeconds).ToFileTime(); //endviewo + (int)mstime;
|
|
|
|
//해당 시간영역의 전체 데이터 영역에 들어있어야 이동이 가능하다
|
|
if ((NewSD > Style.X1 && NewED < Style.X2))
|
|
{
|
|
Style.XV1 = NewSD;
|
|
Style.XV2 = NewED;
|
|
|
|
//y축 사용시에만 설정되게한다.
|
|
if (Key_Control || Style.UseZoomY)
|
|
{
|
|
Single termy = Mouseinfo.Position.Y - Mouseinfo.DragStart.Y - ChartRect.Top;
|
|
Single termvolt = GetVoltfromY(termy, ChartRect);
|
|
Single mvolt = termvolt;
|
|
|
|
Single SV = Style.YV1o + mvolt;
|
|
Single EV = Style.YV2o + mvolt;
|
|
|
|
Style.YV1 = SV;
|
|
Style.YV2 = EV;
|
|
|
|
|
|
}
|
|
Mouseinfo.DragStart = Mouseinfo.Position; //현재위치부터 드래그가 다시되도록
|
|
Set_Refresh();
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Mouseinfo.Hand) this.Cursor = Cursors.Hand;
|
|
if (Mouseinfo.Cross) this.Cursor = Cursors.Cross;
|
|
if (Mouseinfo.ChangePos) this.Cursor = Cursors.SizeWE;
|
|
}
|
|
|
|
this.Refresh();
|
|
}
|
|
|
|
|
|
public void Graph_Left(int perc)
|
|
{
|
|
DateTime newStartview = DateTime.FromFileTime(this.Style.XV1);
|
|
DateTime newEndview = DateTime.FromFileTime(this.Style.XV2);
|
|
TimeSpan term = newEndview - newStartview;
|
|
DateTime NewStart = newStartview.AddMinutes(-1 * (term.TotalMinutes / perc));
|
|
DateTime NewEnd = newEndview.AddMinutes(-1 * (term.TotalMinutes / perc));
|
|
if (NewStart < DateTime.FromFileTime(Style.X1)) return;
|
|
this.Style.XV1 = NewStart.ToFileTime();
|
|
this.Style.XV2 = NewEnd.ToFileTime();
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : Graph_Left");
|
|
}
|
|
|
|
public void Graph_Right(int perc)
|
|
{
|
|
DateTime newStartview = DateTime.FromFileTime(this.Style.XV1);
|
|
DateTime newEndview = DateTime.FromFileTime(this.Style.XV2);
|
|
TimeSpan term = newEndview - newStartview;
|
|
DateTime NewStart = newStartview.AddMinutes(term.TotalMinutes / perc);
|
|
DateTime NewEnd = newEndview.AddMinutes(term.TotalMinutes / perc);
|
|
if (NewEnd > DateTime.FromFileTime(Style.X2)) return;
|
|
this.Style.XV1 = NewStart.ToFileTime();
|
|
this.Style.XV2 = NewEnd.ToFileTime();
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : Graph_Right");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 그래프의 Y축 좌표영역을 10% 위로 이동합니다.
|
|
/// </summary>
|
|
public void Graph_Up()
|
|
{
|
|
Single v = (Style.YV2 - Style.YV1) / 10;
|
|
Style.YV2 -= v;
|
|
Style.YV1 -= v;
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : Graph_Up");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 그래프의 Y축 좌표영역을 10% 아래로 이동합니다.
|
|
/// </summary>
|
|
public void Graph_Down()
|
|
{
|
|
Single v = (Style.YV2 - Style.YV1) / 10;
|
|
Style.YV2 += v;
|
|
Style.YV1 += v;
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : Graph_Down");
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 현재 그래프의 Y축 좌표영역을 10% 확대합니다.
|
|
/// </summary>
|
|
public void Graph_ZoomInY()
|
|
{
|
|
Single v = (Style.YV2 - Style.YV1) / 10;
|
|
Style.YV2 -= v;
|
|
Style.YV1 += v;
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : Graph_ZoomInY");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 그래프의 Y축 좌표영역을 10% 축소합니다.
|
|
/// </summary>
|
|
public void Graph_ZommOutY()
|
|
{
|
|
Single v = (Style.YV2 - Style.YV1) / 10;
|
|
Style.YV2 += v;
|
|
Style.YV1 -= v;
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : Graph_ZommOutY");
|
|
}
|
|
|
|
|
|
public void ZoomIN()
|
|
{
|
|
DateTime newStartview = DateTime.FromFileTime(this.Style.XV1);
|
|
DateTime newEndview = DateTime.FromFileTime(this.Style.XV2);
|
|
TimeSpan term = newEndview - newStartview;
|
|
DateTime NewStart = newStartview.AddMinutes(term.TotalMinutes / 20);
|
|
DateTime NewEnd = newEndview.AddMinutes(-1 * (term.TotalMinutes / 20));
|
|
if (NewStart >= DateTime.FromFileTime(Style.X2).AddMinutes(-10)) NewStart = DateTime.FromFileTime(Style.X2).AddMinutes(-10);
|
|
if (NewEnd <= DateTime.FromFileTime(Style.X1).AddMinutes(10)) NewEnd = DateTime.FromFileTime(Style.X1).AddMinutes(10);
|
|
Style.XV1 = NewStart.ToFileTime();
|
|
this.Style.XV2 = NewEnd.ToFileTime();
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : ZoomIN");
|
|
}
|
|
|
|
public void ZoomOUT()
|
|
{
|
|
DateTime newStartview = DateTime.FromFileTime(Style.XV1);
|
|
DateTime newEndview = DateTime.FromFileTime(Style.XV2);
|
|
TimeSpan term = newEndview - newStartview;
|
|
DateTime NewStart = newStartview.AddMinutes(-1 * (term.TotalMinutes / 20));
|
|
DateTime NewEnd = newEndview.AddMinutes(term.TotalMinutes / 20);
|
|
if (newStartview < DateTime.FromFileTime(Style.X1)) NewStart = DateTime.FromFileTime(Style.X1);
|
|
if (newEndview > DateTime.FromFileTime(Style.X2)) NewEnd = DateTime.FromFileTime(Style.X2);
|
|
Style.XV1 = NewStart.ToFileTime();
|
|
Style.XV2 = NewEnd.ToFileTime();
|
|
Set_Refresh();
|
|
Refresh();
|
|
Console.WriteLine("Graph : ZoomOUT");
|
|
}
|
|
|
|
private void TrendCtrl_MouseWhell(object sender, MouseEventArgs e)
|
|
{
|
|
if (Key_Control)
|
|
{
|
|
//온도축 변경(Y)
|
|
Single news, newe;
|
|
|
|
news = Style.Y2;
|
|
newe = Style.Y1;
|
|
|
|
Single TimerTerm = newe - news;
|
|
|
|
if (e.Delta > 0)
|
|
{
|
|
//확대
|
|
news = news + (TimerTerm / 10);
|
|
newe = newe + (-1 * (TimerTerm / 10));
|
|
}
|
|
else
|
|
{
|
|
//축소(down)
|
|
news = news + (-1 * (TimerTerm / 10));
|
|
newe = newe + (1 * (TimerTerm / 10));
|
|
}
|
|
|
|
if (news > 400) news = 400;
|
|
if (news < -200) news = -200;
|
|
|
|
|
|
Style.Y2 = news;
|
|
Style.Y1 = newe;
|
|
}
|
|
else
|
|
{
|
|
//시간축 변경(X)
|
|
DateTime news, newe;
|
|
|
|
news = DateTime.FromFileTime(Style.XV1);
|
|
newe = DateTime.FromFileTime(Style.XV2);
|
|
|
|
TimeSpan TimerTerm = newe - news;
|
|
|
|
if (e.Delta > 0)
|
|
{
|
|
//확대
|
|
if (TimerTerm.TotalSeconds < Style.MaxZoomX) return;
|
|
news = news.AddSeconds(TimerTerm.TotalSeconds / 10);
|
|
newe = newe.AddSeconds(-1 * (TimerTerm.TotalSeconds / 10));
|
|
}
|
|
else
|
|
{
|
|
//축소(down)
|
|
news = news.AddSeconds(-1 * (TimerTerm.TotalSeconds / 10));
|
|
newe = newe.AddSeconds(1 * (TimerTerm.TotalSeconds / 10));
|
|
}
|
|
|
|
if (news > DateTime.FromFileTime(Style.X2)) news = DateTime.FromFileTime(Style.X2);
|
|
if (news < DateTime.FromFileTime(Style.X1)) news = DateTime.FromFileTime(Style.X1);
|
|
if (newe > DateTime.FromFileTime(Style.X2)) newe = DateTime.FromFileTime(Style.X2);
|
|
if (newe < DateTime.FromFileTime(Style.X1)) newe = DateTime.FromFileTime(Style.X1);
|
|
|
|
if (news < DateTime.FromFileTime(Style.X1) || newe > DateTime.FromFileTime(Style.X2))
|
|
{
|
|
//MessageBox.Show("데이터가 없으므로 줌을 사용할 수 없습니다");
|
|
}
|
|
else
|
|
{
|
|
Style.XV1 = news.ToFileTime();
|
|
Style.XV2 = newe.ToFileTime();
|
|
Style.XV1 = news.ToFileTime();
|
|
Style.XV2o = newe.ToFileTime();
|
|
}
|
|
|
|
}
|
|
|
|
this.Set_Refresh();
|
|
this.Refresh();
|
|
Console.WriteLine("Graph : Mouse Wheel");
|
|
}
|
|
|
|
private void TrendCtrl_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
Mouseinfo.Drag = false;
|
|
if (Mouseinfo.DragType == EDRAGTYPE.UC)
|
|
{
|
|
Refresh_Grpah = true; //다시값을 계산하려면 실행해야함
|
|
this.Refresh();
|
|
Console.WriteLine("Graph : MouseUp1");
|
|
|
|
if (OnUpdateUserCursor != null)
|
|
OnUpdateUserCursor(Mouseinfo.DragIndex);
|
|
}
|
|
else
|
|
{
|
|
if (UserZoom.Width != 0 && e.Button == System.Windows.Forms.MouseButtons.Left) //줌영역이 있다면 줌을 활성화한다.
|
|
{
|
|
int x1, x2, y1, y2;
|
|
|
|
x1 = UserZoom.Left;
|
|
x2 = UserZoom.Left + UserZoom.Width;
|
|
|
|
if (!Style.UseZoomY)
|
|
{
|
|
y1 = (int)ChartRect.Top;
|
|
y2 = (int)ChartRect.Bottom;
|
|
}
|
|
else
|
|
{
|
|
y1 = UserZoom.Top;
|
|
y2 = UserZoom.Bottom;
|
|
}
|
|
|
|
|
|
Int64 startx = GetTimeFromX(x1 - ChartRect.Left, ChartRect);
|
|
Int64 endx = GetTimeFromX(x2 - ChartRect.Left, ChartRect);
|
|
|
|
Single endy = Style.Y2 - GetVoltfromY(y1 - ChartRect.Top, ChartRect);
|
|
Single starty = Style.Y2 - GetVoltfromY(y2 - ChartRect.Top, ChartRect);
|
|
|
|
if (endx < startx) //교환
|
|
{
|
|
Int64 t = startx;
|
|
startx = endx;
|
|
endx = t;
|
|
}
|
|
|
|
if (endy < starty) //교환
|
|
{
|
|
Single t = starty;
|
|
starty = endy;
|
|
endy = t;
|
|
}
|
|
|
|
TimeSpan tst = DateTime.FromFileTime(endx) - DateTime.FromFileTime(startx);
|
|
Single VoltTerm = endy - starty;
|
|
if (tst.TotalSeconds >= Style.MaxZoomX && VoltTerm >= Style.MaxZoomY && UserZoom.Width > 20) //보기영역이 5초는 넘어야 줌이 가능한다.
|
|
{
|
|
this.Style.XV1 = startx;
|
|
this.Style.XV2 = endx;
|
|
|
|
this.Style.YV1 = starty;// +this.Style.최소값;
|
|
this.Style.YV2 = endy;// +this.Style.최대값;
|
|
|
|
UserZoom.Width = 0;
|
|
Set_Refresh();
|
|
this.Refresh();
|
|
Console.WriteLine("Graph : MouseUp2");
|
|
}
|
|
else
|
|
{
|
|
UserZoom.Width = 0;
|
|
Set_Refresh();
|
|
this.Refresh();
|
|
Console.WriteLine("Graph : MouseUp3");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void TrendCtrl_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
////마우스더블클릭
|
|
//int idx = check_userpoint(e);
|
|
//if (idx != -1)
|
|
//{
|
|
// //삭제한다.
|
|
// uc.Remove(uc[Mouseinfo.DragIndex]);
|
|
// if (uc.Count == 1)
|
|
// {
|
|
// uc[0].Idx = 0;
|
|
// foreach (CChinfo c in this.chinfo)
|
|
// {
|
|
// c.C2value = "";
|
|
// }
|
|
// }
|
|
|
|
// Refresh_Grpah = true; //다시갱신해야 값이 계산됨
|
|
// this.Refresh();
|
|
|
|
// if(OnUpdateUserCursor != null)
|
|
// OnUpdateUserCursor(Mouseinfo.DragIndex);
|
|
|
|
// return;
|
|
//}
|
|
|
|
//if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
|
//{
|
|
// if (this.uc.Count < 2)
|
|
// {
|
|
// Single newx = GetXfromTime(Mouseinfo.Time, ChartRect);
|
|
// this.uc.Add(new CUserCursor((short)this.uc.Count, Mouseinfo.Time, newx));
|
|
|
|
// Refresh_Grpah = true; //다시갱신해야 값이 계산됨
|
|
// this.Refresh();
|
|
|
|
// if (OnUpdateUserCursor != null)
|
|
// OnUpdateUserCursor(this.uc.Count);
|
|
// }
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
private void DispCtrl_Load(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
} //end class
|
|
|
|
} //end namespace |