Page 1 of 2

FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 6:45 am
by 15685014
Hello.
I'm using TeeChart Pro 4.2019.8.8 and I need to determine indexes of the first and last point that are visible to user. I'm using line1.FirstVisibleIndex and line1.LastVisibleIndex, but it gives me strange values. I use non-historical horizontal zoom.
First zoom:
Image
Second zoom:
Image
Third Zoom:
Image
Undone zoom:
Image
Undone zoom again (values changed!!!):
Image

I've uploaded test app here

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 8:28 am
by Christopher
Hello!

rather than using the Zoomed and UndoneZoom events, have you tried using the AfterDraw events?

Code: Select all

        private void TChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
        {
            Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";
        }

        private void TChart1_Zoomed(object sender, EventArgs e)
        {
            //Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";
        }

        private void TChart1_UndoneZoom(object sender, EventArgs e)
        {
            //Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";
        }
Here this works much better.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 9:00 am
by 15685014
Christopher wrote:
Fri Aug 09, 2019 8:28 am
rather than using the Zoomed and UndoneZoom events, have you tried using the AfterDraw events?Here this works much better.
For unzoomed chart both values are correct:
Image
But for zoomed chart LastVisibleIndex returns correct_value + 1:
Image
Image
Image

P. S. I'm drawing custom labels for bottom axis (label text is long - so I need to perform labels thinning). So I need to clear all current labels (30 for example) and add some custom labels (10 for example). And looks like AfterDraw event does't suitable for that -tChart.Axes.Labels.Items.Count in debugger doesn't correspond to number of labels that I see on a screen aftewards.
I've uploaded sample application here.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 11:23 am
by Christopher
Hello!

Okay - first off, LastVisibleIndex is one off in LIne series because the line itself is considered as belonging to the next point - so, for example, if you scroll the chart so there's only one point visible, the visible part of the line which continues to the next point (which isn't visible) causes LastVisibleIndex to be one and not zero.

As for the events, you can use BeforeDraw for the Labels and AfterDraw for the Text and this will save you having to zoom out twice to get the correct labels, e.g.

Code: Select all

        private void TChart1_BeforeDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
        {
            //Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";

            DrawLabels(maxDisplayedLabelsForBottomaAxis);
        }

        private void TChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
        {
            Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";

            //DrawLabels(maxDisplayedLabelsForBottomaAxis);
        }

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 11:49 am
by 15685014
Christopher wrote:
Fri Aug 09, 2019 11:23 am
Okay - first off, LastVisibleIndex is one off in LIne series because the line itself is considered as belonging to the next point - so, for example, if you scroll the chart so there's only one point visible, the visible part of the line which continues to the next point (which isn't visible) causes LastVisibleIndex to be one and not zero.
Ok, I got it.
Christopher wrote:
Fri Aug 09, 2019 11:23 am
As for the events, you can use BeforeDraw for the Labels and AfterDraw for the Text and this will save you having to zoom out twice to get the correct labels
If I use BeforeDraw event - I have FirstVisibleIndex=0 and LastVisibleIndex=line1.Count after the first zoom. After the second zoom FirstVisibleIndex and LastVisibleIndex have values of the first zoom and so on. That makes impossible to calculate currently visible points inside DrawLabels function and it is working incorrectly.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 12:26 pm
by Christopher
bairog wrote:
Fri Aug 09, 2019 11:49 am
If I use BeforeDraw event - I have FirstVisibleIndex=0 and LastVisibleIndex=line1.Count after the first zoom. After the second zoom FirstVisibleIndex and LastVisibleIndex have values of the first zoom and so on. That makes impossible to calculate currently visible points inside DrawLabels function and it is working incorrectly.
I can't see that it's working incorrectly - using this slightly modified version of your example:

Code: Select all

            //DrawLabels(maxDisplayedLabelsForBottomaAxis);

            tChart1.BeforeDraw += TChart1_BeforeDraw;
        }

        private void TChart1_BeforeDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
        {
            //Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";

            DrawLabels(maxDisplayedLabelsForBottomaAxis);
        }

        private void TChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
        {
            Text = $"FirstVisibleIndex: {line1.FirstVisibleIndex}, LastVisibleIndex: {line1.LastVisibleIndex}";

            //DrawLabels(maxDisplayedLabelsForBottomaAxis);
        }
