Knowledgebase
How to create zoom slider
Posted by Admin - on 11 February 2019 04:24 PM
|
|
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.
ScaleFactorModifierCreate 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 slider, the chart will zoom in and out, keeping the center of the visible range in the same point; and when you zoom by other means (RubberBandXyZoomModifier, PinchZoomModifier etc.), the slider will also change its value. WarningsPerformanceDue to calculating GetMaximumRange() on each update, this modifier can drop the performance on large amounts of data.Non-linear axisYou’ll need to change the code a bit if you want to use this modifier on logarithmic axis. Essentially, you need to convert ranges to real length when you calculate GetZoomScaleFactor().Clip modeYou will probably want to apply clip mode after zooming, so that if your visible range stacks to one edge of the chart series, the slider zoom would expand the chart only in the opposite direction. For that reason, create methodprivate 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 in the end of OnZoomScaleFactorChanged() method. Further ReadingTo 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. | |
|