/// <summary>
        /// Check whether two labels overlap. Also calculate the horizontal and vertical offsets
        /// to overcome the overlap.
        /// </summary>
        /// <param name="labelInfo">Information of the label</param>
        /// <param name="verticalOffset">How much need to move vertically to overcome overlap</param>
        /// <param name="horizontalOffset">How much need to move horizontally to overcome overlap</param>
        /// <returns>OverlapTypes</returns>
        private OverlapTypes CheckOverlap(CircularLabel label, out Double verticalOffset, out Double horizontalOffset)
        {
            OverlapTypes retValue = OverlapTypes.None; // Type of overlap

            verticalOffset   = 0;                      // How much need to move vertically to overcome overlap
            horizontalOffset = 0;                      // How much need to move horizontally to overcome overlap

            CircularLabel A = this;
            CircularLabel B = label;

            if (B.Position.Y > A.Position.Y)
            {
                if (B.Position.Y < A.Position.Y + A.Height)
                {
                    // Calculate how much need to move vertically to overcome overlap
                    verticalOffset = A.Position.Y + A.Height - B.Position.Y;
                    retValue       = OverlapTypes.Vertical;
                }
            }
            else if (A.Position.Y > B.Position.Y)
            {
                if (A.Position.Y < B.Position.Y + B.Height)
                {
                    // Calculate how much need to move vertically to overcome overlap
                    verticalOffset = B.Position.Y + B.Height - A.Position.Y;
                    retValue       = OverlapTypes.Vertical;
                }
            }

            if (B.Position.X > A.Position.X)
            {
                if (B.Position.X < A.Position.X + A.Width)
                {
                    // Calculate how much need to move horizontally to overcome overlap
                    horizontalOffset = A.Position.X + A.Width - B.Position.X;
                    retValue         = (retValue == OverlapTypes.Vertical) ? OverlapTypes.Both : OverlapTypes.Horizontal;
                }
            }
            else if (A.Position.X > B.Position.X)
            {
                if (A.Position.X < B.Position.X + B.Width)
                {
                    // Calculate how much need to move horizontally to overcome overlap
                    horizontalOffset = B.Position.X + B.Width - A.Position.X;
                    retValue         = (retValue == OverlapTypes.Vertical) ? OverlapTypes.Both : OverlapTypes.Horizontal;
                }
            }

            return(retValue);
        }
        /// <summary>
        /// Ask for space to NextLabel if NextLabel can leave the space.
        /// NextLabel B asks for space to the next label C.. and so on
        /// </summary>
        /// <param name="labelA">CircularLabel looking for space to overcome the overlap</param>
        private static Boolean AskSpaceToNextLabel(CircularLabel label, Double requiredVerticalOffset, Int32 noOfIteration)
        {
            Boolean retValue = true;
            Double  gap      = 0;

            if (label.IsLast)
            {
                if (label.Position.Y + label.Height < label.Boundary.Height &&
                    label.Boundary.Height - (label.Position.Y + label.Height) > requiredVerticalOffset)
                {
                    retValue = label.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Clockwise);
                    return(retValue);
                }
                else
                {
                    return(false);
                }
            }

            gap = VerticalSpcaeBetweenLabels(label, label.NextLabel);
            if (gap > requiredVerticalOffset)
            {
                retValue = label.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Clockwise);
                return(retValue);
            }
            else
            {
                retValue = AskSpaceToNextLabel(label.NextLabel, requiredVerticalOffset, noOfIteration);
                if (retValue)
                {
                    retValue = label.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Clockwise);
                    return(retValue);
                }
                else
                {
                    retValue = false;
                }
            }

            return(retValue);
        }
        /// <summary>
        /// Ask for space to PreviusLabel B if it can leave the space inorder to overcome the overlap.
        /// PreviusLabel B asks for space to the previous label C.. and so on
        /// </summary>
        /// <param name="labelA">CircularLabel looking for space to overcome the overlap</param>
        private static Boolean AskSpaceToPreviusLabel(CircularLabel labelA, Double requiredVerticalOffset, Int32 noOfIteration)
        {
            Boolean retValue = true;
            Double  gap      = 0;

            if (labelA.IsFirst)
            {
                if (labelA.Position.Y > requiredVerticalOffset)
                {
                    retValue = labelA.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Counterclockwise);
                    return(retValue);
                }
                else
                {
                    return(false);
                }
            }

            gap = VerticalSpcaeBetweenLabels(labelA, labelA.PreviusLabel);

            if (gap > requiredVerticalOffset)
            {
                retValue = labelA.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Counterclockwise);
                return(retValue);
            }
            else
            {
                retValue = AskSpaceToPreviusLabel(labelA.PreviusLabel, requiredVerticalOffset, noOfIteration);
                if (retValue)
                {
                    retValue = labelA.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Counterclockwise);
                    return(retValue);
                }
                else
                {
                    retValue = false;
                }
            }

            return(retValue);
        }
        /// <summary>
        /// Calculate vertical space available between two CircularLabels
        /// </summary>
        /// <param name="label1">CircularLabel A</param>
        /// <param name="label2">CircularLabel B</param>
        /// <returns>vertical space available between two CircularLabels</returns>
        private static Double VerticalSpcaeBetweenLabels(CircularLabel labelA, CircularLabel labelB)
        {
            Double gap = 0;

            if (labelA.Position.Y < labelB.Position.Y)
            {
                gap = labelB.Position.Y - (labelA.Position.Y + labelA.Height);
            }
            else
            {
                gap = labelA.Position.Y - (labelB.Position.Y + labelB.Height);
            }

            if (gap < 0)
            {
                return(0);
            }
            else
            {
                return(gap);
            }
        }
