How to: Control Panning and Zooming

This how-to guide shows you how to control the panning and zooming gestures for the axes on your chart.

In order to control panning and zooming gestures you need to do the following:

  1. Create a chart, giving it an X and Y axis and some data.
  2. Enabled panning and zooming gestures on each axis as required.
  3. To make fast pan and zoom gestures continue once you’ve released your fingers, slowing down instead of stopping immediately, enable momentum panning and momentum zooming.
  4. Limit the range in which you can pan and zoom.

An axis object defines how data values are mapped to pixel values on screen. One of the things that can affect this is the zoom and pan states of the chart and hence these are handled by the axes.

Enabling Panning and Zooming

By default, gestures are disabled on an Axis. To enable them simply call:

Java

axis.enableGesturePanning(true);
axis.enableGestureZooming(true);

C#

axis.GesturePanningEnabled = true;
axis.GestureZoomingEnabled = true;

Panning and zooming gestures are configured separately, on a per axis basis. This gives you a lot of control allowing you, for example, to enable panning and zooming on the X axis while keeping the Y axis fixed. Just remember to enable them on both axes if that’s what you require!

You can of course turn them off again by calling the same method with false as the argument.

Adding Momentum

If you would like the chart to continue panning and zooming after you have lifted off your fingers you need to enable momentum panning and zooming:

Java

axis.enableMomentumPanning(true);
axis.enableMomentumZooming(true);

C#

axis.MomentumPanningEnabled = true;
axis.MomentumZoomingEnabled = true;

Fast pan and zoom gestures will cause the chart to continue panning and zooming during a brief ‘slowing down’ period rather than stopping immediately. Again, you can configure each gesture separately on each axis, and you can disable them by calling the same method with false as the argument.

Restricting Panning and Zooming

Restrictions on panning and zooming are based on two ranges: the default range and the max range.

The default range is a user-settable range on an axis. It is the range that will be displayed when data is loaded into the chart or when the zoom is reset. If it is not set by the user it will be the same as the data range of the axis - the range of all the data from all series represented by the axis.

To set the default range for an axis, call its setDefaultRange method with a suitable Range for the type of axis it is. For example, if the axis is a NumberAxis give it a NumberRange. Similarly, if the axis is a DateTimeAxis give it a DateRange.

The max range of an axis is the union of its default range and data range. So, where a default range has not been set, the max range and default range will be the same.

By default, panning out of an axis’ default range is allowed but panning out of its max range is not. This is typically what you would want if you have a lot of data but want to show a specific section when the chart loads; the PanAndZoom sample code does just that for the X axis, displaying data between 2005 and 2010 but allowing you to pan and zoom to temperature readings from the years before and after that range.

You can change this behavior by calling the following methods:

Java

axis.allowPanningOutOfDefaultRange(false);
axis.allowPanningOutOfMaxRange(true);

C#

axis.PanningOutOfDefaultRangeAllowed = false;
axis.PanningOutOfMaxRangeAllowed = true;

If you don’t want to put any limits on panning and zooming, call both of the above methods with an argument of true for each axis.

Getting notifications about user gestures and axis range change events

It’s often helpful to get information about how the user is panning and zooming the chart. shinobicharts provides this by exposing a set of listener interfaces (and associated setters) for you to implement. These are:

Java

ShinobiChart.OnGestureListener
Axis.OnRangeChangeListener
ShinobiChart.OnAxisMotionStateChangeListener

C#

IShinobiChartOnGestureListener
IAxisOnRangeChangeListener
IShinobiChartOnAxisMotionStateChangeListener

The ShinobiChart.OnGestureListener interface defines methods called by the chart when the user performs touch gestures. The Axis.OnRangeChangeListener interface defines a method called by the axis when its range changes for any reason. The axis keeps track of its motion state, informing you about internally generated range changes (animating, gesture, bouncing, momentum and stopped). The ShinobiChart.OnAxisMotionStateChangeListener interface defines a method called by the axis when its motion state changes.

Let’s modify the sample so that the chart title displays the current date range, but only when the axis range changes have stopped. You’re going to make the activity a listener for the axis, so modify the activity class to implement the Axis.OnMotionStateChangeListener interface.

Java

public class PanAndZoomActivity extends Activity implements ShinobiChart.OnAxisMotionStateChangeListener

C#

public class MainActivity : Activity, IShinobiChartOnAxisMotionStateChangeListener

You now need to tell the chart that the activity is listening to it

Java

shinobiChart.setOnAxisMotionStateChangeListener(this);

C#

shinobiChart.SetOnAxisMotionStateChangeListener (this);

Finally provide an implementation for the handler method. If the motion state has changed to STOPPED, you will format the current displayed range and add it to the title.

Java

@Override
public void onAxisMotionStateChange(Axis<?, ?> axis) {
    // We're only interested in the X axis here
    if (axis == axis.getChart().getXAxis()) {
        if (axis.getMotionState() == Axis.MotionState.STOPPED) {
            setTitle(axis.getChart(), (DateRange) axis.getCurrentDisplayedRange());
        } else {
            axis.getChart().setTitle(TITLE);
        }
    }
}

private void setTitle(ShinobiChart chart, DateRange range) {
    DateFormat dateFormat = DateFormat.getDateInstance();
    String titleString = String.format("%s    %s to %s",
            TITLE,
            dateFormat.format(range.getMinimum()),
            dateFormat.format(range.getMaximum()));
    chart.setTitle(titleString);
}

C#

public void OnAxisMotionStateChange (Axis axis)
{
    if (axis == axis.Chart.XAxis) {
       DateTimeAxis xAxis = (DateTimeAxis)axis;
       if (axis.GetMotionState() == Axis.MotionState.Stopped) {
         SetTitle(axis.Chart, xAxis.CurrentDisplayedRange);
       }
       else {
         axis.Chart.Title = TITLE;
       }
    }
}

void SetTitle(IShinobiChart chart, DateRange range) {
    String titleString = String.Format("{0}    {1} to {2}",
                                       TITLE,
                                       range.Minimum.ToShortDateString(),
                                       range.Maximum.ToShortDateString());
    chart.Title = titleString;
}

See it in Action

PanAndZoom Sample App

Take a look at the PanAndZoom sample code. Here you’re displaying the average monthly max and min temperatures, recorded at the Durham weather station as two line series. While you’re loading a larger set of data, you’re setting the X axis’ default range to be between 2005 to 2010. This is what is displayed when the app starts up. You’ve enabled panning and zooming, with momentum, on the X axis allowing the user to browse the data for different years. The Y axis is fixed and automatically takes the range of the data i.e. the lowest to the highest temperature readings.

See related code sample: Pan And Zoom Sample, in the samples/pan-and-zoom folder of your product download (Xamarin.Android/samples/PanAndZoom if you’re using Xamarin.Android).