* UILineChart: 支持数据包括Nan

This commit is contained in:
Sunny 2021-10-03 10:11:03 +08:00
parent f11a898b84
commit 39a8472c85
9 changed files with 84 additions and 86 deletions

Binary file not shown.

Binary file not shown.

View File

@ -36,8 +36,8 @@
this.LineChart = new Sunny.UI.UILineChart();
this.uiSymbolButton2 = new Sunny.UI.UISymbolButton();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.uiCheckBox1 = new Sunny.UI.UICheckBox();
this.uiSymbolButton3 = new Sunny.UI.UISymbolButton();
this.cbPoints = new Sunny.UI.UICheckBox();
this.cbContainsNan = new Sunny.UI.UICheckBox();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton3)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton1)).BeginInit();
@ -132,41 +132,39 @@
//
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// uiCheckBox1
// cbPoints
//
this.uiCheckBox1.Cursor = System.Windows.Forms.Cursors.Hand;
this.uiCheckBox1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiCheckBox1.Location = new System.Drawing.Point(571, 505);
this.uiCheckBox1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiCheckBox1.Name = "uiCheckBox1";
this.uiCheckBox1.Padding = new System.Windows.Forms.Padding(22, 0, 0, 0);
this.uiCheckBox1.Size = new System.Drawing.Size(100, 29);
this.uiCheckBox1.TabIndex = 37;
this.uiCheckBox1.Text = "显示点";
this.uiCheckBox1.CheckedChanged += new System.EventHandler(this.uiCheckBox1_CheckedChanged);
this.cbPoints.Cursor = System.Windows.Forms.Cursors.Hand;
this.cbPoints.Font = new System.Drawing.Font("微软雅黑", 12F);
this.cbPoints.Location = new System.Drawing.Point(571, 505);
this.cbPoints.MinimumSize = new System.Drawing.Size(1, 1);
this.cbPoints.Name = "cbPoints";
this.cbPoints.Padding = new System.Windows.Forms.Padding(22, 0, 0, 0);
this.cbPoints.Size = new System.Drawing.Size(95, 27);
this.cbPoints.TabIndex = 37;
this.cbPoints.Text = "只显示点";
this.cbPoints.CheckedChanged += new System.EventHandler(this.uiCheckBox1_CheckedChanged);
//
// uiSymbolButton3
// cbContainsNan
//
this.uiSymbolButton3.Cursor = System.Windows.Forms.Cursors.Hand;
this.uiSymbolButton3.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiSymbolButton3.Location = new System.Drawing.Point(665, 505);
this.uiSymbolButton3.MinimumSize = new System.Drawing.Size(1, 1);
this.uiSymbolButton3.Name = "uiSymbolButton3";
this.uiSymbolButton3.Padding = new System.Windows.Forms.Padding(28, 0, 0, 0);
this.uiSymbolButton3.Size = new System.Drawing.Size(100, 27);
this.uiSymbolButton3.Symbol = 61952;
this.uiSymbolButton3.TabIndex = 38;
this.uiSymbolButton3.Text = "数据";
this.uiSymbolButton3.Visible = false;
this.uiSymbolButton3.Click += new System.EventHandler(this.uiSymbolButton3_Click);
this.cbContainsNan.Cursor = System.Windows.Forms.Cursors.Hand;
this.cbContainsNan.Font = new System.Drawing.Font("微软雅黑", 12F);
this.cbContainsNan.Location = new System.Drawing.Point(571, 535);
this.cbContainsNan.MinimumSize = new System.Drawing.Size(1, 1);
this.cbContainsNan.Name = "cbContainsNan";
this.cbContainsNan.Padding = new System.Windows.Forms.Padding(22, 0, 0, 0);
this.cbContainsNan.Size = new System.Drawing.Size(95, 27);
this.cbContainsNan.TabIndex = 38;
this.cbContainsNan.Text = "包含Nan";
this.cbContainsNan.CheckedChanged += new System.EventHandler(this.uiCheckBox2_CheckedChanged);
//
// FLineChart
//
this.AllowShowTitle = true;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.ClientSize = new System.Drawing.Size(800, 574);
this.Controls.Add(this.uiSymbolButton3);
this.Controls.Add(this.uiCheckBox1);
this.Controls.Add(this.cbContainsNan);
this.Controls.Add(this.cbPoints);
this.Controls.Add(this.uiSymbolButton2);
this.Controls.Add(this.uiSymbolButton1);
this.Controls.Add(this.uiImageButton3);
@ -194,7 +192,7 @@
private UILineChart LineChart;
private UISymbolButton uiSymbolButton2;
private System.Windows.Forms.Timer timer1;
private UICheckBox uiCheckBox1;
private UISymbolButton uiSymbolButton3;
private UICheckBox cbPoints;
private UICheckBox cbContainsNan;
}
}

