FirstVisibleIndex and LastVisibleIndex while zooming

TeeChart for Microsoft Visual Studio .NET, Xamarin Studio (Android, iOS & Forms) & Monodevelop.
bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Fri Aug 09, 2019 6:45 am

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
Last edited by bairog on Tue Aug 13, 2019 6:14 am, edited 1 time in total.

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Fri Aug 09, 2019 8:28 am

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.
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Fri Aug 09, 2019 9:00 am

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.

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Fri Aug 09, 2019 11:23 am

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);
        }
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Fri Aug 09, 2019 11:49 am

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.

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Fri Aug 09, 2019 12:26 pm

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.
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Fri Aug 09, 2019 12:43 pm

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.

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Mon Aug 12, 2019 5:00 am

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..

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Mon Aug 12, 2019 8:05 am

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?
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Mon Aug 12, 2019 8:43 am

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.

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Mon Aug 12, 2019 8:56 am

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;
            }
        }
    }
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Mon Aug 12, 2019 9:05 am

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.

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Mon Aug 12, 2019 9:34 am

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.
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

bairog
Advanced
Posts: 128
Joined: Fri Dec 07, 2018 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by bairog » Mon Aug 12, 2019 10:55 am

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?

Christopher
Guru
Posts: 1603
Joined: Fri Nov 15, 2002 12:00 am

Re: FirstVisibleIndex and LastVisibleIndex while zooming

Post by Christopher » Mon Aug 12, 2019 11:41 am

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;
Best Regards,
Christopher Ireland / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Instructions - How to post in this forum

Post Reply