DotNet 4.8.1 build of DotNetBar
This commit is contained in:
@@ -0,0 +1,922 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using DevComponents.DotNetBar.Charts.Style;
|
||||
|
||||
namespace DevComponents.DotNetBar.Charts
|
||||
{
|
||||
class FlockAlign
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const long RemovePenalty = 1;
|
||||
private const int MovesPerIteration = 500;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private variables
|
||||
|
||||
private List<PointLabelGroup> _LabelGroups;
|
||||
|
||||
#endregion
|
||||
|
||||
public FlockAlign(List<PointLabelGroup> labelGroups)
|
||||
{
|
||||
_LabelGroups = labelGroups;
|
||||
|
||||
foreach (PointLabelGroup lg in _LabelGroups)
|
||||
{
|
||||
foreach (PointLabel pl in lg.PointLabels)
|
||||
pl.Bounds = Rectangle.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#region Iterate
|
||||
|
||||
public bool Iterate(Rectangle bounds, DataLabelOverlapMode ovlMode)
|
||||
{
|
||||
if (ovlMode == DataLabelOverlapMode.NotSet)
|
||||
ovlMode = DataLabelOverlapMode.RotateAroundPoint;
|
||||
|
||||
for (int i = 0; i < _LabelGroups.Count; i++)
|
||||
{
|
||||
PointLabelGroup lg = _LabelGroups[i];
|
||||
List<PointLabel> lps = lg.PointLabels;
|
||||
ChartSeries series = lg.ChartSeries;
|
||||
|
||||
Point lp = Point.Empty;
|
||||
|
||||
for (int j = 0; j < lps.Count; j++)
|
||||
{
|
||||
PointLabel pl = lps[j];
|
||||
|
||||
if (pl.Visible == true )
|
||||
{
|
||||
DataLabelVisualStyle dstyle = pl.DataLabelVisualStyle ?? series.EffectiveDataLabelStyle;
|
||||
|
||||
if (series.IsBarSeries == true)
|
||||
{
|
||||
if (series.IsRotated == true)
|
||||
IterateHBar(series, pl, bounds, ovlMode, dstyle);
|
||||
else
|
||||
IterateVBar(series, pl, bounds, ovlMode, dstyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
IteratePoint(series, pl, bounds, lp, ovlMode, dstyle);
|
||||
}
|
||||
}
|
||||
|
||||
lp = pl.Point;
|
||||
}
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
#region IterateHBar
|
||||
|
||||
private void IterateHBar(ChartSeries series, PointLabel pl,
|
||||
Rectangle bounds, DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
ChartXy chartXy = series.Parent as ChartXy;
|
||||
|
||||
int start = (pl.IsDataLabel == true)
|
||||
? pl.Point.X - 1 : series.GetHBarStart(chartXy, pl.SeriesPoint);
|
||||
|
||||
int end = pl.Point.X;
|
||||
|
||||
BarLabelPosition labelPos = pl.BarLabelPosition;
|
||||
|
||||
if (labelPos == BarLabelPosition.NotSet)
|
||||
labelPos = series.GetBarLabelPosition(chartXy);
|
||||
|
||||
switch (labelPos)
|
||||
{
|
||||
case BarLabelPosition.Near:
|
||||
SetHBarLabelNear(series, pl, bounds, ovlMode, dstyle, start, end, false);
|
||||
break;
|
||||
|
||||
case BarLabelPosition.NearInside:
|
||||
SetHBarLabelNear(series, pl, bounds, ovlMode, dstyle, start, end, true);
|
||||
break;
|
||||
|
||||
case BarLabelPosition.Far:
|
||||
SetHBarLabelFar(series, pl, bounds, ovlMode, dstyle, start, end, false);
|
||||
break;
|
||||
|
||||
case BarLabelPosition.FarInside:
|
||||
SetHBarLabelFar(series, pl, bounds, ovlMode, dstyle, start, end, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
SetHBarLabelCenter(series, pl, bounds, ovlMode, dstyle, start, end);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region SetHBarLabelNear
|
||||
|
||||
private void SetHBarLabelNear(ChartSeries series, PointLabel pl, Rectangle bounds,
|
||||
DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle, int start, int end, bool inside)
|
||||
{
|
||||
ConnectorLineVisualStyle cstyle = dstyle.ConnectorLineStyle;
|
||||
|
||||
Point pt = new Point(start, pl.Point.Y + series.BarOffset);
|
||||
|
||||
Size size = GetBoundsSize(series, pl, dstyle);
|
||||
Rectangle t = Rectangle.Empty;
|
||||
|
||||
int minLength = Dpi.Width(cstyle.MinLength);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int clen = (inside == false && minLength > 0) ? minLength + Dpi.Width2 : Dpi.Width4;
|
||||
|
||||
int step = cstyle.LengthStep;
|
||||
int offset = (size.Width / 2 + clen);
|
||||
|
||||
if (inside ? end < start : end > start)
|
||||
{
|
||||
step *= -1;
|
||||
offset *= -1;
|
||||
}
|
||||
|
||||
Point ptc = pt;
|
||||
ptc.X += offset;
|
||||
|
||||
t = GetCenteredRectangle(series, ptc, size);
|
||||
|
||||
while (step < 0 ? t.X > bounds.X : t.Right < bounds.Right)
|
||||
{
|
||||
if (SetHBarLabelPos(pl, ovlMode, bounds, ptc, t, start, end) == true)
|
||||
return;
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
t.X += step;
|
||||
|
||||
if (cstyle.MaxLength > 0)
|
||||
{
|
||||
if (Math.Abs(t.X - ptc.X) > cstyle.MaxLength)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
SetHBarDefaultLabelPos(series, ref pl, pt, t, ovlMode, start, end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetHBarLabelFar
|
||||
|
||||
private void SetHBarLabelFar(ChartSeries series, PointLabel pl, Rectangle bounds,
|
||||
DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle, int start, int end, bool inside)
|
||||
{
|
||||
ConnectorLineVisualStyle cstyle = dstyle.ConnectorLineStyle;
|
||||
|
||||
Point pt = new Point(end, pl.Point.Y + series.BarOffset);
|
||||
Size size = GetBoundsSize(series, pl, dstyle);
|
||||
|
||||
Rectangle t = Rectangle.Empty;
|
||||
|
||||
int minLength = Dpi.Width(cstyle.MinLength);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int clen = (inside == false && minLength >= 0) ? minLength + Dpi.Width2 : Dpi.Width4;
|
||||
|
||||
int step = cstyle.LengthStep;
|
||||
int offset = (size.Width / 2 + clen);
|
||||
|
||||
if (inside ? end > start : end < start)
|
||||
{
|
||||
step *= -1;
|
||||
offset *= -1;
|
||||
}
|
||||
|
||||
Point ptc = pt;
|
||||
ptc.X += offset;
|
||||
|
||||
t = GetCenteredRectangle(series, ptc, size);
|
||||
|
||||
while (step < 0 ? t.X > bounds.X : t.Right < bounds.Right)
|
||||
{
|
||||
if (SetHBarLabelPos(pl, ovlMode, bounds, ptc, t, start, end) == true)
|
||||
return;
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
t.X += step;
|
||||
|
||||
if (cstyle.MaxLength > 0)
|
||||
{
|
||||
if (Math.Abs(t.X - ptc.X) > cstyle.MaxLength)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
SetHBarDefaultLabelPos(series, ref pl, pt, t, ovlMode, start, end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetHBarLabelCenter
|
||||
|
||||
private void SetHBarLabelCenter(ChartSeries series, PointLabel pl,
|
||||
Rectangle bounds, DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle,
|
||||
int start, int end)
|
||||
{
|
||||
Point pt = new Point((end + start) / 2, pl.Point.Y + series.BarOffset);
|
||||
|
||||
int pass = 0;
|
||||
int step = 2;
|
||||
int startx = pt.X;
|
||||
|
||||
Size size = GetBoundsSize(series, pl, dstyle);
|
||||
|
||||
Rectangle t = GetCenteredRectangle(series, pt, size);
|
||||
|
||||
int len = (end + start) / 2;
|
||||
|
||||
while (pass <= len)
|
||||
{
|
||||
if (SetHBarLabelPos(pl, ovlMode, bounds, pt, t, start, end) == true)
|
||||
return;
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
int pval = pass / 2 + 1;
|
||||
|
||||
if (pass % 2 > 0)
|
||||
pval = -pval;
|
||||
|
||||
t.X = (startx + (pval * step));
|
||||
|
||||
pass++;
|
||||
}
|
||||
|
||||
SetHBarDefaultLabelPos(series, ref pl, pt, t, ovlMode, start, end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetHBarLabelPos
|
||||
|
||||
private bool SetHBarLabelPos(PointLabel pl,
|
||||
DataLabelOverlapMode ovlMode, Rectangle bounds, Point pt, Rectangle t, int start, int end)
|
||||
{
|
||||
if (IsFreeArea(t, bounds, ovlMode, false, true) == true)
|
||||
{
|
||||
pl.Bounds = t;
|
||||
|
||||
SetHBarEdgePoint(pl, pt, t, start, end);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (ovlMode == DataLabelOverlapMode.HideOverlapping)
|
||||
return (true);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetHBarDefaultLabelPos
|
||||
|
||||
private void SetHBarDefaultLabelPos(ChartSeries series, ref PointLabel pl,
|
||||
Point pt, Rectangle t, DataLabelOverlapMode ovlMode, int start, int end)
|
||||
{
|
||||
if (ovlMode == DataLabelOverlapMode.RotateAroundPoint)
|
||||
{
|
||||
if (t.X < start)
|
||||
t.X = start + Dpi.Width4;
|
||||
else
|
||||
t.X = end - (t.Width + Dpi.Width4);
|
||||
|
||||
ChartXy chartXy = series.Parent as ChartXy;
|
||||
|
||||
Rectangle bounds = chartXy.ContentBoundsEx;
|
||||
|
||||
if (t.Right > bounds.Right)
|
||||
t.X -= (t.Right - bounds.Right + Dpi.Width4);
|
||||
|
||||
if (t.X < bounds.X)
|
||||
t.X = bounds.X + Dpi.Width4;
|
||||
|
||||
pl.Bounds = t;
|
||||
|
||||
SetHBarEdgePoint(pl, pt, t, start, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
pl.Bounds = Rectangle.Empty;
|
||||
pl.EdgePoint = Point.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetHBarEdgePoint
|
||||
|
||||
private void SetHBarEdgePoint(PointLabel pl, Point pt, Rectangle t, int start, int end)
|
||||
{
|
||||
if (t.X > start && t.X > end)
|
||||
{
|
||||
pt.X = Math.Max(start, end);
|
||||
pl.EdgePoint = new Point(t.X, pt.Y);
|
||||
}
|
||||
else if (t.X < start && t.X < end)
|
||||
{
|
||||
pt.X = Math.Min(start, end);
|
||||
pl.EdgePoint = new Point(t.Right, pt.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
pl.EdgePoint = Point.Empty;
|
||||
}
|
||||
|
||||
pl.Point = pt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region IterateVBar
|
||||
|
||||
private void IterateVBar(ChartSeries series, PointLabel pl,
|
||||
Rectangle bounds, DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
ChartXy chartXy = series.Parent as ChartXy;
|
||||
|
||||
int start = series.GetVBarStart(chartXy, pl.SeriesPoint);
|
||||
int end = pl.Point.Y;
|
||||
|
||||
BarLabelPosition labelPos = series.GetBarLabelPosition(chartXy);
|
||||
|
||||
switch (labelPos)
|
||||
{
|
||||
case BarLabelPosition.Near:
|
||||
SetVBarLabelNear(series, pl, bounds, ovlMode, dstyle, start, end, false);
|
||||
break;
|
||||
|
||||
case BarLabelPosition.NearInside:
|
||||
SetVBarLabelNear(series, pl, bounds, ovlMode, dstyle, start, end, true);
|
||||
break;
|
||||
|
||||
case BarLabelPosition.Far:
|
||||
SetVBarLabelFar(series, pl, bounds, ovlMode, dstyle, start, end, false);
|
||||
break;
|
||||
|
||||
case BarLabelPosition.FarInside:
|
||||
SetVBarLabelFar(series, pl, bounds, ovlMode, dstyle, start, end, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
SetVBarLabelCenter(series, pl, bounds, ovlMode, dstyle, start, end);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region SetVBarLabelNear
|
||||
|
||||
private void SetVBarLabelNear(ChartSeries series, PointLabel pl, Rectangle bounds,
|
||||
DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle, int start, int end, bool inside)
|
||||
{
|
||||
ConnectorLineVisualStyle cstyle = dstyle.ConnectorLineStyle;
|
||||
|
||||
Point pt = new Point(pl.Point.X + series.BarOffset, start);
|
||||
Size size = GetBoundsSize(series, pl, dstyle);
|
||||
|
||||
int minLength = Dpi.Width(cstyle.MinLength);
|
||||
|
||||
int clen = (inside == false && minLength >= 0) ? minLength + Dpi.Width2 : Dpi.Width4;
|
||||
|
||||
int step = cstyle.LengthStep;
|
||||
int offset = (size.Height / 2 + clen);
|
||||
|
||||
Rectangle t = Rectangle.Empty;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (inside ? end < start : end > start)
|
||||
{
|
||||
step *= -1;
|
||||
offset *= -1;
|
||||
}
|
||||
|
||||
Point ptc = pt;
|
||||
ptc.Y += offset;
|
||||
|
||||
t = GetCenteredRectangle(series, ptc, size);
|
||||
|
||||
while (t.Y < bounds.Bottom)
|
||||
{
|
||||
if (SetVBarLabelPos(pl, ovlMode, bounds, ptc, t, start, end) == true)
|
||||
return;
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
t.Y += step;
|
||||
|
||||
if (cstyle.MaxLength > 0)
|
||||
{
|
||||
if (Math.Abs(t.Y - ptc.Y) > cstyle.MaxLength)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
SetVBarDefaultLabelPos(series, ref pl, pt, t, ovlMode, start, end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetVBarLabelFar
|
||||
|
||||
private void SetVBarLabelFar(ChartSeries series, PointLabel pl, Rectangle bounds,
|
||||
DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle, int start, int end, bool inside)
|
||||
{
|
||||
ConnectorLineVisualStyle cstyle = dstyle.ConnectorLineStyle;
|
||||
|
||||
Point pt = new Point(pl.Point.X + series.BarOffset, end);
|
||||
Size size = GetBoundsSize(series, pl, dstyle);
|
||||
|
||||
int minLength = Dpi.Width(cstyle.MinLength);
|
||||
|
||||
Rectangle t = Rectangle.Empty;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int clen = (inside == false && minLength >= 0) ? minLength + Dpi.Width2 : Dpi.Width4;
|
||||
|
||||
int step = cstyle.LengthStep;
|
||||
int offset = (size.Height / 2 + clen);
|
||||
|
||||
if (inside ? end > start : end < start)
|
||||
{
|
||||
step *= -1;
|
||||
offset *= -1;
|
||||
}
|
||||
|
||||
Point ptc = pt;
|
||||
ptc.Y += offset;
|
||||
|
||||
t = GetCenteredRectangle(series, ptc, size);
|
||||
|
||||
while (step < 0 ? t.Y > bounds.Y : t.Y < bounds.Bottom)
|
||||
{
|
||||
if (SetVBarLabelPos(pl, ovlMode, bounds, ptc, t, start, end) == true)
|
||||
return;
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
t.Y += step;
|
||||
|
||||
if (cstyle.MaxLength > 0)
|
||||
{
|
||||
if (Math.Abs(t.Y - ptc.Y) > cstyle.MaxLength)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
SetVBarDefaultLabelPos(series, ref pl, pt, t, ovlMode, start, end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetVBarLabelCenter
|
||||
|
||||
private void SetVBarLabelCenter(ChartSeries series, PointLabel pl,
|
||||
Rectangle bounds, DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle,
|
||||
int origin, int end)
|
||||
{
|
||||
Point pt = new Point(pl.Point.X + series.BarOffset, (end + origin) / 2);
|
||||
|
||||
int pass = 0;
|
||||
int step = 2;
|
||||
int starty = pt.Y;
|
||||
|
||||
Size size = GetBoundsSize(series, pl, dstyle);
|
||||
|
||||
Rectangle t = GetCenteredRectangle(series, pt, size);
|
||||
|
||||
int len = (end + origin) / 2;
|
||||
|
||||
while (pass <= len)
|
||||
{
|
||||
if (SetVBarLabelPos(pl, ovlMode, bounds, pt, t, origin, end) == true)
|
||||
return;
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
int pval = pass / 2 + 1;
|
||||
|
||||
if (pass % 2 > 0)
|
||||
pval = -pval;
|
||||
|
||||
t.Y = (starty + (pval * step));
|
||||
|
||||
pass++;
|
||||
}
|
||||
|
||||
SetVBarDefaultLabelPos(series, ref pl, pt, t, ovlMode, origin, end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetVBarLabelPos
|
||||
|
||||
private bool SetVBarLabelPos(PointLabel pl,
|
||||
DataLabelOverlapMode ovlMode, Rectangle bounds, Point pt, Rectangle t, int start, int end)
|
||||
{
|
||||
if (IsFreeArea(t, bounds, ovlMode, false, true) == true)
|
||||
{
|
||||
pl.Bounds = t;
|
||||
|
||||
SetVBarEdgePoint(pl, pt, t, start, end);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (ovlMode == DataLabelOverlapMode.HideOverlapping)
|
||||
return (true);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetVBarDefaultLabelPos
|
||||
|
||||
private void SetVBarDefaultLabelPos(ChartSeries series, ref PointLabel pl,
|
||||
Point pt, Rectangle t, DataLabelOverlapMode ovlMode, int start, int end)
|
||||
{
|
||||
if (ovlMode == DataLabelOverlapMode.RotateAroundPoint)
|
||||
{
|
||||
if (t.Y > start)
|
||||
t.Y = start - (t.Height + Dpi.Height4);
|
||||
else
|
||||
t.Y = end + Dpi.Height4;
|
||||
|
||||
ChartXy chartXy = series.Parent as ChartXy;
|
||||
|
||||
Rectangle bounds = chartXy.ContentBoundsEx;
|
||||
|
||||
if (t.Y > bounds.Bottom)
|
||||
t.Y -= (t.Bottom - bounds.Bottom + Dpi.Height4);
|
||||
|
||||
if (t.Y < bounds.Y)
|
||||
t.Y = bounds.Y + Dpi.Height4;
|
||||
|
||||
pl.Bounds = t;
|
||||
|
||||
SetVBarEdgePoint(pl, pt, t, start, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
pl.Bounds = Rectangle.Empty;
|
||||
pl.EdgePoint = Point.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetVBarEdgePoint
|
||||
|
||||
private void SetVBarEdgePoint(PointLabel pl, Point pt, Rectangle t, int start, int end)
|
||||
{
|
||||
if (t.Y > start && t.Y > end)
|
||||
{
|
||||
pt.Y = Math.Max(start, end);
|
||||
pl.EdgePoint = new Point(pt.X, t.Y);
|
||||
}
|
||||
else if (t.Y < start && t.Y < end)
|
||||
{
|
||||
pt.Y = Math.Min(start, end);
|
||||
pl.EdgePoint = new Point(pt.X, t.Bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
pl.EdgePoint = Point.Empty;
|
||||
}
|
||||
|
||||
pl.Point = pt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region IteratePoint
|
||||
|
||||
private void IteratePoint(ChartSeries series, PointLabel pl,
|
||||
Rectangle bounds, Point lp, DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
if ((dstyle.CenterLabel != Tbool.True) ||
|
||||
SetLabelCenter(series, pl, bounds, ovlMode, dstyle) == false)
|
||||
{
|
||||
ConnectorLineVisualStyle cstyle = dstyle.ConnectorLineStyle;
|
||||
|
||||
int step;
|
||||
int startAngle = GetStartAngle(lp, pl, cstyle, out step);
|
||||
|
||||
int offset = 0;
|
||||
|
||||
if (cstyle.Origin == ConnectorOrigin.Edge)
|
||||
{
|
||||
offset = Math.Max(
|
||||
pl.SeriesPoint.PointSize.Width,
|
||||
pl.SeriesPoint.PointSize.Height) / 2;
|
||||
}
|
||||
|
||||
SetLabel(series, pl, startAngle, step,
|
||||
cstyle.MinLength + offset, cstyle.MaxLength + offset, ovlMode, bounds, dstyle);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetBoundsSize
|
||||
|
||||
private Size GetBoundsSize(
|
||||
ChartSeries series, PointLabel pl, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
RotateDegrees rotate = series.GetRotateDegrees(dstyle);
|
||||
|
||||
Size size = (rotate == RotateDegrees.Rotate90 || rotate == RotateDegrees.Rotate270)
|
||||
? new Size(pl.LabelSize.Height, pl.LabelSize.Width) : pl.LabelSize;
|
||||
|
||||
if (dstyle.HasBorder == true)
|
||||
{
|
||||
size.Width += (dstyle.BorderThickness << 1);
|
||||
size.Height += (dstyle.BorderThickness << 1);
|
||||
}
|
||||
|
||||
size.Width += dstyle.Padding.Horizontal;
|
||||
size.Height += dstyle.Padding.Vertical;
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetLabelCenter
|
||||
|
||||
private bool SetLabelCenter(ChartSeries series, PointLabel pl,
|
||||
Rectangle bounds, DataLabelOverlapMode ovlMode, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
Rectangle t = GetCenteredRectangle(series, pl.Point, pl.LabelSize);
|
||||
|
||||
if (IsFreeArea(t, bounds, ovlMode, true, true) == true)
|
||||
{
|
||||
pl.Bounds = t;
|
||||
pl.EdgePoint = new Point(t.Right, t.Bottom);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (ovlMode == DataLabelOverlapMode.HideOverlapping)
|
||||
return (true);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetLabel
|
||||
|
||||
private bool SetLabel(ChartSeries series, PointLabel pl, int startAngle, int step,
|
||||
int radius, int maxRadius, DataLabelOverlapMode ovlMode, Rectangle bounds, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
int angle = startAngle;
|
||||
int pass = 0;
|
||||
|
||||
radius = Dpi.Width(radius);
|
||||
maxRadius = Dpi.Width(maxRadius);
|
||||
|
||||
while (radius <= maxRadius)
|
||||
{
|
||||
Point calcPoint;
|
||||
Rectangle r = GetAreaRectangle(series, pl, angle, radius, out calcPoint, dstyle);
|
||||
|
||||
if (IsFreeArea(r, bounds, ovlMode, true, true) == true)
|
||||
{
|
||||
pl.Angle = angle;
|
||||
pl.Bounds = r;
|
||||
pl.EdgePoint = calcPoint;
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (ovlMode != DataLabelOverlapMode.RotateAroundPoint)
|
||||
break;
|
||||
|
||||
int pval = pass / 2 + 1;
|
||||
|
||||
if (pass % 2 > 0)
|
||||
pval = -pval;
|
||||
|
||||
angle = (startAngle + (pval * step)) % 360;
|
||||
|
||||
pass++;
|
||||
|
||||
if (pass * step >= 360)
|
||||
{
|
||||
radius += Dpi.Width15;
|
||||
pass = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pl.Bounds = Rectangle.Empty;
|
||||
pl.EdgePoint = Point.Empty;
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetStartAngle
|
||||
|
||||
private int GetStartAngle(Point lp,
|
||||
PointLabel pl, ConnectorLineVisualStyle cstyle, out int step)
|
||||
{
|
||||
step = cstyle.AngleStep;
|
||||
|
||||
if (cstyle.DefaultAngle >= 0)
|
||||
return (cstyle.DefaultAngle);
|
||||
|
||||
Point pt = pl.Point;
|
||||
|
||||
int rise = lp.Y - pt.Y;
|
||||
int run = lp.X - pt.X;
|
||||
|
||||
double slope = (run == 0) ? 0 : (double)rise / run;
|
||||
|
||||
return ((slope < 1) ? 270 : (slope > 0) ? 315 : 225);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetCenteredRectangle
|
||||
|
||||
private Rectangle GetCenteredRectangle(
|
||||
ChartSeries series, Point pt, Size labelSize)
|
||||
{
|
||||
Rectangle r = new Rectangle(pt, labelSize);
|
||||
|
||||
r.X -= (r.Width / 2);
|
||||
r.Y -= (r.Height / 2);
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetAreaRectangle
|
||||
|
||||
private Rectangle GetAreaRectangle(ChartSeries series, PointLabel pl,
|
||||
int angle, int radius, out Point calcPoint, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
Rectangle r = new Rectangle(pl.Point, pl.LabelSize);
|
||||
|
||||
RotateDegrees rotate = series.GetRotateDegrees(dstyle);
|
||||
|
||||
if (rotate == RotateDegrees.Rotate90 || rotate == RotateDegrees.Rotate270)
|
||||
{
|
||||
r.Width = pl.LabelSize.Height;
|
||||
r.Height = pl.LabelSize.Width;
|
||||
}
|
||||
|
||||
if (dstyle.HasBorder == true)
|
||||
{
|
||||
int n = Dpi.Width(dstyle.BorderThickness) << 1;
|
||||
|
||||
r.Width += n;
|
||||
r.Height += n;
|
||||
}
|
||||
|
||||
r.Width += Dpi.Width(dstyle.Padding.Horizontal);
|
||||
r.Height += Dpi.Height(dstyle.Padding.Vertical);
|
||||
|
||||
r.X += (int)(radius * Math.Cos(MathHelper.ToRadians(angle)));
|
||||
r.Y += (int)(radius * Math.Sin(MathHelper.ToRadians(angle)));
|
||||
|
||||
calcPoint = r.Location;
|
||||
|
||||
return (OffsetAreaRectangle(r, angle, ref calcPoint, dstyle));
|
||||
}
|
||||
|
||||
#region OffsetAreaRectangle
|
||||
|
||||
private Rectangle OffsetAreaRectangle(Rectangle r,
|
||||
int angle, ref Point calcPoint, DataLabelVisualStyle dstyle)
|
||||
{
|
||||
if (angle == 0)
|
||||
{
|
||||
r.Y -= (r.Height / 2);
|
||||
}
|
||||
else if (angle == 90)
|
||||
{
|
||||
r.X -= (r.Width / 2);
|
||||
}
|
||||
else if (angle == 180)
|
||||
{
|
||||
r.X -= r.Width;
|
||||
r.Y -= (r.Height / 2);
|
||||
}
|
||||
else if (angle == 270)
|
||||
{
|
||||
r.X -= (r.Width / 2);
|
||||
r.Y -= r.Height;
|
||||
}
|
||||
else if (angle < 90)
|
||||
{
|
||||
}
|
||||
else if (angle < 180)
|
||||
{
|
||||
r.X -= r.Width;
|
||||
}
|
||||
else if (angle < 270)
|
||||
{
|
||||
r.X -= r.Width;
|
||||
r.Y -= r.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Y -= r.Height;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsFreeArea
|
||||
|
||||
private bool IsFreeArea(
|
||||
Rectangle r, Rectangle bounds, DataLabelOverlapMode ovlMode, bool xos, bool yos)
|
||||
{
|
||||
if (xos == true)
|
||||
{
|
||||
if (r.X < bounds.X || r.Right > bounds.Right)
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (yos == true)
|
||||
{
|
||||
if (r.Y < bounds.Y || r.Bottom > bounds.Bottom)
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (ovlMode == DataLabelOverlapMode.ShowOverlapping)
|
||||
return (true);
|
||||
|
||||
r.Inflate(3, 3);
|
||||
|
||||
for (int i = 0; i < _LabelGroups.Count; i++)
|
||||
{
|
||||
List<PointLabel> lps = _LabelGroups[i].PointLabels;
|
||||
|
||||
for (int j = 0; j < lps.Count; j++)
|
||||
{
|
||||
PointLabel pl = lps[j];
|
||||
|
||||
if (pl.Bounds.IsEmpty == false)
|
||||
{
|
||||
if (pl.Bounds.IntersectsWith(r) == true)
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user