I obtain the following (the zoom rectangle is an artefact of the gif):

Image

I can't see what is working incorrectly here.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Fri Aug 09, 2019 12:43 pm
by 15685014
Christopher wrote:
Fri Aug 09, 2019 12:26 pm
I can't see what is working incorrectly here.
When you zoom in first time and number of currently displayed points is lower than 20 (in your gif from point 11 to point 19) every label on bottom axis should be drawn (because 19 - 11 < 20). In your gif every second label is drawn. That is because of incorrect FirstVisibleIndex and LasVisibleIndex values.
The logic is simple - labels are thinned to maximum 20 labels simultaneously visible.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 5:00 am
by 15685014
Once again: I want to avoid labels overlapping on bottom axis and ensure two adjacent labels have a free space between them. So labels are thinned to maximum 20 labels simultaneously visible.

As I can see from my experiments:
In BeforeDraw event FirstVisibleIndex/LastVisibleIndex have incorrect values (FirstVisibleIndex=0 and LastVisibleIndex=line1.Count after the first zoom; after the second zoom FirstVisibleIndex and LastVisibleIndex have values of the first zoom and so on) but I can manipulate labels.
In AfterDraw event FirstVisibleIndex/LastVisibleIndex have correct values but I cannot manipulate labels (clear/add has no effect).

So the only workaround that I see is the following (force redraw after initial draw + drawing custom labels on redraw):

Code: Select all

private Boolean FirstAndLastVisibleIndexesAreCorrect = true;

private void TChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
     if (!FirstAndLastVisibleIndexesAreCorrect)
          tChart1.Refresh();
}
private void TChart1_BeforeDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
     FirstAndLastVisibleIndexesAreCorrect = !FirstAndLastVisibleIndexesAreCorrect;

     if (FirstAndLastVisibleIndexesAreCorrect)
          DrawLabels(maxDisplayedLabelsForBottomaAxis);
}
That workaround archeives the goal but it's very bad (hits performance and maybe have some other side effects).
Moreover labels are not fully visible - chart isn't recalculating vertical space that is needed to draw bottom axis labels for some reason:
Image
The only workaround is to use the following code (draw labels every time):

Code: Select all

private Boolean FirstAndLastVisibleIndexesAreCorrect = true;

private void TChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
     if (!FirstAndLastVisibleIndexesAreCorrect)
          tChart1.Refresh();
}
private void TChart1_BeforeDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
     FirstAndLastVisibleIndexesAreCorrect = !FirstAndLastVisibleIndexesAreCorrect;

     DrawLabels(maxDisplayedLabelsForBottomaAxis);
}
But it hits performance even worse because my custom labels are drawn on initial draw and on force redraw.
I've uploaded sample app here

BTW: long time ago in TeeChart V2 I was successfully using Zoomed/UndoneZoom/Scroll events to obtain FirstVisibleIndex/LastVisibleIndexand draw my custom labels. Now in TeeChart V4 inside that events FirstVisibleIndex/LastVisibleIndex have incorrect values.

To sum up: to draw custom labels depending on first and last visible points it is vital to have an event with correct FirstVisibleIndex/LastVisibleIndex and which allows to manipulate labels. Some time ago it was Zoomed/UndoneZoom/Scroll, but now it's not working. Maybe you can repair them?

P. S. If there is enother way to ensure two adjacent labels have a free space between them (e. g. tChart1.Axes.Bottom.Labels.Space = 10) - any help will be appreciated..

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 8:05 am
by Christopher
bairog wrote:
Mon Aug 12, 2019 5:00 am
P. S. If there is enother way to ensure two adjacent labels have a free space between them (e. g. tChart1.Axes.Bottom.Labels.Space = 10) - any help will be appreciated..
One alternative is this:

