* UILineChart: 增加了Y轴数据由上向下绘制
This commit is contained in:
parent
069ed8c606
commit
bc9e2effe5
@ -48,6 +48,7 @@
|
|||||||
* 2023-07-02: V3.3.9 增加PointFormat,鼠标选中值显示格式化事件
|
* 2023-07-02: V3.3.9 增加PointFormat,鼠标选中值显示格式化事件
|
||||||
* 2023-07-02: V3.3.9 增加了数据沿Y轴变化时鼠标移动到数据点时显示数据点标签
|
* 2023-07-02: V3.3.9 增加了数据沿Y轴变化时鼠标移动到数据点时显示数据点标签
|
||||||
* 2023-07-14: V3.4.0 增加了坐标轴绘制时显示箭头,并在箭头处显示数量单位的功能
|
* 2023-07-14: V3.4.0 增加了坐标轴绘制时显示箭头,并在箭头处显示数量单位的功能
|
||||||
|
* 2023-10-04: V3.5.0 增加了Y轴数据由上向下绘制
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@ -77,7 +78,7 @@ namespace Sunny.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public Point DrawOrigin => new Point(Option.Grid.Left, Height - Option.Grid.Bottom);
|
public Point DrawOrigin => new Point(Option.Grid.Left, Option.YDataOrder == UIYDataOrder.Asc ? Height - Option.Grid.Bottom : Option.Grid.Top);
|
||||||
|
|
||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public Size DrawSize => new Size(Width - Option.Grid.Left - Option.Grid.Right, Height - Option.Grid.Top - Option.Grid.Bottom);
|
public Size DrawSize => new Size(Width - Option.Grid.Left - Option.Grid.Right, Height - Option.Grid.Top - Option.Grid.Bottom);
|
||||||
@ -98,15 +99,15 @@ namespace Sunny.UI
|
|||||||
foreach (var series in Option.Series.Values)
|
foreach (var series in Option.Series.Values)
|
||||||
{
|
{
|
||||||
if (series.IsY2)
|
if (series.IsY2)
|
||||||
series.CalcData(this, XScale, Y2Scale);
|
series.CalcData(this, XScale, Y2Scale, Option.YDataOrder);
|
||||||
else
|
else
|
||||||
series.CalcData(this, XScale, YScale);
|
series.CalcData(this, XScale, YScale, Option.YDataOrder);
|
||||||
|
|
||||||
if (series is UISwitchLineSeries lineSeries)
|
if (series is UISwitchLineSeries lineSeries)
|
||||||
{
|
{
|
||||||
lineSeries.YOffsetPos = series.IsY2 ?
|
lineSeries.YOffsetPos = series.IsY2 ?
|
||||||
Y2Scale.CalcYPixel(lineSeries.YOffset, DrawOrigin.Y, DrawSize.Height) :
|
Y2Scale.CalcYPixel(lineSeries.YOffset, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder) :
|
||||||
YScale.CalcYPixel(lineSeries.YOffset, DrawOrigin.Y, DrawSize.Height);
|
YScale.CalcYPixel(lineSeries.YOffset, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +299,7 @@ namespace Sunny.UI
|
|||||||
g.DrawLine(ForeColor, Option.Grid.Left, Height - Option.Grid.Bottom, Width - Option.Grid.Right, Height - Option.Grid.Bottom);
|
g.DrawLine(ForeColor, Option.Grid.Left, Height - Option.Grid.Bottom, Width - Option.Grid.Right, Height - Option.Grid.Bottom);
|
||||||
|
|
||||||
using var TempFont = Font.DPIScaleFont(UIStyles.DefaultSubFontSize);
|
using var TempFont = Font.DPIScaleFont(UIStyles.DefaultSubFontSize);
|
||||||
float zeroPos = YScale.CalcYPixel(0, DrawOrigin.Y, DrawSize.Height);
|
float zeroPos = YScale.CalcYPixel(0, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
if (zeroPos > Option.Grid.Top && zeroPos < Height - Option.Grid.Bottom)
|
if (zeroPos > Option.Grid.Top && zeroPos < Height - Option.Grid.Bottom)
|
||||||
{
|
{
|
||||||
if (Option.ShowZeroLine)
|
if (Option.ShowZeroLine)
|
||||||
@ -395,13 +396,19 @@ namespace Sunny.UI
|
|||||||
if (xx > xr && xx + sf.Width < Width)
|
if (xx > xr && xx + sf.Width < Width)
|
||||||
{
|
{
|
||||||
xr = xx + sf.Width;
|
xr = xx + sf.Width;
|
||||||
g.DrawString(label, TempFont, ForeColor, new Rectangle((int)x - Width, DrawOrigin.Y + Option.XAxis.AxisTick.Length, Width * 2, Height), ContentAlignment.TopCenter);
|
if (Option.YDataOrder == UIYDataOrder.Asc)
|
||||||
|
g.DrawString(label, TempFont, ForeColor, new Rectangle((int)x - Width, DrawOrigin.Y + Option.XAxis.AxisTick.Length, Width * 2, Height), ContentAlignment.TopCenter);
|
||||||
|
else
|
||||||
|
g.DrawString(label, TempFont, ForeColor, new Rectangle((int)x - Width, 0, Width * 2, (int)(DrawOrigin.Y - Option.XAxis.AxisTick.Length)), ContentAlignment.BottomCenter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Option.XAxis.AxisTick.Show)
|
if (Option.XAxis.AxisTick.Show)
|
||||||
{
|
{
|
||||||
g.DrawLine(ForeColor, x, DrawOrigin.Y, x, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
if (Option.YDataOrder == UIYDataOrder.Asc)
|
||||||
|
g.DrawLine(ForeColor, x, DrawOrigin.Y, x, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
||||||
|
else
|
||||||
|
g.DrawLine(ForeColor, x, DrawOrigin.Y, x, DrawOrigin.Y - Option.XAxis.AxisTick.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x.Equals(DrawOrigin.X)) continue;
|
if (x.Equals(DrawOrigin.X)) continue;
|
||||||
@ -424,7 +431,7 @@ namespace Sunny.UI
|
|||||||
//Y Tick
|
//Y Tick
|
||||||
{
|
{
|
||||||
double[] YLabels = Option.YAxis.HaveCustomLabels ? Option.YAxis.CustomLabels.LabelValues() : YScale.CalcLabels();
|
double[] YLabels = Option.YAxis.HaveCustomLabels ? Option.YAxis.CustomLabels.LabelValues() : YScale.CalcLabels();
|
||||||
float[] labels = YScale.CalcYPixels(YLabels, DrawOrigin.Y, DrawSize.Height);
|
float[] labels = YScale.CalcYPixels(YLabels, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
float widthMax = 0;
|
float widthMax = 0;
|
||||||
for (int i = 0; i < labels.Length; i++)
|
for (int i = 0; i < labels.Length; i++)
|
||||||
{
|
{
|
||||||
@ -474,7 +481,7 @@ namespace Sunny.UI
|
|||||||
if (Option.HaveY2)
|
if (Option.HaveY2)
|
||||||
{
|
{
|
||||||
double[] Y2Labels = Option.Y2Axis.HaveCustomLabels ? Option.Y2Axis.CustomLabels.LabelValues() : Y2Scale.CalcLabels();
|
double[] Y2Labels = Option.Y2Axis.HaveCustomLabels ? Option.Y2Axis.CustomLabels.LabelValues() : Y2Scale.CalcLabels();
|
||||||
float[] labels = Y2Scale.CalcYPixels(Y2Labels, DrawOrigin.Y, DrawSize.Height);
|
float[] labels = Y2Scale.CalcYPixels(Y2Labels, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
float widthMax = 0;
|
float widthMax = 0;
|
||||||
for (int i = 0; i < labels.Length; i++)
|
for (int i = 0; i < labels.Length; i++)
|
||||||
{
|
{
|
||||||
@ -644,7 +651,7 @@ namespace Sunny.UI
|
|||||||
|
|
||||||
if (Option.GreaterWarningArea != null)
|
if (Option.GreaterWarningArea != null)
|
||||||
{
|
{
|
||||||
wTop = YScale.CalcYPixel(Option.GreaterWarningArea.Value, DrawOrigin.Y, DrawSize.Height);
|
wTop = YScale.CalcYPixel(Option.GreaterWarningArea.Value, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
if (wTop < Option.Grid.Top)
|
if (wTop < Option.Grid.Top)
|
||||||
{
|
{
|
||||||
wTop = Option.Grid.Top;
|
wTop = Option.Grid.Top;
|
||||||
@ -660,7 +667,7 @@ namespace Sunny.UI
|
|||||||
|
|
||||||
if (Option.LessWarningArea != null)
|
if (Option.LessWarningArea != null)
|
||||||
{
|
{
|
||||||
wBottom = YScale.CalcYPixel(Option.LessWarningArea.Value, DrawOrigin.Y, DrawSize.Height);
|
wBottom = YScale.CalcYPixel(Option.LessWarningArea.Value, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
if (wBottom > Height - Option.Grid.Bottom)
|
if (wBottom > Height - Option.Grid.Bottom)
|
||||||
{
|
{
|
||||||
wBottom = Height - Option.Grid.Bottom;
|
wBottom = Height - Option.Grid.Bottom;
|
||||||
@ -770,7 +777,7 @@ namespace Sunny.UI
|
|||||||
{
|
{
|
||||||
foreach (var line in Option.YAxisScaleLines)
|
foreach (var line in Option.YAxisScaleLines)
|
||||||
{
|
{
|
||||||
float pos = YScale.CalcYPixel(line.Value, DrawOrigin.Y, DrawSize.Height);
|
float pos = YScale.CalcYPixel(line.Value, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
|
|
||||||
|
|
||||||
if (pos <= Option.Grid.Top || pos >= Height - Option.Grid.Bottom) continue;
|
if (pos <= Option.Grid.Top || pos >= Height - Option.Grid.Bottom) continue;
|
||||||
@ -794,7 +801,7 @@ namespace Sunny.UI
|
|||||||
{
|
{
|
||||||
foreach (var line in Option.Y2AxisScaleLines)
|
foreach (var line in Option.Y2AxisScaleLines)
|
||||||
{
|
{
|
||||||
float pos = Y2Scale.CalcYPixel(line.Value, DrawOrigin.Y, DrawSize.Height);
|
float pos = Y2Scale.CalcYPixel(line.Value, DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
if (pos <= Option.Grid.Top || pos >= Height - Option.Grid.Bottom) continue;
|
if (pos <= Option.Grid.Top || pos >= Height - Option.Grid.Bottom) continue;
|
||||||
|
|
||||||
using (Pen pn = new Pen(line.Color, line.Size))
|
using (Pen pn = new Pen(line.Color, line.Size))
|
||||||
@ -1085,13 +1092,18 @@ namespace Sunny.UI
|
|||||||
var zoomArea = new ZoomArea();
|
var zoomArea = new ZoomArea();
|
||||||
zoomArea.XMin = XScale.CalcXPos(Math.Min(StartPoint.X, StopPoint.X), DrawOrigin.X, DrawSize.Width);
|
zoomArea.XMin = XScale.CalcXPos(Math.Min(StartPoint.X, StopPoint.X), DrawOrigin.X, DrawSize.Width);
|
||||||
zoomArea.XMax = XScale.CalcXPos(Math.Max(StartPoint.X, StopPoint.X), DrawOrigin.X, DrawSize.Width);
|
zoomArea.XMax = XScale.CalcXPos(Math.Max(StartPoint.X, StopPoint.X), DrawOrigin.X, DrawSize.Width);
|
||||||
zoomArea.YMax = YScale.CalcYPos(Math.Min(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height);
|
|
||||||
zoomArea.YMin = YScale.CalcYPos(Math.Max(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height);
|
double y1 = YScale.CalcYPos(Math.Min(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
|
double y2 = YScale.CalcYPos(Math.Max(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
|
zoomArea.YMax = Math.Max(y1, y2);
|
||||||
|
zoomArea.YMin = Math.Min(y1, y2);
|
||||||
|
|
||||||
if (Option.HaveY2)
|
if (Option.HaveY2)
|
||||||
{
|
{
|
||||||
zoomArea.Y2Max = Y2Scale.CalcYPos(Math.Min(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height);
|
y1 = Y2Scale.CalcYPos(Math.Min(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
zoomArea.Y2Min = Y2Scale.CalcYPos(Math.Max(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height);
|
y2 = Y2Scale.CalcYPos(Math.Max(StartPoint.Y, StopPoint.Y), DrawOrigin.Y, DrawSize.Height, Option.YDataOrder);
|
||||||
|
zoomArea.Y2Max = Math.Max(y1, y2);
|
||||||
|
zoomArea.Y2Min = Math.Min(y1, y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddZoomArea(zoomArea);
|
AddZoomArea(zoomArea);
|
||||||
|
@ -38,6 +38,12 @@ namespace Sunny.UI
|
|||||||
Y
|
Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum UIYDataOrder
|
||||||
|
{
|
||||||
|
Asc,
|
||||||
|
Desc
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class UILineOption : UIOption, IDisposable
|
public sealed class UILineOption : UIOption, IDisposable
|
||||||
{
|
{
|
||||||
public bool ShowZeroLine { get; set; } = true;
|
public bool ShowZeroLine { get; set; } = true;
|
||||||
@ -52,6 +58,8 @@ namespace Sunny.UI
|
|||||||
|
|
||||||
public UILineToolTip ToolTip { get; private set; } = new UILineToolTip();
|
public UILineToolTip ToolTip { get; private set; } = new UILineToolTip();
|
||||||
|
|
||||||
|
public UIYDataOrder YDataOrder { get; set; } = UIYDataOrder.Asc;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 析构函数
|
/// 析构函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -663,11 +671,11 @@ namespace Sunny.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void CalcData(UILineChart chart, UIScale XScale, UIScale YScale)
|
internal void CalcData(UILineChart chart, UIScale XScale, UIScale YScale, UIYDataOrder order = UIYDataOrder.Asc)
|
||||||
{
|
{
|
||||||
ClearPoints();
|
ClearPoints();
|
||||||
float[] x = XScale.CalcXPixels(XData.ToArray(), chart.DrawOrigin.X, chart.DrawSize.Width);
|
float[] x = XScale.CalcXPixels(XData.ToArray(), chart.DrawOrigin.X, chart.DrawSize.Width);
|
||||||
float[] y = YScale.CalcYPixels(YData.ToArray(), chart.DrawOrigin.Y, chart.DrawSize.Height);
|
float[] y = YScale.CalcYPixels(YData.ToArray(), chart.DrawOrigin.Y, chart.DrawSize.Height, order);
|
||||||
AddPoints(x, y);
|
AddPoints(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +56,20 @@ namespace Sunny.UI
|
|||||||
return (float)(_min + (value - origin) * (_max - _min) * 1.0f / width);
|
return (float)(_min + (value - origin) * (_max - _min) * 1.0f / width);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float CalcYPixel(double value, int origin, int height)
|
public float CalcYPixel(double value, int origin, int height, UIYDataOrder order = UIYDataOrder.Asc)
|
||||||
{
|
{
|
||||||
return origin - (float)((value - _min) * 1.0f * height / (_max - _min));
|
if (order == UIYDataOrder.Asc)
|
||||||
|
return origin - (float)((value - _min) * 1.0f * height / (_max - _min));
|
||||||
|
else
|
||||||
|
return origin + (float)((value - _min) * 1.0f * height / (_max - _min));
|
||||||
}
|
}
|
||||||
|
|
||||||
public double CalcYPos(double value, int origin, int height)
|
public double CalcYPos(double value, int origin, int height, UIYDataOrder order)
|
||||||
{
|
{
|
||||||
return (float)(_min + (origin - value) * (_max - _min) * 1.0f / height);
|
if (order == UIYDataOrder.Asc)
|
||||||
|
return (float)(_min + (origin - value) * (_max - _min) * 1.0f / height);
|
||||||
|
else
|
||||||
|
return (float)(_min + (value - origin) * (_max - _min) * 1.0f / height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[] CalcXPixels(double[] labels, int origin, int width)
|
public float[] CalcXPixels(double[] labels, int origin, int width)
|
||||||
@ -81,7 +87,7 @@ namespace Sunny.UI
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[] CalcYPixels(double[] labels, int origin, int height)
|
public float[] CalcYPixels(double[] labels, int origin, int height, UIYDataOrder order = UIYDataOrder.Asc)
|
||||||
{
|
{
|
||||||
if (labels == null) return null;
|
if (labels == null) return null;
|
||||||
float[] result = new float[labels.Length];
|
float[] result = new float[labels.Length];
|
||||||
@ -90,7 +96,7 @@ namespace Sunny.UI
|
|||||||
if (labels[i].IsInfinity() || labels[i].IsNan())
|
if (labels[i].IsInfinity() || labels[i].IsNan())
|
||||||
result[i] = float.NaN;
|
result[i] = float.NaN;
|
||||||
else
|
else
|
||||||
result[i] = CalcYPixel(labels[i], origin, height);
|
result[i] = CalcYPixel(labels[i], origin, height, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user