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:
- Each series is to contain twenty-four data points, one for each hour of the day (0-23)
- A total of three separate series are to be rendered as a stacked bar chart
- The chart shall initially display the seven hours closest to the current time of the user's device for the selected day
- 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
0
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.
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:
iOS Platform Effect
Now, in the iOS Platform Effect class, retrieve the values from the Routing Effect and apply them to the native control
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.
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
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
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
{
// Visit to see how to implement https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/effects/creating
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
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:
Regards,
Lance | Technical Support Engineer, Principal
Progress Telerik
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