How to reproduce:
private void UpdateChart()
{
this.radChartView1.Series.Clear();
// Create two series for the bar chart.
BarSeries requiredBarSeries = new BarSeries
{
ShowLabels = true,
CombineMode = ChartSeriesCombineMode.Cluster,
NumberOfColors = 2,
};
BarSeries actualBarSeries = new BarSeries
{
ShowLabels = true,
CombineMode = ChartSeriesCombineMode.Cluster,
NumberOfColors = 2,
};
// Add the data.
AddDataPoint(requiredBarSeries, .0333d, "Germany", "Required");
AddDataPoint(actualBarSeries, .050d, "Germany", "Actual");
AddDataPoint(requiredBarSeries, .0333d, "United States", "Required");
AddDataPoint(actualBarSeries, .050d, "United States", "Actual");
AddDataPoint(requiredBarSeries, .00d, "France", "Required");
AddDataPoint(actualBarSeries, .050d, "France", "Actual");
AddDataPoint(requiredBarSeries, 0.0d, "United Kingdom", "Required");
AddDataPoint(actualBarSeries, .050d, "United Kingdom", "Actual");
AddDataPoint(requiredBarSeries, 0.955d, "Russia", "Required");
// Change the following value to .95d to see
// the issue.
AddDataPoint(actualBarSeries, .15d, "Russia", "Actual");
this.radChartView1.Series.Add(requiredBarSeries);
this.radChartView1.Series.Add(actualBarSeries);
CategoricalAxis horizontalAxis = radChartView1.Axes[0] as CategoricalAxis;
horizontalAxis.LabelFitMode = AxisLabelFitMode.MultiLine;
}
private void AddDataPoint(BarSeries series, double val, string category, string label)
{
series.DataPoints.Add(new CategoricalDataPoint
{
Value = val,
Label = String.Format("{0}\n{1:P2}", label, val),
Category = category
});
}
Workaround: create a custom SmartLabelsController
public RadForm1()
{
InitializeComponent();
SmartLabelsController labelsController = new CustomSmartLabelsController();
this.radChartView1.Controllers.Add(labelsController);
// Set up the chart
}
public class CustomSmartLabelsController : SmartLabelsController
{
protected override SmartLabelsStrategyBase GetDefaultStrategy(ChartArea area)
{
SmartLabelsStrategyBase strategy = base.GetDefaultStrategy(area);
if (strategy is VerticalAdjusmentLabelsStrategy)
{
strategy = new CustomVerticalAdjusmentLabelsStrategy();
Dictionary<Type, List<Type>> strategies = typeof(SmartLabelsController).GetField("strategySeries", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(this) as Dictionary<Type, List<Type>>;
strategies.Remove(typeof(VerticalAdjusmentLabelsStrategy));
strategies.Add(typeof(CustomVerticalAdjusmentLabelsStrategy), new List<Type> { typeof(BarSeries), typeof(LineSeriesBase) });
}
return strategy;
}
}
public class CustomVerticalAdjusmentLabelsStrategy : VerticalAdjusmentLabelsStrategy
{
public override void CalculateLocations(ChartSeriesCollection series, Rectangle plotArea)
{
if (series.Count == 0)
{
return;
}
List<LabelElement> labels = new List<LabelElement>();
List<int> overlaps = new List<int>();
foreach (ChartSeries chartSeries in series)
{
if (!chartSeries.ShowLabels || !chartSeries.IsVisible)
{
continue;
}
foreach (DataPointElement point in chartSeries.Children)
{
LabelElement label = (LabelElement)point.Children[0];
Rectangle labelRect = ChartRenderer.ToRectangle(label.GetLayoutSlot());
labelRect.X += (int)(series[0].View.Viewport.X + ((IChartView)series[0].View).PlotOriginX);
labelRect.Y += (int)(series[0].View.Viewport.Y + ((IChartView)series[0].View).PlotOriginY);
if (chartSeries.View.GetArea<CartesianArea>().Orientation == Orientation.Vertical)
{
labelRect.Y -= this.DistanceToLabel;
}
else
{
labelRect.X += this.DistanceToLabel;
}
labelRect.Inflate(0, this.DistanceBetweenLabels);
label.SmartRectangle = labelRect;
labels.Add(label);
}
}
CartesianSeries cartesianSeries = (CartesianSeries)series[0];
if (cartesianSeries != null)
{
this.RestrictWithinAxes(labels, cartesianSeries);
}
LabelElement labelToMove = this.GetElementWithMostOverlaps(labels, series);
int counter = 0;
while (labelToMove != null && counter < labels.Count)
{
Rectangle firstDirectionRect;
Rectangle secondDirectionRect;
int firstMoveCost;
int secondMoveCost;
Rectangle dataPointLayout = ChartRenderer.ToRectangle(labelToMove.DataPoint.LayoutSlot);
dataPointLayout.X += (int)labelToMove.View.Viewport.X;
dataPointLayout.Y += (int)labelToMove.View.Viewport.Y;
if (cartesianSeries.View.GetArea<CartesianArea>().Orientation == System.Windows.Forms.Orientation.Vertical)
{
firstDirectionRect = this.GetBestPositionInUpwardDirection(labels, labelToMove, cartesianSeries);
secondDirectionRect = this.GetBestPositionInDownwardDirection(labels, labelToMove, cartesianSeries);
firstMoveCost = Math.Abs(labelToMove.SmartRectangle.Y - firstDirectionRect.Y);
secondMoveCost = Math.Abs(labelToMove.SmartRectangle.Y - secondDirectionRect.Y);
}
else
{
firstDirectionRect = this.GetBestPositionInLeftDirection(labels, labelToMove, cartesianSeries);
secondDirectionRect = this.GetBestPositionInRightDirection(labels, labelToMove, cartesianSeries);
firstMoveCost = Math.Abs(dataPointLayout.X - firstDirectionRect.X);
secondMoveCost = Math.Abs(dataPointLayout.X - secondDirectionRect.X);
}
if (!dataPointLayout.IntersectsWith(secondDirectionRect) && firstMoveCost > secondMoveCost)
{
labelToMove.SmartRectangle = secondDirectionRect;
}
else
{
labelToMove.SmartRectangle = firstDirectionRect;
}
labelToMove = this.GetElementWithMostOverlaps(labels, series);
counter++;
}
this.FinalPositionsOptimization(labels);
foreach (LabelElement label in labels)
{
Rectangle rect = label.SmartRectangle;
rect.Inflate(0, -this.DistanceBetweenLabels);
Rectangle dataPointLayout = ChartRenderer.ToRectangle(label.DataPoint.LayoutSlot);
dataPointLayout.X += (int)cartesianSeries.View.Viewport.X;
dataPointLayout.Y += (int)cartesianSeries.View.Viewport.Y;
int delta = 1;
if (dataPointLayout.Y > label.SmartRectangle.Y)
{
delta = -1;
}
rect.Y += delta * this.DistanceToLabel;
label.SmartRectangle = rect;
}
}
}