Пример #1
0
        /// <summary>
        /// We know which labels are overlapping the data points, but we need to make sure the labels that will be
        /// displayed can fit in the scale using the Min/MaxGrace properties and adjusting the label fractions if appropriate:
        /// TextObjs with CoordType.AxisXYScale coordinates will move proportionally with Min/MaxGrace, but ChartFraction
        /// coordinates will not.
        /// </summary>
        protected void autoScaleForManualLabels(Graphics g)
        {
            Axis yAxis   = YAxis;
            bool maxAuto = yAxis.Scale.MaxAuto;

            try
            {
                if (maxAuto)
                {
                    AxisChange(g);
                }

                double yMaxRequired = 0;
                foreach (var kvp in _manualLabels)
                {
                    TextObj text = kvp.Key;
                    if (text.Location.X < XAxis.Scale.Min || text.Location.X > XAxis.Scale.Max)
                    {
                        continue;
                    }

                    if (!YAxis.Scale.IsLog && !IsYChartFractionObject(text))
                    {
                        double axisHeight = YAxis.Scale.Max - YAxis.Scale.Min;

                        PointF[] pts = text.FontSpec.GetBox(g, text.Text, 0, 0, text.Location.AlignH, text.Location.AlignV, 1.0f,
                                                            new SizeF());
                        float pixelShift = 0;
                        var   rectPeak   = _labelBoundsCache.GetLabelBounds(text, this, g);
                        foreach (var id in _manualLabels.Keys.Where(IsYChartFractionObject))
                        {
                            var rectID = _labelBoundsCache.GetLabelBounds(id, this, g);

                            // If the rectangles overlap
                            if (Math.Min(rectID.Right, rectPeak.Right) - Math.Max(rectID.Left, rectPeak.Left) > 0 &&
                                Math.Min(rectID.Bottom, rectPeak.Bottom) - Math.Max(rectID.Top, rectPeak.Top) > 0)
                            {
                                pixelShift = Math.Max(rectID.Height + 7, pixelShift);   // 7 pixel gap between labels
                            }
                        }
                        double y2Pos       = yAxis.Scale.ReverseTransform(pts[2].Y);
                        double labelHeight =
                            Math.Abs(yAxis.Scale.ReverseTransform(pts[0].Y - pixelShift) - y2Pos);
                        // If separating the labels takes too much space, just revert to showing them aligned
                        if (labelHeight >= axisHeight / 2)
                        {
                            labelHeight = Math.Abs(yAxis.Scale.ReverseTransform(pts[0].Y) - y2Pos);
                        }

                        if (labelHeight < axisHeight / 2)
                        {
                            // Ensure that the YAxis will have enough space to show the label.
                            // Only do this if the labelHeight is going to take up less than half the space on the graph, because
                            // otherwise the graph will be shrunk too much to have any useful information.

                            // When calculating the scaling required, take into account that the height of the label
                            // itself will not shrink when we shrink the YAxis.
                            var labelYMaxRequired = (text.Location.Y - labelHeight * YAxis.Scale.Min / axisHeight) /
                                                    (1 - labelHeight / axisHeight);
                            yMaxRequired = Math.Max(yMaxRequired, labelYMaxRequired);
                        }
                    }

                    if (!GraphObjList.Any(
                            o =>
                            (o is TextObj) && ((TextObj)o).Location == text.Location &&
                            ((TextObj)o).Text == text.Text))
                    {
                        if (_pointAnnotations.Contains(text))
                        {
                            GraphObjList.Add(text);
                        }
                    }
                }

                if (maxAuto && yMaxRequired > 0)
                {
                    yAxis.Scale.Max = Math.Max(yAxis.Scale.Max, yMaxRequired);
                }
            }
            finally
            {
                // Reset the value of MaxAuto since it may have been changed to false when Scale.Max was changed.
                yAxis.Scale.MaxAuto = maxAuto;
            }
        }