923 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			923 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
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
 | 
						|
    }
 | 
						|
}
 | 
						|
 |