Displaying a Subset of Data Points / Horizontal Scrolling

3 posts, 0 answers
  1. Nicholas
    Nicholas avatar
    1 posts
    Member since:
    Apr 2019

    Posted 10 May Link to this post

    Hello,

    I'm working on a stacked bar chart for a client project and running into a bit of a snag with the amount of data being displayed in the chart. Below is a summary of the requirements I need to meet:

    1. Each series is to contain twenty-four data points, one for each hour of the day (0-23)
    2. A total of three separate series are to be rendered as a stacked bar chart
    3. The chart shall initially display the seven hours closest to the current time of the user's device for the selected day
    4. Horizontal scrolling shall be used to view remaining hours of the selected day

    To add some clarity to point (3) above, if the current time is 5 PM, the chart needs to display data for 2 PM, 3 PM, 4 PM, 5 PM, 6 PM, 7 PM, and 8 PM. If the current time is 10 PM it'll display 5 PM, 6 PM, 7 PM, 8 PM, 9 PM, 10 PM and 11 PM.

    I've seen this feature referred to as "Autoscrolling" by other UI toolkits for Xamarin Forms. How would I go about implementing this using Telerik UI?

  2. Lance | Team Lead - US DevTools Support
    Admin
    Lance | Team Lead - US DevTools Support avatar
    1047 posts

    Posted 14 May Link to this post

    Hi Nicholas,

    The Xamarin.Forms Chart control has support for panning and zooming using the PanAndZoomBehavior with PanMode and ZoomMode set to Horizontal. However, these  can only be set by user gestures.

    At this time there is no programmatic way to set the precise zoom and pan amount from Xamarin.Forms.


    Custom Development Using Native Control Features

    You can access the native controls that get rendered on the platforms by our Platform Renderer using a Xamarin.Forms custom renderer, see the article on registering custom renderers.

    An alternative approach is to access native controls using a new Xamarin feature called Xamarin.Forms Effects, see Microsoft's documentation on how to use Platform Effect. If you would like to be able to pass a value from the Xamarin.Forms project, you can easily pass parameters to an effect.

    With access to the native control, you can manually set each platform's specific usage of the manipulation of the canvas area.

    iOS - You can set the XAxis.Pan and XAxis.Zoom values on the axis, see the native TKChartView Pan documentation
    UWP - You can use the ChartBase to set ScrollOffset and Zoom
    Android - You can use the SetPanOffset and SetZoom methods


    Custom Implementation

    If you would like to move forward and try the native approach, I can give you a good head start. Please note that the code below is not production ready and will require experimentation and testing in your scenario to get the exact results you want. Additionally, I strongly recommend first reviewing the above Effect articles I linked to above so that you know where to put the following classes.

    Okay, let's get started...


    Routing Effect

    In the XF project, you can have the Routing Effect class defined with 3 parameters. This is because all three platforms have different ways to set the values. However, you could just have one and do the conversion to the native platform type in the platform's Effect.

    using Xamarin.Forms;
     
    // ReSharper disable InconsistentNaming
    namespace PanAndZoomDemo.Portable.Effects
    {
        public class PanEffect : RoutingEffect
        {
            public PanEffect() : base($"MyCompany.{nameof(PanEffect)}")
            {
     
            }
     
            public double NormalizedPan_iOS { get; set; }
     
            public double ScrollOffsetX_Uwp { get; set; }
     
            public double PanXOffset_Android { get; set; }
     
            public double ZoomLevel { get; set; }
        }
    }

    Important Note: In order for Pan to even work, there must be an initial amount of Zoom applied (otherwise, there is nothing to pan to). In this case, I have added a ZoomLevel property to the effect.

    With that defined, you can apply the Effect to the chart instance and set the experiment values:

    <telerikChart:RadCartesianChart x:Name="Chart">
        <telerikChart:RadCartesianChart.ChartBehaviors>
            <telerikChart:ChartPanAndZoomBehavior PanMode="Horizontal"  ZoomMode="Horizontal"/>
        </telerikChart:RadCartesianChart.ChartBehaviors>
        <telerikChart:RadCartesianChart.Effects>
            <effects:PanEffect ZoomLevel="2" NormalizedPan_iOS="4" ScrollOffsetX_Uwp="-1" PanXOffset_Android="-1" />
        </telerikChart:RadCartesianChart.Effects>
        ...
    </telerikChart:RadCartesianChart>


    iOS Platform Effect

    Now, in the iOS Platform Effect class, retrieve the values from the Routing Effect and apply them to the native control

    using System;
    using System.Linq;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.iOS;
     
    [assembly: ResolutionGroupName("MyCompany")]
    [assembly: ExportEffect(typeof(PanAndZoomDemo.iOS.Effects.PanEffect), nameof(PanAndZoomDemo.iOS.Effects.PanEffect))]
    namespace PanAndZoomDemo.iOS.Effects
    {
        public class PanEffect : PlatformEffect
        {
            protected override void OnAttached()
            {
                try
                {
                    // this.Control is the native component
                    // TKChartAxis exposes two properties dedicated to control the pan level of the axis - "Pan" and "NormalizedPan".
                    // See https://docs.telerik.com/devtools/xamarin/nativecontrols/ios/chart/zoom-and-pan for more info
     
                    if (this.Control is TelerikUI.TKChart chart &&
                        Element.Effects.FirstOrDefault() is PanAndZoomDemo.Portable.Effects.PanEffect effect)
                    {
                        // Set the zoom level to 2x
                        chart.XAxis.AllowZoom = true;
                        chart.XAxis.Zoom = effect.ZoomLevel;
     
                        // Set this with the value passed form the RoutingEffect class
                        chart.XAxis.AllowPan = true;
                        chart.XAxis.Pan = effect.NormalizedPan_iOS;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
     
            protected override void OnDetached()
            {
            }
        }
    }


    Runtime

    In my test, I have 10 categories, so there will be 10 X-axis positions. Setting the normalized Pan to 4, the chart loaded at the 5th position on the axis:




    UWP Platform Effect

    The ChartBase class has a couple helpful properties we can use. Please take a moment to review Zoom and ScrollOffset property descriptions in the Properties documentation, this is critical to understanding what values to use.

    using System;
    using System.Linq;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.UWP;
     
    [assembly: ResolutionGroupName("MyCompany")]
    [assembly: ExportEffect(typeof(PanAndZoomDemo.UWP.Effects.PanEffect), nameof(PanAndZoomDemo.UWP.Effects.PanEffect))]
    namespace PanAndZoomDemo.UWP.Effects
    {
        public class PanEffect : PlatformEffect
        {
            protected override void OnAttached()
            {
                try
                {
                    // Control is the native component
                    if (this.Control is Telerik.UI.Xaml.Controls.Chart.RadCartesianChart chart &&
                        Element.Effects.FirstOrDefault() is PanAndZoomDemo.Portable.Effects.PanEffect effect)
                    {
                        // Please visit this article first: https://docs.telerik.com/devtools/universal-windows-platform/controls/radchart/properties#properties-and-configuration
     
                        //Zoom (Size): Gets or sets the current zoom (scale) of the chart.
                        chart.Zoom = new Windows.Foundation.Size(effect.ZoomLevel, 1);
     
                        // ScrollOffset (Point): Gets or sets the origin used to calculate the arrange box of the chart area. The value is in units relative to the viewport size.
                        // For example value of (-1, 0) will scroll the chart scene to the left with the width of the viewport.
                        chart.ScrollOffset = new Windows.Foundation.Point(effect.ScrollOffsetX_Uwp, 0);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
     
            protected override void OnDetached()
            {
            }
        }
    }


    Runtime

    If you go back to the XAML, you'll see that I set the UWP pan to -1, this will shift the axis exactly one viewport-width over. Since I set the zoom level to 2x, this represents exactly half of the viewable area and should start at exactly halfway.. the "Six" category.



    Android Platform Effect

    Android has two methods you can use: SetZoom and SetPanOffset

    using System;
    using System.Linq;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
     
    [assembly: ResolutionGroupName("MyCompany")]
    [assembly: ExportEffect(typeof(PanAndZoomDemo.Android.Effects.PanEffect), nameof(PanAndZoomDemo.Android.Effects.PanEffect))]
    namespace PanAndZoomDemo.Android.Effects
    {
        public class PanEffect : PlatformEffect
        {
            protected override void OnAttached()
            {
                try
                {
                    // Control is the native component
                    if (this.Control is Com.Telerik.Widget.Chart.Visualization.CartesianChart.RadCartesianChartView chart &&
                        Element.Effects.FirstOrDefault() is PanAndZoomDemo.Portable.Effects.PanEffect effect)
                    {
                        // set the zoom
                        chart.SetZoom(effect.ZoomLevel, 1);
     
                        // Set the Pan offset
                        chart.SetPanOffset(effect.PanXOffset_Android, 0);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
     
            protected override void OnDetached()
            {
            }
        }
    }



    Further Assistance

    Due to the complexity of this configuration, if you need additional assistance with the native controls, please open an official support ticket using your Support License so that the development team for that native control can provide additional insight into the native chart's functionality.

    I hope I was able to help you get closer to your goal.

    Regards,
    Lance | Technical Support Engineer, Principal
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Lance | Team Lead - US DevTools Support
    Admin
    Lance | Team Lead - US DevTools Support avatar
    1047 posts

    Posted 20 May Link to this post

    Hello Nicholas,

    I have update for you. You can do everything in Xamarin.Forms, the only catch is you'll need to measure the width using the NativeControlLoaded event handler.

    Here's the code:

    <chart:RadCartesianChart x:Name="chart"
                  NativeControlLoaded="Chart_OnNativeControlLoaded">
        ...
    </chart:RadCartesianChart>

    private void Chart_OnNativeControlLoaded(object sender, EventArgs e)
    {
        chart.Zoom = new Size(2,0);
        chart.PanOffset = new Point(-200, 0);
     
        // Or, you may want to measure the control's width and then do the X offset from there
        var xOffset = chart.Width / 2;
        chart.PanOffset = new Point(-xOffset, 0);
    }


    Regards,
    Lance | Technical Support Engineer, Principal
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top