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

Displaying a Subset of Data Points / Horizontal Scrolling

2 Answers 204 Views
Chart
This is a migrated thread and some comments may be shown as answers.
Nicholas
Top achievements
Rank 1
Nicholas asked on 10 May 2019, 11:19 PM

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 Answers, 1 is accepted

Sort by
0
Lance | Senior Manager Technical Support
Telerik team
answered on 14 May 2019, 08:54 PM
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
0
Lance | Senior Manager Technical Support
Telerik team
answered on 20 May 2019, 05:50 PM
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
Tags
Chart
Asked by
Nicholas
Top achievements
Rank 1
Answers by
Lance | Senior Manager Technical Support
Telerik team
Share this question
or