Code: Select all

    public partial class Form1 : Form
    {
        //max visible labels
        private const Int32 maxDisplayedLabelsForBottomaAxis = 20;
        //list of customa labels
        private List<String> Labels = new List<string>();

        public Form1()
        {
            var rnd = new Random();

            InitializeComponent();

            tChart1.Axes.Bottom.GetAxisDrawLabel += Bottom_GetAxisDrawLabel;

            tChart1.Axes.Bottom.Labels.Style = Steema.TeeChart.AxisLabelStyle.Text;

            for (int i = 0; i < 30; i++)
            {
                //adding points
                line1.Add(i, rnd.Next(5));

                //adding custom labels
                Labels.Add($"Point #{i}");
            }

            line1.Labels.AddRange(Labels);
        }

        private void Bottom_GetAxisDrawLabel(object sender, Steema.TeeChart.GetAxisDrawLabelEventArgs e)
        {
            if((line1.LastVisibleIndex - line1.FirstVisibleIndex) > maxDisplayedLabelsForBottomaAxis)
            {
                var label = int.Parse(e.Text.Last().ToString());
                e.DrawLabel = label % 2 == 0;
            }
            else
            {
                e.DrawLabel = true;
            }
        }
    }
How does that work for you?

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 8:43 am
by 15685014
Christopher wrote:
Mon Aug 12, 2019 8:05 am
How does that work for you?
Looks like DrawAxisLabel event is forking fine.
But what is my labels are not like Point #{i}, but like First point, Second point, etc..
In that case i cannot rely on:

Code: Select all

var labelIndex = int.Parse(e.Text.Last().ToString())
How can I determine labelIndex inside DrawAxisLabel event? I've tried e.LabelValue - but it is always 0 in my case..

BTW. At least Steema.TeeChart.NET nuget package (and I suppose all others too) doesn't have *.xml files inside. It's really hard to use your libraries on machines with no internet connection. Many developers prefer to have XML-comments right in their IDE. It's a real pain to guess what are the differences for example between CalcPosPoint or CalcPosValue or CalcXPosValue. Suppose it will not be a big problem to generate XML-documentation and add it to nuget package on every build automatically. Thank you in advance.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 8:56 am
by Christopher
bairog wrote:
Mon Aug 12, 2019 8:43 am
How can I determine labelIndex inside DrawAxisLabel event? I've tried e.LabelValue - but it is always 0 in my case..
Well, you could check the incoming Text with the Labels collection you already have, e.g.

Code: Select all

    public partial class Form1 : Form
    {
        //max visible labels
        private const Int32 maxDisplayedLabelsForBottomaAxis = 20;
        //list of customa labels
        private List<String> Labels = new List<string>();

        public Form1()
        {
            var rnd = new Random();

            InitializeComponent();

            tChart1.Axes.Bottom.GetAxisDrawLabel += Bottom_GetAxisDrawLabel;

            tChart1.Axes.Bottom.Labels.Style = Steema.TeeChart.AxisLabelStyle.Text;

            for (int i = 0; i < 30; i++)
            {
                //adding points
                line1.Add(i, rnd.Next(5));

                //adding custom labels
                Labels.Add($"Point NoClue #{rnd.Next()}");
            }

            line1.Labels.AddRange(Labels);
        }

        private void Bottom_GetAxisDrawLabel(object sender, Steema.TeeChart.GetAxisDrawLabelEventArgs e)
        {
            if((line1.LastVisibleIndex - line1.FirstVisibleIndex) > maxDisplayedLabelsForBottomaAxis)
            {
                var label = Labels.IndexOf(e.Text);
                e.DrawLabel = label % 2 == 0;
            }
            else
            {
                e.DrawLabel = true;
            }
        }
    }

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 9:05 am
by 15685014
Christopher wrote:
Mon Aug 12, 2019 8:56 am
Well, you could check the incoming Text with the Labels collection you already have, e.g.
Well, not so elegant as I thought - I supposed I can use something like

Code: Select all

(sender as Steema.TeeChart.Axis).CalcXXXXValue(e.X)
And now I cannot dispose that Labels collection until my application closes. But it's working now, thank you :)