Exemple #5
0
        /// <summary>
        /// Position labels for Pie /Doughnut
        /// </summary>
        /// <param name="visual">Visual element</param>
        /// <param name="totalSum">Total YValue sum from all dataPoints</param>
        /// <param name="dataPoints">List of dataPoint</param>
        /// <param name="labels">Dictionary of dataPoint labels</param>
        /// <param name="pieSize">Pie size</param>
        /// <param name="referenceEllipseSize">Reference ellipse size</param>
        /// <param name="visualCanvasSize">Visual canvas size</param>
        /// <param name="scaleY">Scale Y</param>
        /// <param name="is3D">Whether a 3D chart</param>
        private static void PositionLabels(Canvas visual, Double totalSum, List<DataPoint> dataPoints, Size pieSize, Size referenceEllipseSize, Size visualCanvasSize, Double scaleY, Boolean is3D)
        {
            //Point plotRadius;
            Double xRadiusLabel = referenceEllipseSize.Width / 2;
            Double yRadiusLabel = referenceEllipseSize.Height / 2;
            Double xRadiusChart = pieSize.Width / 2;
            Double yRadiusChart = pieSize.Height / 2;
            Point center;
            Chart chart = null;
            //if(is3D)
            //    center = new Point(visualCanvasSize.Width / 2, visualCanvasSize.Height / 2 - (yRadiusChart * scaleY) / 2);
            //else
                center = new Point(visualCanvasSize.Width / 2, visualCanvasSize.Height / 2);
            
            Double startAngle = FixAngle(dataPoints[0].Parent.InternalStartAngle), stopAngle, meanAngle;
            //Graphics.DrawPointAt(center, visual, System.Windows.Media.Colors.Red);

            CircularLabel prevousLabel = null;
            CircularLabel cLabel = null;
            Rect boundingArea = new Rect(0, 0, visual.Width, visual.Height);
            // List of CircularLabels
            List<CircularLabel> circularLabels = new List<CircularLabel>();

            // Creating the LinkList of CircularLabels
            foreach (DataPoint dp in dataPoints)
            {
                chart = dp.Chart as Chart;
                stopAngle = startAngle + Math.PI * 2 * Math.Abs(dp.InternalYValue) / totalSum;
                meanAngle = (startAngle + stopAngle) / 2;

                if (dp.LabelStyle == LabelStyles.Inside)
                {
                    meanAngle = CircularLabel.ResetMeanAngle(meanAngle);
                    PlaceLabelInside(dp, center, meanAngle, pieSize, referenceEllipseSize, scaleY, is3D);
                    startAngle = stopAngle; 
                    continue;
                }

                // if (meanAngle > Math.PI * 2) meanAngle -= Math.PI * 2;

                cLabel = new CircularLabel(dp.LabelVisual, center, meanAngle, xRadiusLabel, yRadiusLabel, xRadiusChart, yRadiusChart, visual);
                cLabel.Boundary = boundingArea;

                if (prevousLabel != null)
                    prevousLabel.NextLabel = cLabel;

                cLabel.PreviusLabel = prevousLabel;
                prevousLabel = cLabel;

                circularLabels.Add(cLabel);

                startAngle = stopAngle;
            }

            if (circularLabels.Count > 0)
            {   
                circularLabels[0].PreviusLabel = cLabel;
                cLabel.NextLabel = circularLabels[0];
                LabelPlacementHelper.CircularLabelPlacment(boundingArea, circularLabels, (chart != null) ? chart.SmartLabelEnabled : false);
            }
        }
        /// <summary>
        /// Rearrange the labels vertically
        /// </summary>
        /// <param name="labels">List of CircularLabels</param>
        /// <param name="leftOfArea">Left of the bounding area</param>
        /// <param name="topOfArea">Top of the bounding area</param>
        /// <param name="areaHeight">Height of the bounding area</param>
        /// <param name="areaWidth">Width of the bounding area</param>
        private static void RearrangeLabelsVertically(List <CircularLabel> labels, Double leftOfArea, Double topOfArea, Double areaHeight, Double areaWidth)
        {
            Rect[] labelInfo = new Rect[labels.Count];
            int    index     = 0;

            // Prepare label information into an array
            foreach (CircularLabel label in labels)
            {
                Double left = (Double)label.LabelVisual.GetValue(Canvas.LeftProperty);
                Double top  = (Double)label.LabelVisual.GetValue(Canvas.TopProperty);

                labelInfo[index++] = new Rect(left, top, label.LabelVisual.Width, label.LabelVisual.Height);
            }

            // Arrange the labels vertically
            LabelPlacementHelper.VerticalLabelPlacement(new Rect(leftOfArea, topOfArea, areaWidth, areaHeight), ref labelInfo);

            index = 0;

            // Update position of the labels
            foreach (CircularLabel label in labels)
            {
                Double top  = labelInfo[index].Top + topOfArea;
                Double left = labelInfo[index].Left;

                Double currentMeanAngle = label.CalculateAngleByYCoordinate(top);

                Double offset = 0;

                if (!Double.IsNaN(currentMeanAngle))
                {
                    currentMeanAngle = CircularLabel.ResetMeanAngle(currentMeanAngle);
                    label.Position   = label.GetCartesianCoordinates4Labels(currentMeanAngle);

                    if (left < label.Center.X)
                    {
                        left = label.Center.X - (label.Position.X - label.Center.X);
                        //left = areaWidth - label.Position.X - label.LabelVisual.Width;
                        //left = areaWidth - label.Position.X - (label.Center.X - left) + label.LabelVisual.Width;
                        //left = label.Center.X - (label.Position.X - label.Center.X) - label.LabelVisual.Width;
                    }
                    else
                    {
                        left = label.Position.X;
                    }

                    label.CurrentMeanAngle = currentMeanAngle;
                }


                // Move the labels towards left or right if space availlable
                //if ((label.BaseMeanAngle > 7 * Math.PI / 4 && label.BaseMeanAngle < Math.PI / 4
                //    || label.BaseMeanAngle > 3 * Math.PI / 2 && label.BaseMeanAngle < 5 * Math.PI / 4)
                if (top > (label.YRadiusLabel * 2) / 6 && top < 5 * (label.YRadiusLabel * 2) / 6)
                {
                    if (left < label.Center.X)
                    {
                        Double x = left - label.LabelVisual.Width;
                        if (x > 0)
                        {
                            offset = -x / 3;
                        }
                    }
                    else
                    {
                        Double x = areaWidth - (left + label.LabelVisual.Width);
                        if (x > 0)
                        {
                            offset = +x / 3;
                        }
                    }
                }

                label.Position = new Point(left + offset, top);

                label.UpdateLabelVisualPosition();
                //label.LabelVisual.SetValue(Canvas.LeftProperty, left); // );
                //label.LabelVisual.SetValue(Canvas.TopProperty, top);

                index++;
            }
        }
        /// <summary>
        /// Check whether two labels overlap. Also calculate the horizontal and vertical offsets 
        /// to overcome the overlap.
        /// </summary>
        /// <param name="labelInfo">Information of the label</param>
        /// <param name="verticalOffset">How much need to move vertically to overcome overlap</param>
        /// <param name="horizontalOffset">How much need to move horizontally to overcome overlap</param>
        /// <returns>OverlapTypes</returns>
        private OverlapTypes CheckOverlap(CircularLabel label, out Double verticalOffset, out Double horizontalOffset)
        {
            OverlapTypes retValue = OverlapTypes.None;  // Type of overlap
            verticalOffset = 0;     // How much need to move vertically to overcome overlap
            horizontalOffset = 0;   // How much need to move horizontally to overcome overlap

            CircularLabel A = this;
            CircularLabel B = label;

            if (B.Position.Y > A.Position.Y)
            {
                if (B.Position.Y < A.Position.Y + A.Height)
                {
                    // Calculate how much need to move vertically to overcome overlap
                    verticalOffset = A.Position.Y + A.Height - B.Position.Y;
                    retValue = OverlapTypes.Vertical;
                }
            }
            else if (A.Position.Y > B.Position.Y)
            {
                if (A.Position.Y < B.Position.Y + B.Height)
                {
                    // Calculate how much need to move vertically to overcome overlap
                    verticalOffset = B.Position.Y + B.Height - A.Position.Y;
                    retValue = OverlapTypes.Vertical;
                }
            }

            if (B.Position.X > A.Position.X)
            {
                if (B.Position.X < A.Position.X + A.Width)
                {
                    // Calculate how much need to move horizontally to overcome overlap
                    horizontalOffset = A.Position.X + A.Width - B.Position.X;
                    retValue = (retValue == OverlapTypes.Vertical) ? OverlapTypes.Both : OverlapTypes.Horizontal;
                }
            }
            else if (A.Position.X > B.Position.X)
            {
                if (A.Position.X < B.Position.X + B.Width)
                {
                    // Calculate how much need to move horizontally to overcome overlap
                    horizontalOffset = B.Position.X + B.Width - A.Position.X;
                    retValue = (retValue == OverlapTypes.Vertical) ? OverlapTypes.Both : OverlapTypes.Horizontal;
                }
            }

            return retValue;
        }
        /// <summary>
        /// Calculate vertical space available between two CircularLabels
        /// </summary>
        /// <param name="label1">CircularLabel A</param>
        /// <param name="label2">CircularLabel B</param>
        /// <returns>vertical space available between two CircularLabels</returns>
        private static Double VerticalSpcaeBetweenLabels(CircularLabel labelA, CircularLabel labelB)
        {
            Double gap = 0;

            if (labelA.Position.Y < labelB.Position.Y)
                gap = labelB.Position.Y - (labelA.Position.Y + labelA.Height);
            else
                gap = labelA.Position.Y - (labelB.Position.Y + labelB.Height);

            if (gap < 0)
                return 0;
            else
                return gap;
        }
        /// <summary>
        /// Ask for space to PreviusLabel B if it can leave the space inorder to overcome the overlap.
        /// PreviusLabel B asks for space to the previous label C.. and so on
        /// </summary>
        /// <param name="labelA">CircularLabel looking for space to overcome the overlap</param>
        private static Boolean AskSpaceToPreviusLabel(CircularLabel labelA, Double requiredVerticalOffset, Int32 noOfIteration)
        {
            Boolean retValue = true;
            Double gap = 0;
            if (labelA.IsFirst)
            {
                if (labelA.Position.Y > requiredVerticalOffset)
                {
                    retValue = labelA.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Counterclockwise);
                    return retValue;
                }
                else
                    return false;
            }

            gap = VerticalSpcaeBetweenLabels(labelA, labelA.PreviusLabel);

            if (gap > requiredVerticalOffset)
            {   
                retValue =labelA.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Counterclockwise);
                return retValue;
            }
            else
            {
                retValue = AskSpaceToPreviusLabel(labelA.PreviusLabel, requiredVerticalOffset, noOfIteration);
                if (retValue)
                {
                    retValue = labelA.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Counterclockwise);
                    return retValue;
                }
                else
                    retValue = false;
            }

            return retValue;
        }
        /// <summary>
        /// Ask for space to NextLabel if NextLabel can leave the space.
        /// NextLabel B asks for space to the next label C.. and so on
        /// </summary>
        /// <param name="labelA">CircularLabel looking for space to overcome the overlap</param>
        private static Boolean AskSpaceToNextLabel(CircularLabel label, Double requiredVerticalOffset, Int32 noOfIteration)
        {   
            Boolean retValue = true;
            Double gap = 0;
            if (label.IsLast)
            {   
                if (label.Position.Y + label.Height < label.Boundary.Height &&
                    label.Boundary.Height - (label.Position.Y + label.Height) > requiredVerticalOffset)
                {   
                    retValue = label.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Clockwise);
                    return retValue;
                }
                else
                    return false;
            }

            gap = VerticalSpcaeBetweenLabels(label, label.NextLabel);
            if (gap > requiredVerticalOffset)
            {
                retValue = label.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Clockwise);
                return retValue;
            }
            else
            {
                retValue = AskSpaceToNextLabel(label.NextLabel, requiredVerticalOffset, noOfIteration);
                if (retValue)
                {
                    retValue = label.RotateByVerticalOffset(requiredVerticalOffset, SweepDirection.Clockwise);
                    return retValue;
                }
                else
                    retValue = false;
            }

            return retValue;
        }