* UIBarChart: 重写Y轴坐标显示
This commit is contained in:
parent
cf2c4acd01
commit
5603bc88fe
Binary file not shown.
@ -21,6 +21,7 @@
|
|||||||
* 2021-07-22: V3.0.5 增加更新数据的方法
|
* 2021-07-22: V3.0.5 增加更新数据的方法
|
||||||
* 2021-01-01: V3.0.9 增加柱子上显示数值
|
* 2021-01-01: V3.0.9 增加柱子上显示数值
|
||||||
* 2022-03-08: V3.1.1 增加X轴文字倾斜
|
* 2022-03-08: V3.1.1 增加X轴文字倾斜
|
||||||
|
* 2022-05-27: V3.1.9 重写Y轴坐标显示
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@ -65,70 +66,7 @@ namespace Sunny.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
UILinearScale YScale = new UILinearScale();
|
||||||
/// 计算刻度
|
|
||||||
/// 起始值必须小于结束值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">起始值</param>
|
|
||||||
/// <param name="end">结束值</param>
|
|
||||||
/// <param name="expect_num">期望刻度数量,实际数接近此数</param>
|
|
||||||
/// <param name="degree_start">刻度起始值,须乘以间隔使用</param>
|
|
||||||
/// <param name="degree_end">刻度结束值,须乘以间隔使用</param>
|
|
||||||
/// <param name="degree_gap">刻度间隔</param>
|
|
||||||
public void CalcDegreeScale(double start, double end, int expect_num,
|
|
||||||
out int degree_start, out int degree_end, out double degree_gap, out int decimalCount)
|
|
||||||
{
|
|
||||||
if (start >= end)
|
|
||||||
{
|
|
||||||
throw new Exception("起始值必须小于结束值");
|
|
||||||
}
|
|
||||||
|
|
||||||
double differ = end - start;
|
|
||||||
double differ_gap = differ / (expect_num - 1); //35, 4.6, 0.27
|
|
||||||
|
|
||||||
double exponent = Math.Log10(differ_gap) - 1; //0.54, -0.34, -1.57
|
|
||||||
int _exponent = (int)exponent; //0, 0=>-1, -1=>-2
|
|
||||||
if (exponent < 0 && Math.Abs(exponent) > 1e-8)
|
|
||||||
{
|
|
||||||
_exponent--;
|
|
||||||
}
|
|
||||||
|
|
||||||
int step = (int)(differ_gap / Math.Pow(10, _exponent)); //35, 46, 27
|
|
||||||
int[] fix_steps = new int[] { 10, 20, 25, 50, 100 };
|
|
||||||
int fix_step = 10; //25, 50, 25
|
|
||||||
for (int i = fix_steps.Length - 1; i >= 1; i--)
|
|
||||||
{
|
|
||||||
if (step > (fix_steps[i] + fix_steps[i - 1]) / 2)
|
|
||||||
{
|
|
||||||
fix_step = fix_steps[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
degree_gap = fix_step * Math.Pow(10, _exponent); //25, 5, 0.25
|
|
||||||
|
|
||||||
double start1 = start / degree_gap;
|
|
||||||
int start2 = (int)start1;
|
|
||||||
if (start1 < 0 && Math.Abs(start1 - start2) > 1e-8)
|
|
||||||
{
|
|
||||||
start2--;
|
|
||||||
}
|
|
||||||
|
|
||||||
degree_start = start2;
|
|
||||||
|
|
||||||
double end1 = end / degree_gap;
|
|
||||||
int end2 = (int)end1;
|
|
||||||
if (end1 >= 0 && Math.Abs(end1 - end2) > 1e-8)
|
|
||||||
{
|
|
||||||
end2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
degree_end = end2;
|
|
||||||
_exponent = Math.Abs(_exponent);
|
|
||||||
if (fix_step.IsEven()) _exponent--;
|
|
||||||
if (_exponent < 0) _exponent = 0;
|
|
||||||
decimalCount = _exponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void CalcData()
|
protected override void CalcData()
|
||||||
{
|
{
|
||||||
@ -157,6 +95,28 @@ namespace Sunny.UI
|
|||||||
if (!Option.YAxis.MaxAuto) max = Option.YAxis.Max;
|
if (!Option.YAxis.MaxAuto) max = Option.YAxis.Max;
|
||||||
if (!Option.YAxis.MinAuto) min = Option.YAxis.Min;
|
if (!Option.YAxis.MinAuto) min = Option.YAxis.Min;
|
||||||
|
|
||||||
|
if (Option.YAxis.MaxAuto && Option.YAxis.MinAuto)
|
||||||
|
{
|
||||||
|
if (min > 0) min = 0;
|
||||||
|
if (max < 0) max = 0;
|
||||||
|
|
||||||
|
if (min.IsZero() && !max.IsZero())
|
||||||
|
{
|
||||||
|
max = max * 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max.IsZero() && !min.IsZero())
|
||||||
|
{
|
||||||
|
min = min * 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!max.IsZero() && !min.IsZero())
|
||||||
|
{
|
||||||
|
max = max * 1.2;
|
||||||
|
min = min * 1.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((max - min).IsZero())
|
if ((max - min).IsZero())
|
||||||
{
|
{
|
||||||
if (min.IsZero())
|
if (min.IsZero())
|
||||||
@ -176,13 +136,16 @@ namespace Sunny.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CalcDegreeScale(min, max, Option.YAxis.SplitNumber,
|
YScale.Max = max;
|
||||||
out int start, out int end, out double interval, out int decimalCount);
|
YScale.Min = min;
|
||||||
|
YScale.AxisChange();
|
||||||
|
|
||||||
YAxisStart = start;
|
YAxisStart = YScale.Min;
|
||||||
YAxisEnd = end;
|
YAxisEnd = YScale.Max;
|
||||||
YAxisInterval = interval;
|
YAxisInterval = YScale.Step;
|
||||||
YAxisDecimalCount = decimalCount;
|
double[] YLabels = YScale.CalcLabels();
|
||||||
|
float[] labels = YScale.CalcYPixels(YLabels, DrawOrigin.Y, DrawSize.Height);
|
||||||
|
YAxisDecimalCount = YScale.Format.Replace("F", "").ToInt();
|
||||||
|
|
||||||
float x1 = DrawBarWidth / (Option.SeriesCount * 2 + Option.SeriesCount + 1);
|
float x1 = DrawBarWidth / (Option.SeriesCount * 2 + Option.SeriesCount + 1);
|
||||||
float x2 = x1 * 2;
|
float x2 = x1 * 2;
|
||||||
@ -202,53 +165,14 @@ namespace Sunny.UI
|
|||||||
float ww = Math.Min(x2, series.MaxWidth);
|
float ww = Math.Min(x2, series.MaxWidth);
|
||||||
xx -= ww / 2.0f;
|
xx -= ww / 2.0f;
|
||||||
|
|
||||||
if (YAxisStart >= 0)
|
float YZeroPos = YScale.CalcYPixel(0, DrawOrigin.Y, DrawSize.Height);
|
||||||
{
|
float VPos = YScale.CalcYPixel(series.Data[j], DrawOrigin.Y, DrawSize.Height);
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (series.Data[j] - start * interval) / ((end - start) * interval)));
|
|
||||||
|
|
||||||
|
if (VPos <= YZeroPos)
|
||||||
|
{
|
||||||
Bars[i].Add(new BarInfo()
|
Bars[i].Add(new BarInfo()
|
||||||
{
|
{
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - h, ww, h),
|
Rect = new RectangleF(xx, VPos, ww, (YZeroPos - VPos)),
|
||||||
Value = series.Data[j],
|
|
||||||
Color = color,
|
|
||||||
Top = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (YAxisEnd <= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (end * interval - series.Data[j]) / ((end - start) * interval)));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, Option.Grid.Top + 1, ww, h - 1),
|
|
||||||
Value = series.Data[j],
|
|
||||||
Color = color,
|
|
||||||
Top = false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float lowH = 0;
|
|
||||||
float highH = 0;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
float lowV = 0;
|
|
||||||
float highV = 0;
|
|
||||||
for (int k = YAxisStart; k <= YAxisEnd; k++)
|
|
||||||
{
|
|
||||||
if (k < 0) lowH += DrawBarHeight;
|
|
||||||
if (k > 0) highH += DrawBarHeight;
|
|
||||||
if (k < 0) lowV += (float)YAxisInterval;
|
|
||||||
if (k > 0) highV += (float)YAxisInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lowH.ConsoleWriteLine();
|
|
||||||
// highH.ConsoleWriteLine();
|
|
||||||
|
|
||||||
if (series.Data[j] >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(highH * series.Data[j] / highV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH - h, ww, h),
|
|
||||||
Value = series.Data[j],
|
Value = series.Data[j],
|
||||||
Color = color,
|
Color = color,
|
||||||
Top = true
|
Top = true
|
||||||
@ -256,16 +180,14 @@ namespace Sunny.UI
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float h = Math.Abs((float)(lowH * series.Data[j] / lowV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
Bars[i].Add(new BarInfo()
|
||||||
{
|
{
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH + 1, ww, h - 1),
|
Rect = new RectangleF(xx, YZeroPos, ww, (VPos - YZeroPos)),
|
||||||
Value = series.Data[j],
|
Value = series.Data[j],
|
||||||
Color = color,
|
Color = color,
|
||||||
Top = false
|
Top = false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
barX += DrawBarWidth;
|
barX += DrawBarWidth;
|
||||||
}
|
}
|
||||||
@ -293,8 +215,8 @@ namespace Sunny.UI
|
|||||||
|
|
||||||
protected int selectIndex = -1;
|
protected int selectIndex = -1;
|
||||||
protected float DrawBarWidth;
|
protected float DrawBarWidth;
|
||||||
protected int YAxisStart;
|
protected double YAxisStart;
|
||||||
protected int YAxisEnd;
|
protected double YAxisEnd;
|
||||||
protected double YAxisInterval;
|
protected double YAxisInterval;
|
||||||
protected int YAxisDecimalCount;
|
protected int YAxisDecimalCount;
|
||||||
protected readonly ConcurrentDictionary<int, List<BarInfo>> Bars = new ConcurrentDictionary<int, List<BarInfo>>();
|
protected readonly ConcurrentDictionary<int, List<BarInfo>> Bars = new ConcurrentDictionary<int, List<BarInfo>>();
|
||||||
@ -367,11 +289,6 @@ namespace Sunny.UI
|
|||||||
UIOption option = BaseOption ?? EmptyOption;
|
UIOption option = BaseOption ?? EmptyOption;
|
||||||
return (UIBarOption)option;
|
return (UIBarOption)option;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set
|
|
||||||
// {
|
|
||||||
// SetOption(value);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateEmptyOption()
|
protected override void CreateEmptyOption()
|
||||||
@ -427,10 +344,12 @@ namespace Sunny.UI
|
|||||||
if (!NeedDraw) return;
|
if (!NeedDraw) return;
|
||||||
|
|
||||||
if (Option.ToolTip != null && Option.ToolTip.AxisPointer.Type == UIAxisPointerType.Shadow) DrawToolTip(g);
|
if (Option.ToolTip != null && Option.ToolTip.AxisPointer.Type == UIAxisPointerType.Shadow) DrawToolTip(g);
|
||||||
|
|
||||||
|
DrawSeries(g, Option.Series);
|
||||||
DrawAxis(g);
|
DrawAxis(g);
|
||||||
DrawTitle(g, Option.Title);
|
DrawTitle(g, Option.Title);
|
||||||
DrawSeries(g, Option.Series);
|
|
||||||
if (Option.ToolTip != null && Option.ToolTip.AxisPointer.Type == UIAxisPointerType.Line) DrawToolTip(g);
|
if (Option.ToolTip != null && Option.ToolTip.AxisPointer.Type == UIAxisPointerType.Line) DrawToolTip(g);
|
||||||
|
|
||||||
DrawLegend(g, Option.Legend);
|
DrawLegend(g, Option.Legend);
|
||||||
DrawAxisScales(g);
|
DrawAxisScales(g);
|
||||||
}
|
}
|
||||||
@ -453,47 +372,24 @@ namespace Sunny.UI
|
|||||||
|
|
||||||
protected virtual void DrawAxis(Graphics g)
|
protected virtual void DrawAxis(Graphics g)
|
||||||
{
|
{
|
||||||
|
g.FillRectangle(FillColor, Option.Grid.Left, 1, Width - Option.Grid.Left - Option.Grid.Right, Option.Grid.Top);
|
||||||
|
g.FillRectangle(FillColor, Option.Grid.Left, Height - Option.Grid.Bottom, Width - Option.Grid.Left - Option.Grid.Right, Option.Grid.Bottom - 1);
|
||||||
|
|
||||||
if (YAxisStart >= 0) g.DrawLine(ForeColor, DrawOrigin, new Point(DrawOrigin.X + DrawSize.Width, DrawOrigin.Y));
|
if (YAxisStart >= 0) g.DrawLine(ForeColor, DrawOrigin, new Point(DrawOrigin.X + DrawSize.Width, DrawOrigin.Y));
|
||||||
if (YAxisEnd <= 0) g.DrawLine(ForeColor, new Point(DrawOrigin.X, Option.Grid.Top), new Point(DrawOrigin.X + DrawSize.Width, Option.Grid.Top));
|
if (YAxisEnd <= 0) g.DrawLine(ForeColor, new Point(DrawOrigin.X, Option.Grid.Top), new Point(DrawOrigin.X + DrawSize.Width, Option.Grid.Top));
|
||||||
|
|
||||||
g.DrawLine(ForeColor, DrawOrigin, new Point(DrawOrigin.X, DrawOrigin.Y - DrawSize.Height));
|
g.DrawLine(ForeColor, DrawOrigin, new Point(DrawOrigin.X, DrawOrigin.Y - DrawSize.Height));
|
||||||
|
g.DrawLine(ForeColor, DrawOrigin, new Point(Width - Option.Grid.Right, DrawOrigin.Y));
|
||||||
|
|
||||||
if (Option.XAxis.AxisTick.Show)
|
if (Option.XAxis.AxisTick.Show)
|
||||||
{
|
{
|
||||||
float start;
|
float start = DrawOrigin.X + DrawBarWidth / 2.0f;
|
||||||
|
|
||||||
if (Option.XAxis.AxisTick.AlignWithLabel)
|
|
||||||
{
|
|
||||||
start = DrawOrigin.X + DrawBarWidth / 2.0f;
|
|
||||||
for (int i = 0; i < Option.XAxis.Data.Count; i++)
|
for (int i = 0; i < Option.XAxis.Data.Count; i++)
|
||||||
{
|
{
|
||||||
g.DrawLine(ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
g.DrawLine(ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
||||||
start += DrawBarWidth;
|
start += DrawBarWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
bool haveZero = false;
|
|
||||||
for (int i = YAxisStart; i <= YAxisEnd; i++)
|
|
||||||
{
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
haveZero = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!haveZero)
|
|
||||||
{
|
|
||||||
start = DrawOrigin.X;
|
|
||||||
for (int i = 0; i <= Option.XAxis.Data.Count; i++)
|
|
||||||
{
|
|
||||||
g.DrawLine(ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
|
||||||
start += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Option.XAxis.AxisLabel.Show)
|
if (Option.XAxis.AxisLabel.Show)
|
||||||
{
|
{
|
||||||
@ -503,7 +399,7 @@ namespace Sunny.UI
|
|||||||
SizeF sf = g.MeasureString(data, TempFont);
|
SizeF sf = g.MeasureString(data, TempFont);
|
||||||
int angle = (Option.XAxis.AxisLabel.Angle + 36000) % 360;
|
int angle = (Option.XAxis.AxisLabel.Angle + 36000) % 360;
|
||||||
if (angle > 0 && angle <= 90)
|
if (angle > 0 && angle <= 90)
|
||||||
g.DrawString(data, TempFont, ForeColor, new PointF(start, DrawOrigin.Y),
|
g.DrawString(data, TempFont, ForeColor, new PointF(start, DrawOrigin.Y + Option.XAxis.AxisTick.Length),
|
||||||
new StringFormat() { Alignment = StringAlignment.Far }, (3600 - Option.XAxis.AxisLabel.Angle) % 360);
|
new StringFormat() { Alignment = StringAlignment.Far }, (3600 - Option.XAxis.AxisLabel.Angle) % 360);
|
||||||
else
|
else
|
||||||
g.DrawString(data, TempFont, ForeColor, start - sf.Width / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length); start += DrawBarWidth;
|
g.DrawString(data, TempFont, ForeColor, start - sf.Width / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length); start += DrawBarWidth;
|
||||||
@ -513,63 +409,39 @@ namespace Sunny.UI
|
|||||||
g.DrawString(Option.XAxis.Name, TempFont, ForeColor, DrawOrigin.X + (DrawSize.Width - sfname.Width) / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length + sfname.Height);
|
g.DrawString(Option.XAxis.Name, TempFont, ForeColor, DrawOrigin.X + (DrawSize.Width - sfname.Width) / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length + sfname.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double[] YLabels = YScale.CalcLabels();
|
||||||
|
float[] labels = YScale.CalcYPixels(YLabels, DrawOrigin.Y, DrawSize.Height);
|
||||||
|
for (int i = 0; i < labels.Length; i++)
|
||||||
|
{
|
||||||
|
if (labels[i] > DrawOrigin.Y) continue;
|
||||||
|
if (labels[i] < Option.Grid.Top) continue;
|
||||||
if (Option.YAxis.AxisTick.Show)
|
if (Option.YAxis.AxisTick.Show)
|
||||||
{
|
{
|
||||||
float start = DrawOrigin.Y;
|
g.DrawLine(ForeColor, DrawOrigin.X, labels[i], DrawOrigin.X - Option.YAxis.AxisTick.Length, labels[i]);
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
if (!YLabels[i].EqualsDouble(0))
|
||||||
for (int i = YAxisStart; i <= YAxisEnd; i++)
|
|
||||||
{
|
|
||||||
g.DrawLine(ForeColor, DrawOrigin.X, start, DrawOrigin.X - Option.YAxis.AxisTick.Length, start);
|
|
||||||
|
|
||||||
if (i != 0)
|
|
||||||
{
|
{
|
||||||
using (Pen pn = new Pen(ForeColor))
|
using (Pen pn = new Pen(ForeColor))
|
||||||
{
|
{
|
||||||
pn.DashStyle = DashStyle.Dash;
|
pn.DashStyle = DashStyle.Dash;
|
||||||
pn.DashPattern = new float[] { 3, 3 };
|
pn.DashPattern = new float[] { 3, 3 };
|
||||||
g.DrawLine(pn, DrawOrigin.X, start, Width - Option.Grid.Right, start);
|
g.DrawLine(pn, DrawOrigin.X, labels[i], Width - Option.Grid.Right, labels[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g.DrawLine(ForeColor, DrawOrigin.X, start, Width - Option.Grid.Right, start);
|
g.DrawLine(ForeColor, DrawOrigin.X, labels[i], Width - Option.Grid.Right, labels[i]);
|
||||||
|
|
||||||
float lineStart = DrawOrigin.X;
|
|
||||||
for (int j = 0; j <= Option.XAxis.Data.Count; j++)
|
|
||||||
{
|
|
||||||
g.DrawLine(ForeColor, lineStart, start, lineStart, start + Option.XAxis.AxisTick.Length);
|
|
||||||
lineStart += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start -= DrawBarHeight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Option.YAxis.AxisLabel.Show)
|
if (Option.YAxis.AxisLabel.Show)
|
||||||
{
|
{
|
||||||
float start = DrawOrigin.Y;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
int idx = 0;
|
|
||||||
float wmax = 0;
|
|
||||||
|
|
||||||
if (Option.YAxis.AxisLabel.AutoFormat)
|
if (Option.YAxis.AxisLabel.AutoFormat)
|
||||||
Option.YAxis.AxisLabel.DecimalCount = YAxisDecimalCount;
|
Option.YAxis.AxisLabel.DecimalCount = YAxisDecimalCount;
|
||||||
|
|
||||||
for (int i = YAxisStart; i <= YAxisEnd; i++)
|
string label = YLabels[i].ToString("F" + Option.YAxis.AxisLabel.DecimalCount);
|
||||||
{
|
|
||||||
string label = Option.YAxis.AxisLabel.GetLabel(i * YAxisInterval, idx);
|
|
||||||
SizeF sf = g.MeasureString(label, TempFont);
|
SizeF sf = g.MeasureString(label, TempFont);
|
||||||
wmax = Math.Max(wmax, sf.Width);
|
g.DrawString(label, TempFont, ForeColor, DrawOrigin.X - Option.YAxis.AxisTick.Length - sf.Width, labels[i] - sf.Height / 2.0f);
|
||||||
g.DrawString(label, TempFont, ForeColor, DrawOrigin.X - Option.YAxis.AxisTick.Length - sf.Width, start - sf.Height / 2.0f);
|
|
||||||
start -= DrawBarHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SizeF sfname = g.MeasureString(Option.YAxis.Name, TempFont);
|
|
||||||
int x = (int)(DrawOrigin.X - Option.YAxis.AxisTick.Length - wmax - sfname.Height);
|
|
||||||
int y = (int)(Option.Grid.Top + (DrawSize.Height - sfname.Width) / 2);
|
|
||||||
g.DrawString(Option.YAxis.Name, TempFont, ForeColor, new Point(x, y),
|
|
||||||
new StringFormat() { Alignment = StringAlignment.Center }, 270);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,8 +451,7 @@ namespace Sunny.UI
|
|||||||
{
|
{
|
||||||
double ymin = YAxisStart * YAxisInterval;
|
double ymin = YAxisStart * YAxisInterval;
|
||||||
double ymax = YAxisEnd * YAxisInterval;
|
double ymax = YAxisEnd * YAxisInterval;
|
||||||
float pos = (float)((line.Value - ymin) * (Height - Option.Grid.Top - Option.Grid.Bottom) / (ymax - ymin));
|
float pos = YScale.CalcYPixel(line.Value, DrawOrigin.Y, DrawSize.Height);
|
||||||
pos = (Height - Option.Grid.Bottom - pos);
|
|
||||||
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))
|
||||||
{
|
{
|
||||||
@ -588,7 +459,6 @@ namespace Sunny.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
SizeF sf = g.MeasureString(line.Name, TempFont);
|
SizeF sf = g.MeasureString(line.Name, TempFont);
|
||||||
|
|
||||||
if (line.Left == UILeftAlignment.Left)
|
if (line.Left == UILeftAlignment.Left)
|
||||||
g.DrawString(line.Name, TempFont, line.Color, DrawOrigin.X + 4, pos - 2 - sf.Height);
|
g.DrawString(line.Name, TempFont, line.Color, DrawOrigin.X + 4, pos - 2 - sf.Height);
|
||||||
if (line.Left == UILeftAlignment.Center)
|
if (line.Left == UILeftAlignment.Center)
|
||||||
|
@ -1,819 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
|
|
||||||
* CopyRight (C) 2012-2022 ShenYongHua(沈永华).
|
|
||||||
* QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
|
|
||||||
*
|
|
||||||
* Blog: https://www.cnblogs.com/yhuse
|
|
||||||
* Gitee: https://gitee.com/yhuse/SunnyUI
|
|
||||||
* GitHub: https://github.com/yhuse/SunnyUI
|
|
||||||
*
|
|
||||||
* SunnyUI.dll can be used for free under the GPL-3.0 license.
|
|
||||||
* If you use this code, please keep this note.
|
|
||||||
* 如果您使用此代码,请保留此说明。
|
|
||||||
******************************************************************************
|
|
||||||
* 文件名称: UIBarChartEx.cs
|
|
||||||
* 文件说明: 柱状图
|
|
||||||
* 当前版本: V3.1
|
|
||||||
* 创建日期: 2020-09-26
|
|
||||||
*
|
|
||||||
* 2020-09-26: V2.2.8 增加文件说明
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace Sunny.UI
|
|
||||||
{
|
|
||||||
[ToolboxItem(false)]
|
|
||||||
public sealed class UIBarChartEx : UIBarChart
|
|
||||||
{
|
|
||||||
protected override void CalcData()
|
|
||||||
{
|
|
||||||
Bars.Clear();
|
|
||||||
NeedDraw = false;
|
|
||||||
if (Option == null || Option.Series == null || Option.SeriesCount == 0) return;
|
|
||||||
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
|
|
||||||
if (Option.Series.Count == 0) return;
|
|
||||||
|
|
||||||
NeedDraw = true;
|
|
||||||
DrawBarWidth = DrawSize.Width * 1.0f / Option.Series.Count;
|
|
||||||
|
|
||||||
double min = double.MaxValue;
|
|
||||||
double max = double.MinValue;
|
|
||||||
foreach (var series in Option.Series)
|
|
||||||
{
|
|
||||||
min = Math.Min(min, series.Data.Min());
|
|
||||||
max = Math.Max(max, series.Data.Max());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min > 0 && max > 0 && !Option.YAxis.Scale)
|
|
||||||
{
|
|
||||||
min = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min < 0 && max < 0 && !Option.YAxis.Scale)
|
|
||||||
{
|
|
||||||
max = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Option.YAxis.MaxAuto) max = Option.YAxis.Max;
|
|
||||||
if (!Option.YAxis.MinAuto) min = Option.YAxis.Min;
|
|
||||||
|
|
||||||
if ((max - min).IsZero())
|
|
||||||
{
|
|
||||||
if (min.IsZero())
|
|
||||||
{
|
|
||||||
max = 100;
|
|
||||||
min = 0;
|
|
||||||
}
|
|
||||||
else if (max > 0)
|
|
||||||
{
|
|
||||||
max = max * 2;
|
|
||||||
min = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
max = 0;
|
|
||||||
min = min * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CalcDegreeScale(min, max, Option.YAxis.SplitNumber,
|
|
||||||
out int start, out int end, out double interval, out int decimalCount);
|
|
||||||
|
|
||||||
YAxisStart = start;
|
|
||||||
YAxisEnd = end;
|
|
||||||
YAxisInterval = interval;
|
|
||||||
YAxisDecimalCount = decimalCount;
|
|
||||||
float barX = DrawOrigin.X;
|
|
||||||
|
|
||||||
if (Option.AutoSizeBars)
|
|
||||||
{
|
|
||||||
//每个柱子等宽
|
|
||||||
float x1 = DrawSize.Width * 1.0f / DataCount / 4;
|
|
||||||
float x2 = x1 * 2;
|
|
||||||
|
|
||||||
if (Option.AutoSizeBarsCompact)
|
|
||||||
{
|
|
||||||
//紧凑
|
|
||||||
for (int i = 0; i < Option.SeriesCount; i++)
|
|
||||||
{
|
|
||||||
var series = Option.Series[i];
|
|
||||||
Bars.TryAdd(i, new List<BarInfo>());
|
|
||||||
float sx = barX + x1 * ((series.Data.Count * 4 - (series.Data.Count * 2 + (series.Data.Count - 1) * Option.AutoSizeBarsCompactValue)) / 2.0f) + x1;
|
|
||||||
|
|
||||||
for (int j = 0; j < series.Data.Count; j++)
|
|
||||||
{
|
|
||||||
Color color = ChartStyle.GetColor(i);
|
|
||||||
if (series.Colors.Count > 0 && j >= 0 && j < series.Colors.Count)
|
|
||||||
color = series.Colors[j];
|
|
||||||
|
|
||||||
float ww = Math.Min(x2, series.MaxWidth);
|
|
||||||
float xx = sx - ww / 2.0f;
|
|
||||||
|
|
||||||
if (YAxisStart >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (series.Data[j] - start * interval) / ((end - start) * interval)));
|
|
||||||
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (YAxisEnd <= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (end * interval - series.Data[j]) / ((end - start) * interval)));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, Option.Grid.Top + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float lowH = 0;
|
|
||||||
float highH = 0;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
float lowV = 0;
|
|
||||||
float highV = 0;
|
|
||||||
for (int k = YAxisStart; k <= YAxisEnd; k++)
|
|
||||||
{
|
|
||||||
if (k < 0) lowH += DrawBarHeight;
|
|
||||||
if (k > 0) highH += DrawBarHeight;
|
|
||||||
if (k < 0) lowV += (float)YAxisInterval;
|
|
||||||
if (k > 0) highV += (float)YAxisInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.Data[j] >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(highH * series.Data[j] / highV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(lowH * series.Data[j] / lowV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sx += x2 + x1 * Option.AutoSizeBarsCompactValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
barX += x2 * 2 * series.Data.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//宽松
|
|
||||||
for (int i = 0; i < Option.SeriesCount; i++)
|
|
||||||
{
|
|
||||||
var series = Option.Series[i];
|
|
||||||
Bars.TryAdd(i, new List<BarInfo>());
|
|
||||||
|
|
||||||
for (int j = 0; j < series.Data.Count; j++)
|
|
||||||
{
|
|
||||||
Color color = ChartStyle.GetColor(i);
|
|
||||||
if (series.Colors.Count > 0 && j >= 0 && j < series.Colors.Count)
|
|
||||||
color = series.Colors[j];
|
|
||||||
|
|
||||||
float xx = barX + DrawSize.Width * 1.0f / DataCount / 2;
|
|
||||||
float ww = Math.Min(x2, series.MaxWidth);
|
|
||||||
xx -= ww / 2.0f;
|
|
||||||
|
|
||||||
if (YAxisStart >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (series.Data[j] - start * interval) / ((end - start) * interval)));
|
|
||||||
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (YAxisEnd <= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (end * interval - series.Data[j]) / ((end - start) * interval)));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, Option.Grid.Top + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float lowH = 0;
|
|
||||||
float highH = 0;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
float lowV = 0;
|
|
||||||
float highV = 0;
|
|
||||||
for (int k = YAxisStart; k <= YAxisEnd; k++)
|
|
||||||
{
|
|
||||||
if (k < 0) lowH += DrawBarHeight;
|
|
||||||
if (k > 0) highH += DrawBarHeight;
|
|
||||||
if (k < 0) lowV += (float)YAxisInterval;
|
|
||||||
if (k > 0) highV += (float)YAxisInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.Data[j] >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(highH * series.Data[j] / highV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(lowH * series.Data[j] / lowV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
barX += DrawSize.Width * 1.0f / DataCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//每个序列等宽
|
|
||||||
if (Option.AutoSizeBarsCompact)
|
|
||||||
{
|
|
||||||
//紧凑
|
|
||||||
|
|
||||||
float CompactWidth = DrawBarWidth / 4.0f * Option.AutoSizeBarsCompactValue;
|
|
||||||
|
|
||||||
for (int i = 0; i < Option.SeriesCount; i++)
|
|
||||||
{
|
|
||||||
var series = Option.Series[i];
|
|
||||||
float x1 = DrawBarWidth / series.Data.Count / 4.0f;
|
|
||||||
float x2 = x1 * 2;
|
|
||||||
float ww = Math.Min(x2, series.MaxWidth);
|
|
||||||
|
|
||||||
float sx = barX + (DrawBarWidth - ww * series.Data.Count - (series.Data.Count - 1) * CompactWidth) / 2.0f;
|
|
||||||
|
|
||||||
Bars.TryAdd(i, new List<BarInfo>());
|
|
||||||
for (int j = 0; j < series.Data.Count; j++)
|
|
||||||
{
|
|
||||||
Color color = ChartStyle.GetColor(i);
|
|
||||||
if (series.Colors.Count > 0 && j >= 0 && j < series.Colors.Count)
|
|
||||||
color = series.Colors[j];
|
|
||||||
|
|
||||||
float xx = sx;
|
|
||||||
|
|
||||||
if (YAxisStart >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (series.Data[j] - start * interval) / ((end - start) * interval)));
|
|
||||||
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (YAxisEnd <= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (end * interval - series.Data[j]) / ((end - start) * interval)));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, Option.Grid.Top + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float lowH = 0;
|
|
||||||
float highH = 0;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
float lowV = 0;
|
|
||||||
float highV = 0;
|
|
||||||
for (int k = YAxisStart; k <= YAxisEnd; k++)
|
|
||||||
{
|
|
||||||
if (k < 0) lowH += DrawBarHeight;
|
|
||||||
if (k > 0) highH += DrawBarHeight;
|
|
||||||
if (k < 0) lowV += (float)YAxisInterval;
|
|
||||||
if (k > 0) highV += (float)YAxisInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.Data[j] >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(highH * series.Data[j] / highV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(lowH * series.Data[j] / lowV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sx += ww + CompactWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
barX += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//宽松
|
|
||||||
for (int i = 0; i < Option.SeriesCount; i++)
|
|
||||||
{
|
|
||||||
var series = Option.Series[i];
|
|
||||||
float x1;
|
|
||||||
if (Option.FixedSeriesCount > 0)
|
|
||||||
x1 = DrawBarWidth / (Option.FixedSeriesCount * 2 + Option.FixedSeriesCount + 1);
|
|
||||||
else
|
|
||||||
x1 = DrawBarWidth / (series.Data.Count * 2 + series.Data.Count + 1);
|
|
||||||
|
|
||||||
float x2 = x1 * 2;
|
|
||||||
|
|
||||||
Bars.TryAdd(i, new List<BarInfo>());
|
|
||||||
for (int j = 0; j < series.Data.Count; j++)
|
|
||||||
{
|
|
||||||
Color color = ChartStyle.GetColor(i);
|
|
||||||
if (series.Colors.Count > 0 && j >= 0 && j < series.Colors.Count)
|
|
||||||
color = series.Colors[j];
|
|
||||||
|
|
||||||
float xx;
|
|
||||||
if (Option.FixedSeriesCount > 0)
|
|
||||||
xx = barX + DrawBarWidth / (series.Data.Count * 2 + series.Data.Count + 1) * ((j + 1) * 3 - 1);
|
|
||||||
else
|
|
||||||
xx = barX + x1 * ((j + 1) * 3 - 1);
|
|
||||||
|
|
||||||
float ww = Math.Min(x2, series.MaxWidth);
|
|
||||||
xx -= ww / 2.0f;
|
|
||||||
|
|
||||||
if (YAxisStart >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (series.Data[j] - start * interval) / ((end - start) * interval)));
|
|
||||||
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (YAxisEnd <= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(DrawSize.Height * (end * interval - series.Data[j]) / ((end - start) * interval)));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, Option.Grid.Top + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float lowH = 0;
|
|
||||||
float highH = 0;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
float lowV = 0;
|
|
||||||
float highV = 0;
|
|
||||||
for (int k = YAxisStart; k <= YAxisEnd; k++)
|
|
||||||
{
|
|
||||||
if (k < 0) lowH += DrawBarHeight;
|
|
||||||
if (k > 0) highH += DrawBarHeight;
|
|
||||||
if (k < 0) lowV += (float)YAxisInterval;
|
|
||||||
if (k > 0) highV += (float)YAxisInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.Data[j] >= 0)
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(highH * series.Data[j] / highV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH - h, ww, h),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float h = Math.Abs((float)(lowH * series.Data[j] / lowV));
|
|
||||||
Bars[i].Add(new BarInfo()
|
|
||||||
{
|
|
||||||
Rect = new RectangleF(xx, DrawOrigin.Y - lowH + 1, ww, h - 1),
|
|
||||||
Color = color
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
barX += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Option.ToolTip != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
var series = Option.Series[i];
|
|
||||||
string str = Option.Series[i].Name;
|
|
||||||
for (int j = 0; j < series.Data.Count; j++)
|
|
||||||
{
|
|
||||||
str += '\n';
|
|
||||||
if (series.BarName.Count > 0 && j < series.BarName.Count)
|
|
||||||
str += series.BarName[j] + " : ";
|
|
||||||
|
|
||||||
str += series.Data[j].ToString(Option.ToolTip.ValueFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bars[i][0].Tips = str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DrawSeries(Graphics g, List<UIBarSeries> series)
|
|
||||||
{
|
|
||||||
if (series == null || series.Count == 0) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < Bars.Count; i++)
|
|
||||||
{
|
|
||||||
var bars = Bars[i];
|
|
||||||
for (int j = 0; j < bars.Count; j++)
|
|
||||||
{
|
|
||||||
g.FillRectangle(bars[j].Color, bars[j].Rect);
|
|
||||||
var s = Option.Series[i];
|
|
||||||
if (s.ShowBarName)
|
|
||||||
{
|
|
||||||
if (s.BarName.Count > 0 && j < s.BarName.Count)
|
|
||||||
{
|
|
||||||
SizeF sf = g.MeasureString(s.BarName[j], TempFont);
|
|
||||||
if (s.Data[j] >= 0)
|
|
||||||
g.DrawString(s.BarName[j], TempFont, ChartStyle.ForeColor,
|
|
||||||
bars[j].Rect.Left + bars[j].Rect.Width / 2 - sf.Width / 2,
|
|
||||||
bars[j].Rect.Bottom + 1);
|
|
||||||
else
|
|
||||||
g.DrawString(s.BarName[j], TempFont, ChartStyle.ForeColor,
|
|
||||||
bars[j].Rect.Left + bars[j].Rect.Width / 2 - sf.Width / 2,
|
|
||||||
bars[j].Rect.Top - sf.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.ShowValue)
|
|
||||||
{
|
|
||||||
string value = s.Data[j].ToString("F" + Option.YAxis.AxisLabel.DecimalCount);
|
|
||||||
SizeF sf = g.MeasureString(value, TempFont);
|
|
||||||
if (s.Data[j] < 0)
|
|
||||||
g.DrawString(value, TempFont, bars[j].Color,
|
|
||||||
bars[j].Rect.Left + bars[j].Rect.Width / 2 - sf.Width / 2,
|
|
||||||
bars[j].Rect.Bottom + 1);
|
|
||||||
else
|
|
||||||
g.DrawString(value, TempFont, bars[j].Color,
|
|
||||||
bars[j].Rect.Left + bars[j].Rect.Width / 2 - sf.Width / 2,
|
|
||||||
bars[j].Rect.Top - sf.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
Bars[i][0].Size = g.MeasureString(Bars[i][0].Tips, TempFont);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int DataCount
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
int dataCount = 0;
|
|
||||||
for (int i = 0; i < Option.SeriesCount; i++)
|
|
||||||
{
|
|
||||||
dataCount += Option.Series[i].Data.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DrawAxis(Graphics g)
|
|
||||||
{
|
|
||||||
if (YAxisStart >= 0) g.DrawLine(ChartStyle.ForeColor, DrawOrigin, new Point(DrawOrigin.X + DrawSize.Width, DrawOrigin.Y));
|
|
||||||
if (YAxisEnd <= 0) g.DrawLine(ChartStyle.ForeColor, new Point(DrawOrigin.X, Option.Grid.Top), new Point(DrawOrigin.X + DrawSize.Width, Option.Grid.Top));
|
|
||||||
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, DrawOrigin, new Point(DrawOrigin.X, DrawOrigin.Y - DrawSize.Height));
|
|
||||||
|
|
||||||
//绘制X轴刻度
|
|
||||||
if (Option.XAxis.AxisTick.Show)
|
|
||||||
{
|
|
||||||
float start;
|
|
||||||
|
|
||||||
if (Option.XAxis.AxisTick.AlignWithLabel)
|
|
||||||
{
|
|
||||||
if (Option.AutoSizeBars)
|
|
||||||
{
|
|
||||||
start = DrawOrigin.X;
|
|
||||||
for (int i = 0; i < Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
float w = DrawSize.Width * Option.Series[i].Data.Count * 1.0f / DataCount;
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, start + (int)(w / 2), DrawOrigin.Y, start + (int)(w / 2), DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
|
||||||
start += (int)w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
start = DrawOrigin.X + DrawBarWidth / 2.0f;
|
|
||||||
for (int i = 0; i < Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
|
||||||
start += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
start = DrawOrigin.X;
|
|
||||||
|
|
||||||
if (Option.AutoSizeBars)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
float w = DrawSize.Width * Option.Series[i].Data.Count * 1.0f / DataCount;
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
|
||||||
start += (int)w;
|
|
||||||
}
|
|
||||||
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, DrawOrigin.X + DrawSize.Width, DrawOrigin.Y, DrawOrigin.X + DrawSize.Width, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i <= Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + Option.XAxis.AxisTick.Length);
|
|
||||||
start += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//绘制X轴标签
|
|
||||||
if (Option.XAxis.AxisLabel.Show)
|
|
||||||
{
|
|
||||||
if (Option.AutoSizeBars)
|
|
||||||
{
|
|
||||||
float start = DrawOrigin.X;
|
|
||||||
foreach (var data in Option.Series)
|
|
||||||
{
|
|
||||||
float w = DrawSize.Width * data.Data.Count * 1.0f / DataCount;
|
|
||||||
SizeF sf = g.MeasureString(data.Name, TempFont);
|
|
||||||
if (Option.XAxis.AxisLabel.Angle != 0)
|
|
||||||
g.DrawString(data.Name, TempFont, ChartStyle.ForeColor, new PointF(start + w / 2.0f - 10, DrawOrigin.Y + Option.Grid.Bottom / 2.0f),
|
|
||||||
new StringFormat() { Alignment = StringAlignment.Center }, (3600 - Option.XAxis.AxisLabel.Angle) % 360);
|
|
||||||
else
|
|
||||||
g.DrawString(data.Name, TempFont, ChartStyle.ForeColor, start + w / 2.0f - sf.Width / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length + Option.XAxis.AxisTick.Distance);
|
|
||||||
start += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float start = DrawOrigin.X + DrawBarWidth / 2.0f;
|
|
||||||
foreach (var data in Option.Series)
|
|
||||||
{
|
|
||||||
SizeF sf = g.MeasureString(data.Name, TempFont);
|
|
||||||
if (Option.XAxis.AxisLabel.Angle != 0)
|
|
||||||
g.DrawString(data.Name, TempFont, ChartStyle.ForeColor, new PointF(start - 10, DrawOrigin.Y + Option.Grid.Bottom / 2.0f),
|
|
||||||
new StringFormat() { Alignment = StringAlignment.Center }, (3600 - Option.XAxis.AxisLabel.Angle) % 360);
|
|
||||||
else
|
|
||||||
g.DrawString(data.Name, TempFont, ChartStyle.ForeColor, start - sf.Width / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length + Option.XAxis.AxisTick.Distance);
|
|
||||||
start += DrawBarWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeF sfName = g.MeasureString(Option.XAxis.Name, TempFont);
|
|
||||||
g.DrawString(Option.XAxis.Name, TempFont, ChartStyle.ForeColor, DrawOrigin.X + (DrawSize.Width - sfName.Width) / 2.0f, DrawOrigin.Y + Option.XAxis.AxisTick.Length + Option.XAxis.AxisTick.Distance + sfName.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
//绘制Y轴刻度
|
|
||||||
if (Option.YAxis.AxisTick.Show)
|
|
||||||
{
|
|
||||||
float start = DrawOrigin.Y;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
for (int i = YAxisStart; i <= YAxisEnd; i++)
|
|
||||||
{
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, DrawOrigin.X, start, DrawOrigin.X - Option.YAxis.AxisTick.Length, start);
|
|
||||||
|
|
||||||
if (i != 0)
|
|
||||||
{
|
|
||||||
using (Pen pn = new Pen(ChartStyle.ForeColor))
|
|
||||||
{
|
|
||||||
pn.DashStyle = DashStyle.Dash;
|
|
||||||
pn.DashPattern = new float[] { 3, 3 };
|
|
||||||
g.DrawLine(pn, DrawOrigin.X, start, Width - Option.Grid.Right, start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g.DrawLine(ChartStyle.ForeColor, DrawOrigin.X, start, Width - Option.Grid.Right, start);
|
|
||||||
|
|
||||||
// float lineStart = DrawOrigin.X;
|
|
||||||
// for (int j = 0; j <= BarOption.Series.Count; j++)
|
|
||||||
// {
|
|
||||||
// g.DrawLine(ChartStyle.ForeColor, lineStart, start, lineStart, start + BarOption.XAxis.AxisTick.Length);
|
|
||||||
// lineStart += DrawBarWidth;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
start -= DrawBarHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//绘制Y轴标签
|
|
||||||
if (Option.YAxis.AxisLabel.Show)
|
|
||||||
{
|
|
||||||
float start = DrawOrigin.Y;
|
|
||||||
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
|
|
||||||
int idx = 0;
|
|
||||||
float wmax = 0;
|
|
||||||
|
|
||||||
if (Option.YAxis.AxisLabel.AutoFormat)
|
|
||||||
Option.YAxis.AxisLabel.DecimalCount = YAxisDecimalCount;
|
|
||||||
|
|
||||||
for (int i = YAxisStart; i <= YAxisEnd; i++)
|
|
||||||
{
|
|
||||||
string label = Option.YAxis.AxisLabel.GetLabel(i * YAxisInterval, idx);
|
|
||||||
SizeF sf = g.MeasureString(label, TempFont);
|
|
||||||
wmax = Math.Max(wmax, sf.Width);
|
|
||||||
g.DrawString(label, TempFont, ChartStyle.ForeColor, DrawOrigin.X - Option.YAxis.AxisTick.Length - sf.Width, start - sf.Height / 2.0f);
|
|
||||||
start -= DrawBarHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeF sfname = g.MeasureString(Option.YAxis.Name, TempFont);
|
|
||||||
int x = (int)(DrawOrigin.X - Option.YAxis.AxisTick.Length - wmax - sfname.Height);
|
|
||||||
int y = (int)(Option.Grid.Top + (DrawSize.Height - sfname.Width) / 2);
|
|
||||||
g.DrawString(Option.YAxis.Name, TempFont, ChartStyle.ForeColor, new Point(x, y),
|
|
||||||
new StringFormat() { Alignment = StringAlignment.Center }, 270);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseMove(MouseEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!Option.ToolTip.Visible) return;
|
|
||||||
if (e.Location.X > Option.Grid.Left &&
|
|
||||||
e.Location.X < Width - Option.Grid.Right &&
|
|
||||||
e.Location.Y > Option.Grid.Top &&
|
|
||||||
e.Location.Y < Height - Option.Grid.Bottom)
|
|
||||||
{
|
|
||||||
if (Option.AutoSizeBars)
|
|
||||||
{
|
|
||||||
float startX = DrawOrigin.X;
|
|
||||||
for (int i = 0; i < Option.Series.Count; i++)
|
|
||||||
{
|
|
||||||
float w = DrawSize.Width * Option.Series[i].Data.Count * 1.0f / DataCount;
|
|
||||||
if (e.Location.X >= startX && e.Location.X < startX + w)
|
|
||||||
{
|
|
||||||
SelectIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
startX += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectIndex = (int)((e.Location.X - Option.Grid.Left) / DrawBarWidth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SelectIndex >= 0 && Bars.Count > 0)
|
|
||||||
{
|
|
||||||
if (tip.Text != Bars[selectIndex][0].Tips)
|
|
||||||
{
|
|
||||||
tip.Text = Bars[selectIndex][0].Tips;
|
|
||||||
tip.Size = new Size((int)Bars[selectIndex][0].Size.Width + 4, (int)Bars[selectIndex][0].Size.Height + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
int x = e.Location.X + 15;
|
|
||||||
int y = e.Location.Y + 20;
|
|
||||||
if (e.Location.X + 15 + tip.Width > Width - Option.Grid.Right)
|
|
||||||
x = e.Location.X - tip.Width - 2;
|
|
||||||
if (e.Location.Y + 20 + tip.Height > Height - Option.Grid.Bottom)
|
|
||||||
y = e.Location.Y - tip.Height - 2;
|
|
||||||
|
|
||||||
tip.Left = x;
|
|
||||||
tip.Top = y;
|
|
||||||
if (!tip.Visible) tip.Visible = Bars[selectIndex][0].Tips.IsValid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
Console.WriteLine(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DrawToolTip(Graphics g)
|
|
||||||
{
|
|
||||||
if (selectIndex < 0) return;
|
|
||||||
|
|
||||||
if (Option.AutoSizeBars)
|
|
||||||
{
|
|
||||||
float startX = DrawOrigin.X;
|
|
||||||
|
|
||||||
for (int i = 0; i < Option.SeriesCount; i++)
|
|
||||||
{
|
|
||||||
float w = DrawSize.Width * Option.Series[i].Data.Count * 1.0f / DataCount;
|
|
||||||
|
|
||||||
if (i == selectIndex)
|
|
||||||
{
|
|
||||||
if (Option.ToolTip.AxisPointer.Type == UIAxisPointerType.Line)
|
|
||||||
{
|
|
||||||
float x = startX + w / 2.0f;
|
|
||||||
g.DrawLine(ChartStyle.ToolTipShadowColor, x, DrawOrigin.Y, x, Option.Grid.Top);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Option.ToolTip.AxisPointer.Type == UIAxisPointerType.Shadow)
|
|
||||||
{
|
|
||||||
g.FillRectangle(ChartStyle.ToolTipShadowColor, startX, Option.Grid.Top, w, Height - Option.Grid.Top - Option.Grid.Bottom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startX += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base.DrawToolTip(g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void CreateEmptyOption()
|
|
||||||
{
|
|
||||||
if (emptyOption != null) return;
|
|
||||||
|
|
||||||
UIBarOption option = new UIBarOption();
|
|
||||||
option.Title = new UITitle();
|
|
||||||
option.Title.Text = "SunnyUI";
|
|
||||||
option.Title.SubText = "BarChartEx";
|
|
||||||
|
|
||||||
//设置Legend
|
|
||||||
option.Legend = new UILegend();
|
|
||||||
option.Legend.Orient = UIOrient.Horizontal;
|
|
||||||
option.Legend.Top = UITopAlignment.Top;
|
|
||||||
option.Legend.Left = UILeftAlignment.Left;
|
|
||||||
option.Legend.AddData("Bar1");
|
|
||||||
option.Legend.AddData("Bar2");
|
|
||||||
option.Legend.AddData("Bar3");
|
|
||||||
|
|
||||||
var series = new UIBarSeries();
|
|
||||||
series.Name = "Bar1";
|
|
||||||
series.AddData(1);
|
|
||||||
option.Series.Add(series);
|
|
||||||
|
|
||||||
series = new UIBarSeries();
|
|
||||||
series.Name = "Bar2";
|
|
||||||
series.AddData(2);
|
|
||||||
series.AddData(3);
|
|
||||||
option.Series.Add(series);
|
|
||||||
|
|
||||||
series = new UIBarSeries();
|
|
||||||
series.Name = "Bar2";
|
|
||||||
series.AddData(4);
|
|
||||||
series.AddData(5);
|
|
||||||
series.AddData(6);
|
|
||||||
option.Series.Add(series);
|
|
||||||
|
|
||||||
option.XAxis.Data.Add("Mon");
|
|
||||||
option.XAxis.Data.Add("Tue");
|
|
||||||
option.XAxis.Data.Add("Wed");
|
|
||||||
option.XAxis.Data.Add("Thu");
|
|
||||||
option.XAxis.Data.Add("Fri");
|
|
||||||
|
|
||||||
option.ToolTip = new UIBarToolTip();
|
|
||||||
option.ToolTip.AxisPointer.Type = UIAxisPointerType.Shadow;
|
|
||||||
|
|
||||||
emptyOption = option;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user