This is a migrated thread and some comments may be shown as answers.

Hide legend items for lines that are not visible in current zoom level

5 Answers 81 Views
ChartView
This is a migrated thread and some comments may be shown as answers.
Borislav
Top achievements
Rank 1
Borislav asked on 21 Sep 2017, 10:08 AM

Hi,

I am zooming to particular area of the ChartView. Depending on the zoom, some lines may not be visible in the current zoomed in portion of the chart. So, the legend is displaying items that are not currently visible in the chart. I need to display legend only for the lines that are visible in different zoom/pan settings. How to achieve this?

5 Answers, 1 is accepted

Sort by
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 22 Sep 2017, 11:44 AM
Hello, Borislav, 

Thank you for writing.  

You can iterate the ChartElement.LegendElement.StackElement.Children collection and show/hide the respective LegendItemElement according to your custom requirement. You can find below a sample code snippet demonstrating how to hide the chart legend items for series that are not visible in the chart:
public RadForm1()
{
    InitializeComponent();
 
    BarSeries barSeries = new BarSeries("Performance", "RepresentativeName");
    barSeries.LegendTitle = "Q1";
    barSeries.DataPoints.Add(new CategoricalDataPoint(177, "Harley"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(128, "White"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(143, "Smith"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(111, "Jones"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(118, "Marshall"));
    this.radChartView1.Series.Add(barSeries);
    BarSeries barSeries2 = new BarSeries("Performance", "RepresentativeName");
    barSeries2.LegendTitle = "Q2";
    barSeries2.DataPoints.Add(new CategoricalDataPoint(153, "Harley"));
    barSeries2.DataPoints.Add(new CategoricalDataPoint(141, "White"));
    barSeries2.DataPoints.Add(new CategoricalDataPoint(130, "Smith"));
    barSeries2.DataPoints.Add(new CategoricalDataPoint(88, "Jones"));
    barSeries2.DataPoints.Add(new CategoricalDataPoint(109, "Marshall"));
    this.radChartView1.Series.Add(barSeries2);
 
    this.radChartView1.ShowLegend = true;
}
 
private void radButton1_Click(object sender, EventArgs e)
{
    this.radChartView1.Series[0].IsVisible = !this.radChartView1.Series[0].IsVisible;
 
    foreach (LegendItemElement itemElement in this.radChartView1.ChartElement.LegendElement.StackElement.Children)
    {
        BarSeries s = itemElement.LegendItem.Element as BarSeries;
        if (s != null)
        {
            if (s.IsVisible)
            {
 
                itemElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
            }
            else
            {
            itemElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
            }
        }
    }
}

If you have any further questions feel free to submit a support ticket in the support ticketing system where threads are handled according to license and time of posting. Thank you for your understanding.

I hope this information helps. 

Regards,
Dess
Progress Telerik
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Borislav
Top achievements
Rank 1
answered on 18 Oct 2017, 04:22 PM
The solution you provided is not applicable to the situation I have, since all of my series have values on the whole x axis range. I believe this is why IsVisible is always true for all series. However, I want to hide labels in case a user has zoomed in somewhere on the chart where values of particular series are not visible in the current viewport, For example, current viewport has range between 20 and 40 on the y axis, and the series have values that are below 20, so they are not visible in the current viewport. I want to hide legend items for these series that are not visible in the current viewport.  How to achieve this? I hope my question is clear enough.
0
Borislav
Top achievements
Rank 1
answered on 18 Oct 2017, 06:21 PM
If it's of importance, my x axis is CategoricalAxis.
0
Borislav
Top achievements
Rank 1
answered on 20 Oct 2017, 12:33 PM
I narrowed problem to to checking if all of the categorical points of the series fall into visible range. Thing is that I didn't find of way of comparing the layout slot of the point with the layout slot of the chart. Regardless of the zoom level, layout slot of the chart has always fixed dimensions (1000 x 800), while the layout slot of the point depends on the zoom level so it can be anywhere in the range of (xZoomLevel * 1000)  X (yZoomLevel * 800) thus I cannot try to find intersection of the visible portion of the chart and categorical points. Do you have any suggestion on how to achieve this?
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 20 Oct 2017, 12:53 PM
Hello, Borislav,    

Thank you for writing back. 

I have prepared a sample code snippet demonstrating how to hide the legend items for series that are not visible in the zoomed view range: 
public RadForm1()
{
    InitializeComponent();
 
    BarSeries barSeries = new BarSeries("Performance", "RepresentativeName");
    barSeries.LegendTitle = "Q1";
    barSeries.DataPoints.Add(new CategoricalDataPoint(177, "Harley"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(128, "White"));
    this.radChartView1.Series.Add(barSeries);
    BarSeries barSeries2 = new BarSeries("Performance", "RepresentativeName");
    barSeries2.LegendTitle = "Q2";
    barSeries2.DataPoints.Add(new CategoricalDataPoint(130, "Smith"));
    barSeries2.DataPoints.Add(new CategoricalDataPoint(88, "Jones"));
    barSeries2.DataPoints.Add(new CategoricalDataPoint(109, "Marshall"));
    this.radChartView1.Series.Add(barSeries2);
 
    this.radChartView1.ShowLegend = true;
 
    ChartPanZoomController panZoomController = new ChartPanZoomController();
    panZoomController.PanZoomMode = ChartPanZoomMode.Horizontal;
    radChartView1.Controllers.Add(panZoomController);
 
    this.radChartView1.View.ZoomChanged += View_ZoomChanged;
    this.radChartView1.View.PanChanged += View_PanChanged;
}
 
void View_PanChanged(object sender, EventArgs e)
{
    UpdateLegentItems();
}
 
private void View_ZoomChanged(object sender, EventArgs e)
{
    UpdateLegentItems();
}
 
private void UpdateLegentItems()
{
    Dictionary<ChartSeries, int> visiblePoints = new Dictionary<ChartSeries, int>();
    IChartView view = ((IChartView)this.radChartView1.View);
    foreach (ChartSeries series in this.radChartView1.Series)
    {
        foreach (var dp in series.DataPoints)
        {
            CategoricalDataPoint cdp = (CategoricalDataPoint)dp;
            if (CheckIfDataPointIsVisible(view, cdp))
            {
                if (!visiblePoints.ContainsKey(series))
                {
                    visiblePoints.Add(series, 0);
                }
                visiblePoints[series]++;
            }
        }
    }
 
    //update the legend items considering the visible series
    foreach (LegendItemElement itemElement in this.radChartView1.ChartElement.LegendElement.StackElement.Children)
    {
        if (visiblePoints.ContainsKey(itemElement.LegendItem.Element as ChartSeries))
        {
            itemElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
        }
        else
        {
            itemElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
        }
    }
}
 
private bool CheckIfDataPointIsVisible(IChartView view, CategoricalDataPoint cdp)
{
    double width = ((ChartSeries)cdp.Presenter).Axes[1].Model.LayoutSlot.Width;
    RadRect viewport = new RadRect(-view.PlotOriginX + width, -view.PlotOriginY, view.ViewportWidth, view.ViewportHeight);
    return viewport.IntersectsWith(cdp.LayoutSlot);
}

Note that this is just a sample approach and it may not cover all possible cases. Feel free to modify it in a way which suits your requirement best.

I hope this information helps. If you have any additional questions, please let me know. 

 Regards,
Dess
Progress Telerik
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Tags
ChartView
Asked by
Borislav
Top achievements
Rank 1
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
Borislav
Top achievements
Rank 1
Share this question
or