View File

@ -29,13 +29,14 @@ namespace Sunny.UI.Demo
series.Add(dt.AddHours(0), 1.2);
series.Add(dt.AddHours(1), 2.2);
series.Add(dt.AddHours(2), 3.2);
series.Add(dt.AddHours(3), 4.2);
series.Add(dt.AddHours(3), cbContainsNan.Checked ? double.NaN : 4.2);
series.Add(dt.AddHours(4), 3.2);
series.Add(dt.AddHours(5), 2.2);
series.Symbol = UILinePointSymbol.Square;
series.SymbolSize = 4;
series.SymbolLineWidth = 2;
series.SymbolColor = Color.Red;
series.ShowLine = !cbPoints.Checked;
series = option.AddSeries(new UILineSeries("Line2", Color.Lime));
series.Add(dt.AddHours(3), 3.3);
@ -49,6 +50,7 @@ namespace Sunny.UI.Demo
series.SymbolLineWidth = 2;
series.SymbolColor = Color.Red;
series.Smooth = true;
series.ShowLine = !cbPoints.Checked;
option.GreaterWarningArea = new UILineWarningArea(3.5);
option.LessWarningArea = new UILineWarningArea(2.2, Color.Gold);
@ -135,14 +137,7 @@ namespace Sunny.UI.Demo
private void uiCheckBox1_CheckedChanged(object sender, EventArgs e)
{
if (LineChart.Option == null) return;
foreach (var series in LineChart.Option.Series.Values)
{
series.ShowLine = !uiCheckBox1.Checked;
series.Symbol = uiCheckBox1.Checked ? UILinePointSymbol.Circle : UILinePointSymbol.None;
}
LineChart.Refresh();
uiSymbolButton1.PerformClick();
}
private void uiSymbolButton3_Click(object sender, EventArgs e)
@ -166,7 +161,6 @@ namespace Sunny.UI.Demo
series.SymbolSize = 4;
series.SymbolLineWidth = 2;
series.SymbolColor = Color.Red;
series.ContainsNan = true;
option.XAxis.Name = "日期";
option.YAxis.Name = "数值";
@ -177,5 +171,10 @@ namespace Sunny.UI.Demo
LineChart.SetOption(option);
}
private void uiCheckBox2_CheckedChanged(object sender, EventArgs e)
{
uiSymbolButton1.PerformClick();
}
}
}

View File

@ -54,10 +54,10 @@ namespace Sunny.UI.Demo
Header.SetNodeSymbol(Header.Nodes[2], 61950);
parent = Aside.CreateNode("图表", 61950, 24, pageIndex);
//直接关联默认自动生成GUID
Aside.CreateChildNode(parent, AddPage(new FPieChart()));
Aside.CreateChildNode(parent, AddPage(new FDoughnutChart()));
Aside.CreateChildNode(parent, AddPage(new FBarChart()));
Aside.CreateChildNode(parent, AddPage(new FDoughnutChart()));
Aside.CreateChildNode(parent, AddPage(new FLineChart()));
Aside.CreateChildNode(parent, AddPage(new FPieChart()));
pageIndex = 4000;
Header.SetNodePageIndex(Header.Nodes[3], pageIndex);

View File

