You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

681 lines
23 KiB

using System;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
namespace SSControls
{
public partial class SSChart : UserControl
{
private Timer RedrawTimer;
private Bitmap _backbuffer;
public bool redrawactive;
protected override void OnSizeChanged(EventArgs e)
{
if (_backbuffer != null)
{
_backbuffer.Dispose();
_backbuffer = null;
}
if (!_scaleonresize)
{
Page.Width = this.Width;
Page.Height = this.Height;
}
if (RedrawTimer == null)
{
RedrawTimer = new Timer();
RedrawTimer.Tick += RedrawTimer_Tick;
RedrawTimer.Interval = 100;
RedrawTimer.Start();
}
Invalidate();
base.OnSizeChanged(e);
}
protected override void OnPaint(PaintEventArgs e)
{
if (_backbuffer != null)
{
e.Graphics.DrawImageUnscaled(_backbuffer, 0, 0);
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//MyBase.OnPaintBackground(e)
}
public class GMargins
{
private float _left = 50;
private float _right = 35;
private float _top = 30;
private float _bottom = 30;
public event ChangedEventHandler Changed;
public delegate void ChangedEventHandler();
public float Left
{
get { return _left; }
set
{
if (_left != value)
{
_left = value;
Changed?.Invoke();
}
}
}
public float Right
{
get { return _right; }
set
{
if (_right != value)
{
_right = value;
Changed?.Invoke();
}
}
}
public float Top
{
get { return _top; }
set
{
if (_top != value)
{
_top = value;
Changed?.Invoke();
}
}
}
public float Bottom
{
get { return _bottom; }
set
{
if (_bottom != value)
{
_bottom = value;
Changed?.Invoke();
}
}
}
}
public class GPage
{
private float _width = 400;
private float _height = 300;
public event ChangedEventHandler Changed;
public delegate void ChangedEventHandler();
public GMargins Margins = new GMargins();
public GPage()
{
Margins.Changed += Margins_Changed;
}
public float Width
{
get { return _width; }
set
{
if (_width != value)
{
if (value > Margins.Left + Margins.Right)
{
_width = value;
Changed?.Invoke();
}
}
}
}
public float Height
{
get { return _height; }
set
{
if (_height != value)
{
if (value > Margins.Top + Margins.Bottom)
{
_height = value;
Changed?.Invoke();
}
}
}
}
public float DrawWidth
{
get { return _width - Margins.Left - Margins.Right; }
}
public float DrawHeight
{
get { return _height - Margins.Top - Margins.Bottom; }
}
private void Margins_Changed()
{
Changed?.Invoke();
}
}
public class GScale
{
public enum GScaleTypes : byte
{
HorBottom = 0,
HorTop = 1,
VerLeft = 2,
VerRight = 3
}
private GScaleTypes _scaletype = GScaleTypes.HorBottom;
public GScaleTypes ScaleType
{
get { return _scaletype; }
set
{
switch (value)
{
case GScaleTypes.HorTop:
ValSFormat.Alignment = StringAlignment.Center;
ValSFormat.LineAlignment = StringAlignment.Far;
break;
case GScaleTypes.VerLeft:
ValSFormat.Alignment = StringAlignment.Far;
ValSFormat.LineAlignment = StringAlignment.Center;
break;
case GScaleTypes.VerRight:
ValSFormat.Alignment = StringAlignment.Near;
ValSFormat.LineAlignment = StringAlignment.Center;
break;
default:
ValSFormat.Alignment = StringAlignment.Center;
ValSFormat.LineAlignment = StringAlignment.Near;
break;
}
_scaletype = value;
}
}
public bool PaintOver = false;
public float ValFrom = 0;
public float ValTo = 100;
public float ValMinStep = 5;
public float ValMajStep = 10;
public float ValMinSize = 2;
public float ValMajSize = 4;
public float sX = 0;
public float sY = 0;
public Pen Pen = new Pen(Brushes.White);
public bool Visible = false;
public Font ValFont = (Font)SystemFonts.SmallCaptionFont.Clone();
public string ValFormat = "0.00";
public bool ValVisible = true;
public StringFormat ValSFormat = new StringFormat();
public float ValOffset = 0;
public Brush ValBrush = new SolidBrush(Color.Aquamarine);
public bool ShowMinLines = true;
public Pen MinLinesPen = new Pen(new SolidBrush(Color.FromArgb(0x60606060)));
public bool ShowMajLines = true;
public Pen MajLinesPen = new Pen(new SolidBrush(Color.FromArgb(unchecked((int)0x90909090))));
public GScale()
{
var _with1 = ValSFormat;
_with1.Alignment = StringAlignment.Center;
_with1.LineAlignment = StringAlignment.Near;
Pen.Width = (float)0.000001;
}
public void Dispose()
{
if (Pen != null) Pen.Dispose();
if (ValFont != null) ValFont.Dispose();
if (ValSFormat != null) ValSFormat.Dispose();
if (ValBrush != null) ValBrush.Dispose();
if (MinLinesPen != null) MinLinesPen.Dispose();
if (MajLinesPen != null) MajLinesPen.Dispose();
Pen = null;
ValFont = null;
ValSFormat = null;
ValBrush = null;
MinLinesPen = null;
MajLinesPen = null;
}
public void Draw(ref Graphics g, ref GPage p)
{
float s = 0;
float s1 = 0;
float s2 = 0;
float eX = 0;
float eY = 0;
float majXOff = 0;
float majYoff = 0;
float minXoff = 0;
float minYoff = 0;
float vXoff = 0;
float vYoff = 0;
if (Visible)
{
switch (_scaletype)
{
case GScaleTypes.HorBottom:
eX = sX + p.DrawWidth;
eY = sY;
majXOff = 0;
majYoff = ValMajSize;
minXoff = 0;
minYoff = ValMinSize;
vXoff = 0;
vYoff = ValOffset + ValMajSize;
break;
case GScaleTypes.HorTop:
eX = sX + p.DrawWidth;
eY = sY;
majXOff = 0;
majYoff = -ValMajSize;
minXoff = 0;
minYoff = -ValMinSize;
vXoff = 0;
vYoff = -ValOffset - ValMajSize;
break;
case GScaleTypes.VerLeft:
eX = sX;
eY = sY - p.DrawHeight;
majXOff = -ValMajSize;
majYoff = 0;
minXoff = -ValMinSize;
minYoff = 0;
vXoff = -ValOffset - ValMajSize;
vYoff = 0;
break;
case GScaleTypes.VerRight:
eX = sX;
eY = sY - p.DrawHeight;
majXOff = ValMajSize;
majYoff = 0;
minXoff = ValMinSize;
minYoff = 0;
vXoff = ValOffset + ValMajSize;
vYoff = 0;
break;
}
if (ValFrom != ValTo)
{
g.DrawLine(Pen, sX, sY, eX, eY);
if (ValMinStep > 0)
{
for (s = ValFrom; s <= ValTo; s += ValMinStep)
{
s1 = sX + (((s - ValFrom) / (ValTo - ValFrom))) * (eX - sX);
s2 = sY + (((s - ValFrom) / (ValTo - ValFrom))) * (eY - sY);
g.DrawLine(Pen, s1, s2, s1 + minXoff, s2 + minYoff);
if (ShowMinLines)
{
switch (_scaletype)
{
case GScaleTypes.VerRight:
case GScaleTypes.VerLeft:
g.DrawLine(MinLinesPen, 0, s2, p.DrawWidth, s2);
break;
default:
g.DrawLine(MinLinesPen, s1, 0, s1, -p.DrawHeight);
break;
}
}
}
}
if (ValMajStep > 0)
{
for (s = ValFrom; s <= ValTo; s += ValMajStep)
{
s1 = sX + (((s - ValFrom) / (ValTo - ValFrom))) * (eX - sX);
s2 = sY + (((s - ValFrom) / (ValTo - ValFrom))) * (eY - sY);
g.DrawLine(Pen, s1, s2, s1 + majXOff, s2 + majYoff);
if (ShowMajLines)
{
switch (_scaletype)
{
case GScaleTypes.VerRight:
case GScaleTypes.VerLeft:
g.DrawLine(MajLinesPen, 0, s2, p.DrawWidth, s2);
break;
default:
g.DrawLine(MajLinesPen, s1, 0, s1, -p.DrawHeight);
break;
}
}
if (ValVisible)
{
g.DrawString(s.ToString(ValFormat), ValFont, ValBrush, s1 + vXoff, s2 + vYoff, ValSFormat);
}
}
}
}
}
}
}
public class GDrawing
{
public bool Visible = true;
public Boolean ShowPoints = false;
public Pen Pen = new Pen(Brushes.Red);
public GScale XScale;
public GScale Yscale;
public PointF[] Points;
public long PointsNum
{
get
{
if (Points == null)
{
return 0;
}
else
{
try
{
return Points.Length;
}
catch
{
return 0;
}
}
}
set
{
long oldnum = 0;
long i = 0;
oldnum = PointsNum;
if (oldnum != value)
{
if (value > 0)
{
Array.Resize(ref Points, (int)value);
for (i = oldnum; i < value; i++)
{
Points[i] = new PointF();
}
}
else
{
Points = null;
}
}
}
}
public void Draw(ref Graphics g, ref GPage p)
{
Matrix m = null;
float[] mtx = null;
m = g.Transform.Clone();
g.ScaleTransform(p.DrawWidth / (XScale.ValTo - XScale.ValFrom), -p.DrawHeight / (Yscale.ValTo - Yscale.ValFrom));
g.TranslateTransform(XScale.ValFrom, -Yscale.ValFrom);
Pen.ResetTransform();
mtx = g.Transform.Elements;
Pen.ScaleTransform(1 / mtx[0], 1 / mtx[3]);
Pen.TranslateTransform(0, 0);
if (Points != null) {
g.DrawLines(Pen, Points);
if (ShowPoints) {
var c = Pen.Color;
Pen.Color = Color.FromArgb(255 - Pen.Color.R, 255 - Pen.Color.G, 255 - Pen.Color.B);
g.DrawRectangles(Pen, Points.Select(x => new RectangleF(x.X, x.Y, (float)0.01,1)).ToArray());
Pen.Color = c;
}
}
g.Transform.Dispose();
g.Transform = m;
}
~GDrawing()
{
Pen.Dispose();
}
}
public GPage Page = new GPage();
private bool _scaleonresize = false;
private GScale[] _scales;
private GDrawing[] _drawings;
public bool ScaleOnResize
{
get { return _scaleonresize; }
set { _scaleonresize = value; }
}
public GScale Scales(int index)
{
return _scales[index];
}
public GDrawing Drawings(int index)
{
return _drawings[index];
}
public GDrawing[] Drawings1
{
get { return _drawings; }
}
public long ScaleNum
{
get
{
if (_scales == null)
{
return 0;
}
else
{
try
{
return _scales.Length;
}
catch
{
return 0;
}
}
}
set
{
long i = 0;
long oldnum = 0;
oldnum = ScaleNum;
if (oldnum != value)
{
if (value > 0)
{
for (i = value; i <= oldnum - 1; i++)
{
_scales[i] = null;
}
Array.Resize(ref _scales, (int)value);
for (i = oldnum; i <= value - 1; i++)
{
_scales[i] = new GScale();
}
}
else
{
for (i = 0; i <= ScaleNum - 1; i++)
{
_scales[i] = null;
}
_scales = null;
}
}
}
}
public long DrawingsNum
{
get
{
if (_drawings == null)
{
return 0;
}
else
{
try
{
return _drawings.Length;
}
catch
{
return 0;
}
}
}
set
{
long i = 0;
long oldnum = 0;
oldnum = DrawingsNum;
if (oldnum != value)
{
if (value != 0)
{
for (i = value; i <= oldnum - 1; i++)
{
_drawings[i] = null;
}
Array.Resize(ref _drawings, (int)value);
for (i = oldnum; i <= value - 1; i++)
{
_drawings[i] = new GDrawing();
}
}
else
{
for (i = 0; i <= oldnum - 1; i++)
{
_drawings[i] = null;
}
_drawings = null;
}
}
}
}
public void _Redraw()
{
long i = 0;
redrawactive = true;
_backbuffer = null;
if (_backbuffer == null)
{
_backbuffer = new Bitmap(Math.Max(this.ClientSize.Width, 2), Math.Max(this.ClientSize.Height, 2));
Graphics g = Graphics.FromImage(_backbuffer);
g.ScaleTransform(Math.Max(this.Width, 2) / Page.Width, Math.Max(this.Height, 2) / Page.Height);
g.TranslateTransform(Page.Margins.Left, Page.Height - Page.Margins.Bottom);
g.Clear(BackColor);
g.SmoothingMode = SmoothingMode.HighSpeed;
for (i = 0; i <= ScaleNum - 1; i++)
{
if(!_scales[i].PaintOver) _scales[i].Draw(ref g, ref Page);
}
g.SmoothingMode = SmoothingMode.HighQuality;
foreach(var d in _drawings)
{
if (d.Visible) d.Draw(ref g, ref Page);
}
g.SmoothingMode = SmoothingMode.HighSpeed;
for (i = 0; i <= ScaleNum - 1; i++)
{
if (_scales[i].PaintOver) _scales[i].Draw(ref g, ref Page);
}
g.Dispose();
if (!this.IsDisposed)
{
g = this.CreateGraphics();
g.DrawImageUnscaled(_backbuffer, 0, 0);
g.Dispose();
}
}
Application.DoEvents();
redrawactive = false;
}
public SSChart()
{
long i = 0;
// This call is required by the designer.
InitializeComponent();
// Add any initialization after the InitializeComponent() call.
ScaleNum = 2;
_scales[0].ScaleType = GScale.GScaleTypes.HorBottom;
_scales[0].Visible = true;
_scales[0].sX = 0;
_scales[0].sY = 0;
_scales[0].Pen.Width = 1;
_scales[1].ScaleType = GScale.GScaleTypes.VerLeft;
_scales[1].Visible = true;
_scales[1].sX = 0;
_scales[1].sY = 0;
_scales[1].Pen.Width = 1;
DrawingsNum = 1;
_drawings[0].Pen.Width = 1;
_drawings[0].XScale = Scales(0);
_drawings[0].Yscale = Scales(0);
_drawings[0].PointsNum = 1000;
Random r = new Random();
for (i = 0; i <= _drawings[0].PointsNum - 1; i++)
{
_drawings[0].Points[i].X = Convert.ToSingle(i) / 10;
_drawings[0].Points[i].Y = (float)(r.Next(0, 50) + Math.Sin(i / 50) * 25 + 25);
}
}
private void RedrawTimer_Tick(object sender, EventArgs e)
{
RedrawTimer.Stop();
RedrawTimer.Tick -= RedrawTimer_Tick;
RedrawTimer.Dispose();
RedrawTimer = null;
_Redraw();
}
}
}