P. S. As I wrote above - missing *.XML files in your nuget packages is a real pain, add them please. If in addition you can also add offline variant for http://www.teechart.net/docs/TeeChartNETReference.htm - it will be even better (nuget package already has TeeChart_Pro_Net_Tutorials.chm, why not to add TeeChart_Pro_Net_Library_Reference.chm as well). Many thanks in advance.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 9:34 am
by Christopher
bairog wrote:
Mon Aug 12, 2019 9:05 am
And now I cannot dispose that Labels collection until my application closes.
You don't have to use the Labels collection, unless you want to. I've also modded the code so scrolling doesn't draw every label when less than 20 labels are shown:

Code: Select all

    public partial class Form1 : Form
    {
        //max visible labels
        private const Int32 maxDisplayedLabelsForBottomaAxis = 20;

        public Form1()
        {
            var rnd = new Random();

            InitializeComponent();

            tChart1.Axes.Bottom.GetAxisDrawLabel += Bottom_GetAxisDrawLabel;

            tChart1.Axes.Bottom.Labels.Style = Steema.TeeChart.AxisLabelStyle.Text;

            for (int i = 0; i < 30; i++)
            {
                //adding points
                line1.Add(i, rnd.Next(5), $"Point NoClue #{rnd.Next()}");
            }
        }

        private void Bottom_GetAxisDrawLabel(object sender, Steema.TeeChart.GetAxisDrawLabelEventArgs e)
        {
            if(tChart1.Zoom.Zoomed)
            {
                if ((line1.LastVisibleIndex - line1.FirstVisibleIndex) > maxDisplayedLabelsForBottomaAxis)
                {
                    var label = line1.Labels.IndexOf(e.Text);
                    e.DrawLabel = label % 2 == 0;
                }
                else
                {
                    e.DrawLabel = true;
                }
            }
            else
            {
                var label = line1.Labels.IndexOf(e.Text);
                e.DrawLabel = label % 2 == 0;
            }
        }
    }
bairog wrote:
Mon Aug 12, 2019 9:05 am
Many thanks in advance.
Okay, I've added this issue to our issue tracker with id=2225, which means your request will be considered for inclusion in future releases.

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 10:55 am
by 15685014
Unfortunatelly I'm here again..
In fact instead of your code:

Code: Select all

if ((line1.LastVisibleIndex - line1.FirstVisibleIndex) > maxDisplayedLabelsForBottomaAxis)
{      
   var label = line1.Labels.IndexOf(e.Text);
   e.DrawLabel = label % 2 == 0; 
}
I'm using:

Code: Select all

if ((line1.LastVisibleIndex - line1.FirstVisibleIndex) > maxDisplayedLabelsForBottomaAxis)
{
   var drawEvery = ((line1.LastVisibleIndex - 1 - line1.FirstVisibleIndex) / maxDisplayedLabelsForBottomaAxis) + 1;
   var label = line1.Labels.IndexOf(e.Text);
   e.DrawLabel = label % drawEvery == 0;
}
With it I draw every point if there are <=20 currently visible points; draw every 2nd point - if there are 20<x<=40 currently visible points; draw every 3rd point - if there are 40<x<=60 currently visible points, etc.
That code was working for 30 points in a line, but when I've tried to add 50 points - looks like chart started automatically performing thinning (I've commented Bottom_GetAxisDrawLabel function here):
Image
So GetAxisDrawLabel fired not 50 times, but only 25 (only for visible labels).
And if I uncomment Bottom_GetAxisDrawLabel function - extra thinning is performed by it (it draws every 3rd label but among already thinned labels):
Image
So how to deal with that? Is there a way to disable automatic thinning that is performed by chart itself?

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Posted: Mon Aug 12, 2019 11:41 am
by Christopher
bairog wrote:
Mon Aug 12, 2019 10:55 am
So how to deal with that? Is there a way to disable automatic thinning that is performed by chart itself?
Try setting the Labels separation to zero, e.g.

Code: Select all

            tChart1.Axes.Bottom.Labels.Separation = 0;
            tChart1.Axes.Bottom.Labels.Style = Steema.TeeChart.AxisLabelStyle.Text;