@ -133,11 +133,6 @@ namespace Sunny.UI
Bars.Clear();
NeedDraw = false;
if (Option == null || Option.Series == null || Option.SeriesCount == 0) return;
DrawOrigin = new Point(Option.Grid.Left, Height - Option.Grid.Bottom);
DrawSize = new Size(Width - Option.Grid.Left - Option.Grid.Right,
Height - Option.Grid.Top - Option.Grid.Bottom);
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
if (Option.XAxis.Data.Count == 0) return;
@ -282,9 +277,11 @@ namespace Sunny.UI
}
}
protected Point DrawOrigin => new Point(Option.Grid.Left, Height - Option.Grid.Bottom);
protected Size DrawSize => new Size(Width - Option.Grid.Left - Option.Grid.Right, Height - Option.Grid.Top - Option.Grid.Bottom);
protected Rectangle DrawRect => new Rectangle(Option.Grid.Left, Option.Grid.Top, DrawSize.Width, DrawSize.Height);
protected int selectIndex = -1;
protected Point DrawOrigin;
protected Size DrawSize;
protected float DrawBarWidth;
protected int YAxisStart;
protected int YAxisEnd;

View File

@ -37,11 +37,6 @@ namespace Sunny.UI
Bars.Clear();
NeedDraw = false;
if (Option == null || Option.Series == null || Option.SeriesCount == 0) return;
DrawOrigin = new Point(Option.Grid.Left, Height - Option.Grid.Bottom);
DrawSize = new Size(Width - Option.Grid.Left - Option.Grid.Right,
Height - Option.Grid.Top - Option.Grid.Bottom);
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
if (Option.Series.Count == 0) return;

View File

