How to create a Zoom Slider

Created by Lex Smith, Modified on Tue, 09 Apr 2024 at 12:46 PM by Lex Smith

We often get asked how to add a zoom slider to an Axis. In this tutorial, we will create a Custom Chart Modifier to provide zoom slider functionality to a chart.


ScaleFactorModifier


Create a new class called ScaleFactorModifier using the following code.


using System;
using System.Windows;
using SciChart.Charting.ChartModifiers;
using SciChart.Charting.Visuals.Axes;
using SciChart.Charting.Visuals.Events;
 
namespace SciChartTutorials.Example
{
    /// <summary>
    /// Provides ability to bind zoom scale factor of a chart to a slider.
    /// </summary>
    public class ScaleFactorModifier : ChartModifierBase
    {
        /// <summary>
        /// Prevents recursive calls of <see cref="SetZoomScaleFactor"/>.
        /// </summary>
        private bool _isUpdating;
 
        /// <summary>
        /// Defines the ZoomScaleFactor dependency property.
        /// </summary>
        public static readonly DependencyProperty ZoomScaleFactorProperty =
            DependencyProperty.Register("ZoomScaleFactor", typeof(double), typeof(ScaleFactorModifier), new PropertyMetadata(default(double), OnZoomScaleFactorChanged));
 
        /// <summary>
        /// Gets or sets zoom depth of the chart. It is calculated as Log10 of ratio between VisibleRange length and MaximumRange length
        /// (so, value of 0 means 100% zoom, value of -1 means 10% zoom etc.).
        /// </summary>
        public double ZoomScaleFactor
        {
            get { return (double)GetValue(ZoomScaleFactorProperty); }
            set { SetValue(ZoomScaleFactorProperty, value); }
        }
 
        /// <summary>
        /// Axis on which the zoom scale factor should be applied.
        /// </summary>
        public IAxis Axis { get { return ParentSurface.XAxis; } }
 
        private static void OnZoomScaleFactorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var @this = (ScaleFactorModifier)d;
            if (@this._isUpdating)
                return;
            @this.SetZoomScaleFactor(Math.Pow(10, (double)e.NewValue));
        }
 
        public override void OnAttached()
        {
            base.OnAttached();
            Axis.VisibleRangeChanged += OnVisibleRangeChanged;
            // First call to initialize the ZoomScaleFactor property.
            OnVisibleRangeChanged(this, null);
        }
 
        public override void OnDetached()
        {
            base.OnDetached();
            Axis.VisibleRangeChanged -= OnVisibleRangeChanged;
        }
 
        private void OnVisibleRangeChanged(object sender, VisibleRangeChangedEventArgs e)
        {
            _isUpdating = true;
            ZoomScaleFactor = Math.Log10(GetZoomScaleFactor());
            _isUpdating = false;
        }
 
        /// <summary>
        /// Gets linear zoom scale factor (i. e. without logarithm).
        /// </summary>
        /// <returns>The linear zoom scale factor.</returns>
        private double GetZoomScaleFactor()
        {
            return Axis.VisibleRange.AsDoubleRange().Diff / Axis.GetMaximumRange().AsDoubleRange().Diff;
        }
 
        /// <summary>
        /// Sets linear zoom scale factor (i. e. without logarithm).
        /// </summary>
        /// <param name="value">The new value.</param>
        private void SetZoomScaleFactor(double value)
        {
            var oldValue = GetZoomScaleFactor();
            var diff = value / (2 * oldValue) - 0.5;
            Axis.ZoomBy(diff, diff);
        }
    }
}


Now, if you add this modifier to a chart, you’ll be able to bind some dependency property to its ZoomScaleFactor property (or vice versa). Let’s take a look at an example.


<UserControl
    x:Class="SciChart.Examples.Examples.CreateSimpleChart.BandSeriesChartExampleView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:s="http://schemas.abtsoftware.co.uk/scichart"
    xmlns:example="clr-namespace:SciChartTutorials.Example"
    Loaded="BandSeriesChartExampleView_OnLoaded"
    d:DesignHeight="300"
    d:DesignWidth="300"
    mc:Ignorable="d">
  
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
  
        <s:SciChartSurface Name="sciChart" s:ThemeManager.Theme="BlackSteel">
  
            <s:SciChartSurface.ChartModifier>
                <example:ScaleFactorModifier x:Name="scaleFactorModifier" />
            </s:SciChartSurface.ChartModifier>
  
            <s:SciChartSurface.RenderableSeries>
                <s:FastBandRenderableSeries
                    Fill="#33279B27"
                    FillY1="#33FF1919"
                    StrokeY1="#FF279B27"
                    Stroke="#FFFF1919" />
            </s:SciChartSurface.RenderableSeries>
  
            <s:SciChartSurface.XAxis>
                <s:NumericAxis x:Name="xAxis" />
            </s:SciChartSurface.XAxis>
  
            <s:SciChartSurface.YAxis>
                <s:NumericAxis x:Name="yAxis" DrawMajorBands="True">
                    <s:NumericAxis.GrowBy>
                        <s:DoubleRange Max="0.1" Min="0.1" />
                    </s:NumericAxis.GrowBy>
                </s:NumericAxis>
            </s:SciChartSurface.YAxis>
        </s:SciChartSurface>
  
        <Slider
            Grid.Row="1"
            Maximum="0.1"
            Minimum="-2"
            Value="{Binding Path=ZoomScaleFactor, ElementName=scaleFactorModifier, Mode=TwoWay}" />
    </Grid>
</UserControl>


Now, if you move the slider, the chart will zoom in and out, keeping the center of the Visible Range at the same point. And when you zoom by other means (RubberBandXyZoomModifier, PinchZoomModifier etc.), the slider will also change its value.


Warnings


Performance


Due to calculating GetMaximumRange() on each update, this modifier can drop the performance on large amounts of data.


Non-linear axis


You’ll need to change the code a bit if you want to use this modifier on the logarithmic Axis. Essentially, you need to convert ranges to real lengths when you calculate GetZoomScaleFactor().


Clip mode


You will probably want to apply clip mode after zooming so that if your Visible Range stacks to one edge of the Chart series, the zoom slider will expand the chart only in the opposite direction. For that reason, create a method


        private void ApplyClipMode()
        {
            var max = Axis.GetMaximumRange();
            if (!max.IsValueWithinRange(Axis.VisibleRange.Min))
                Axis.VisibleRange.Min = max.Min;
            if (!max.IsValueWithinRange(Axis.VisibleRange.Max))
                Axis.VisibleRange.Max = max.Max;
        }


and call it at the end of OnZoomScaleFactorChanged() method.


Further Reading


To learn more about SciChart APIs, please see the following documentation articles:



Also, there is a set of articles on Custom Chart Modifiers creation available in the Knowledgebase at this link.






Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select atleast one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article