I have a problem with custom labels on x axis. If I add points [10;1][20;2][30;3][40;4][50;5][60;6][70;7][80;8][90;9] without labels, the x axis looks like this:
If I add them with labels [10;1;A][20;2;B][30;3;C][40;4;D][50;5;E][60;6;F][70;7;G][80;8;H][90;9;I] I get this:
If I change the points to [100;1][200;2][300;3][400;4][500;5][600;6][700;7][800;8][900;9] I get:
If I add labels [100;1;A][200;2;B][300;3;C][400;4;D][500;5;E][600;6;F][700;7;G][800;8;H][900;9;I] I get:
I tried to add labels with points using Add(double x, double y, string text)
and also using DataSource
and LabelMember
- same result with both. As you can see there are all numbers so there should be no problem to show there all labels (there are actually half the number of labels then visible numbers in both cases).
As you can see there is also different number of labels visible based on the actual difference between the numbers - if the difference is 10 it shows me 2 labels and some ticks, but if the difference is 100 there is only the first label without any other labels or even ticks.
If the difference is 1 I can see all custom labels (on this axis width).
For this example I used this code:
var serie = new Line(tChart1.Chart);
for (var i = 1; i < 10; i++)
{
serie.Add(i * 10, i, ((char)(64 + i)).ToString()); //points with labels
//serie.Add(i * 10, i); //points without labels
}
EDIT
I tried GetAxisLabels
event, but it is fired only for labels which are already shown so I am not able to change if I want to show more labels.
I also tried to add labels to the bottom axis manually, but if the labels are wide enough, they start to overlap, so I tried codes from here and after some modifications it works. Somehow. Because, it works only if I don't use the zoom feature. And I have to use the zoom so it is not good for me. I try to make some more modifications but it will be really ugly code for something like this...
I finally found some solution which works for everything I need. Not completely as I wanted, but somehow...
I need to process only bottom axis, so I took the code from johnk and change it to my needs.
I removed comparison with the next label and also change the way, how I find the correct label index.
There are some unpleasant problems with TeeChart
(for example the labels use different Font
than I would expect - tChart1.Graphics3D.Font
instead of axis.Labels.Font
- and the e.LabelValue
is always 0). So if you would like to make some changes, please keep in mind these problems. Below is my, not perfect but more or less working, solution:
Limitations
Features
Code
Helper dictionary
//Label index and true, if the label is visible.
private Dictionary<int, bool> _visibleLabels = new Dictionary<int, bool>();
Resetting the dictionary
private void TChart1_BeforeDrawAxes(object sender, Graphics3D g)
{
//Clear shown labels before showing axis.
_visibleLabels.Clear();
}
Selecting visible labels
private void GetAxisDrawLabel(object sender, GetAxisDrawLabelEventArgs e)
{
bool overlapPrv = false;
Axis axis = (Axis)sender;
//Get the size of the label text. We have to use tcharts font, not axis font.
SizeF currentSize = tChart1.Graphics3D.MeasureString(tChart1.Graphics3D.Font, e.Text);
Rectangle currentRect = new Rectangle(e.X - 3, e.Y, (int)currentSize.Width + 6, (int)currentSize.Height);
var index = FindLabel(tChart1.Axes.Bottom.Labels.Items, e.Text);
//Get the AxisLabelItem we are trying to draw.
AxisLabelItem currentLabel = axis.Labels.Items[index];
//If we set visible to false before GetAxisDrawLabel then set e.DrawLabel to false.
if (currentLabel.Visible == false)
{
_visibleLabels.Add(index, false);
e.DrawLabel = false;
}
//Get the previous visible label.
AxisLabelItem prev = null;
var prevPair = _visibleLabels.LastOrDefault(x => x.Value == true);
var prevIndex = -1;
if (prevPair.Value)
{
prevIndex = prevPair.Key;
tChart1.Axes.Bottom.Grid.DrawEvery = index - prevIndex;
}
else
{
//Current label is the first visible label.
_visibleLabels.Add(index, true);
e.DrawLabel = true;
return;
}
if (prevIndex >= 0)
{
prev = axis.Labels.Items[prevIndex];
}
//If this axis is horizontal then the concern is the width of the label.
//If there is no previous label, we draw this one.
//TODO implementation for the vertical.
if (axis.Horizontal == true && prev != null)
{
//if previous is visible we need to see if it will overlap with the current.
if (prev.Visible == true)
{
//Get the previous labels text size.
SizeF prevSize = tChart1.Graphics3D.MeasureString(tChart1.Graphics3D.Font, prev.Text);
//Get the previous label rectangle.
Rectangle prvRect = new Rectangle(
axis.CalcXPosValue(prev.Value) - 3, e.Y, (int)prevSize.Width + 6, (int)prevSize.Height);
//Set the overlapPrv flag by checking IntersectsWith
overlapPrv = currentRect.IntersectsWith(prvRect);
}
//if any overlap or if e.DrawLabel is false set e.DrawLabel to false.
if (overlapPrv || e.DrawLabel == false)
{
_visibleLabels.Add(index, false);
e.DrawLabel = false;
}
else
{
_visibleLabels.Add(index, true);
}
}
}
Finding the correct label index
private static int FindLabel(AxisLabelsItems items, string labelText)
{
for (var i = 0; i < items.Count; i++)
{
if (items[i].Text == labelText)
{
return i;
}
}
return -1;
}