@ -46,30 +46,25 @@ namespace Sunny.UI
CalcData();
}
protected Point DrawOrigin;
protected Size DrawSize;
private Rectangle DrawRect;
[Browsable(false)]
public Point DrawOrigin => new Point(Option.Grid.Left, Height - Option.Grid.Bottom);
[Browsable(false)]
public Size DrawSize => new Size(Width - Option.Grid.Left - Option.Grid.Right, Height - Option.Grid.Top - Option.Grid.Bottom);
[Browsable(false)]
public Rectangle DrawRect => new Rectangle(Option.Grid.Left, Option.Grid.Top, DrawSize.Width, DrawSize.Height);
protected override void CalcData()
{
NeedDraw = false;
if (Option?.Series == null || Option.Series.Count == 0) return;
DrawOrigin = new Point(Option.Grid.Left, Height - Option.Grid.Bottom);
DrawSize = new Size(Width - Option.Grid.Left - Option.Grid.Right,
Height - Option.Grid.Top - Option.Grid.Bottom);
DrawRect = new Rectangle(Option.Grid.Left, Option.Grid.Top, DrawSize.Width, DrawSize.Height);
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
CalcAxises();
foreach (var series in Option.Series.Values)
{
series.ClearPoints();
float[] x = XScale.CalcXPixels(series.XData.ToArray(), DrawOrigin.X, DrawSize.Width);
float[] y = YScale.CalcYPixels(series.YData.ToArray(), DrawOrigin.Y, DrawSize.Height);
series.AddPoints(x, y);
series.CalcData(this, XScale, YScale);
}
NeedDraw = true;
@ -199,6 +194,7 @@ namespace Sunny.UI
DrawLegend(g, Option.Legend);
DrawAxis(g);
DrawAxisScales(g);
DrawPointSymbols(g);
DrawOther(g);
}
@ -396,18 +392,14 @@ namespace Sunny.UI
if (Option.GreaterWarningArea != null)
{
using (Graphics graphics = bmpGreater.Graphics())
{
DrawSeries(graphics, Option.GreaterWarningArea.Color, series);
}
using Graphics graphics = bmpGreater.Graphics();
DrawSeries(graphics, Option.GreaterWarningArea.Color, series);
}
if (Option.LessWarningArea != null)
{
using (Graphics graphics = bmpLess.Graphics())
{
DrawSeries(graphics, Option.LessWarningArea.Color, series);
}
using Graphics graphics = bmpLess.Graphics();
DrawSeries(graphics, Option.LessWarningArea.Color, series);
}
idx++;
@ -449,7 +441,12 @@ namespace Sunny.UI
g.DrawImage(bmp, new Rectangle((int)wLeft, (int)wTop, (int)(wRight - wLeft), (int)(wBottom - wTop)),
new Rectangle((int)wLeft, (int)wTop, (int)(wRight - wLeft), (int)(wBottom - wTop)), GraphicsUnit.Pixel);
idx = 0;
}
private void DrawPointSymbols(Graphics g)
{
int idx = 0;
foreach (var series in Option.Series.Values)
{
Color color = series.Color;
@ -462,8 +459,8 @@ namespace Sunny.UI
{
foreach (var p in series.Points)
{
if (p.X <= Option.Grid.Left || p.X >= Width - Option.Grid.Right) continue;
if (p.Y <= Option.Grid.Top || p.Y >= Height - Option.Grid.Bottom) continue;
if (p.X < Option.Grid.Left || p.X > Width - Option.Grid.Right) continue;
if (p.Y < Option.Grid.Top || p.Y > Height - Option.Grid.Bottom) continue;
if (double.IsNaN(p.X) || double.IsNaN(p.Y)) continue;
switch (series.Symbol)
@ -538,7 +535,7 @@ namespace Sunny.UI
using (Pen pn = new Pen(line.Color, line.Size))
{
g.DrawLine(pn, DrawOrigin.X, pos, Width - Option.Grid.Right, pos);
g.DrawLine(pn, DrawOrigin.X + 1, pos, Width - Option.Grid.Right - 1, pos);
}
SizeF sf = g.MeasureString(line.Name, SubFont);
@ -559,7 +556,7 @@ namespace Sunny.UI
using (Pen pn = new Pen(line.Color, line.Size))
{
g.DrawLine(pn, pos, DrawOrigin.Y, pos, Option.Grid.Top);
g.DrawLine(pn, pos, DrawOrigin.Y - 1, pos, Option.Grid.Top + 1);
}
SizeF sf = g.MeasureString(line.Name, SubFont);

View File

@ -288,7 +288,7 @@ namespace Sunny.UI
public bool ShowLine { get; set; } = true;
public bool ContainsNan { get; set; }
public bool ContainsNan { get; private set; }
public UILineSeries(string name)
{
@ -354,12 +354,13 @@ namespace Sunny.UI
public void Clear()
{
ContainsNan = false;
XData.Clear();
YData.Clear();
ClearPoints();
}
public void ClearPoints()
private void ClearPoints()
{
Points.Clear();
PointsX.Clear();
@ -383,10 +384,19 @@ namespace Sunny.UI
}
}
public void CalcData(UILineChart chart, UIScale XScale, UIScale YScale)
{
ClearPoints();
float[] x = XScale.CalcXPixels(XData.ToArray(), chart.DrawOrigin.X, chart.DrawSize.Width);
float[] y = YScale.CalcYPixels(YData.ToArray(), chart.DrawOrigin.Y, chart.DrawSize.Height);
AddPoints(x, y);
}
public void Add(double x, double y)
{
XData.Add(x);
if (double.IsInfinity(y)) y = double.NaN;
if (y.IsInfinity()) y = double.NaN;
if (y.IsNan()) ContainsNan = true;
YData.Add(y);
}
@ -394,7 +404,8 @@ namespace Sunny.UI
{
DateTimeInt64 t = new DateTimeInt64(x);
XData.Add(t);
if (double.IsInfinity(y)) y = double.NaN;
if (y.IsInfinity()) y = double.NaN;
if (y.IsNan()) ContainsNan = true;
YData.Add(y);
}
@ -402,7 +413,8 @@ namespace Sunny.UI
{
int cnt = XData.Count;
XData.Add(cnt);
if (double.IsInfinity(y)) y = double.NaN;
if (y.IsInfinity()) y = double.NaN;
if (y.IsNan()) ContainsNan = true;
YData.Add(y);
}
}