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

6 posts, 0 answers
  1. Borislav
    Borislav avatar
    17 posts
    Member since:
    Nov 2016

    Posted 21 Sep Link to this post

    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?

  2. Dess
    Admin
    Dess avatar
    2107 posts

    Posted 22 Sep Link to this post

    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.
  3. Borislav
    Borislav avatar
    17 posts
    Member since:
    Nov 2016

    Posted 4 days and 1 hour ago in reply to Dess Link to this post

    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.
  4. Borislav
    Borislav avatar
    17 posts
    Member since:
    Nov 2016

    Posted 3 days and 23 hours ago Link to this post

    If it's of importance, my x axis is CategoricalAxis.
  5. Borislav
    Borislav avatar
    17 posts
    Member since:
    Nov 2016

    Posted 2 days and 5 hours ago Link to this post

    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?
  6. Dess
    Admin
    Dess avatar
    2107 posts

    Posted 2 days and 4 hours ago Link to this post

    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.
Back to Top