/// <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; } }