Pre loader

Create custom pan modifier

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

0
0

I’m creating a my own modifier that implements bloomberg behaviour (i need autorange and scale at the same time).
Code you can see below. It’s works good but there are several problems.
1) Method OnParentSurfaceRendered is not called when i change a data series.
2) When i stretch x axis the difference of currentPoint.X and panLastPoint.X in OnModifierMouseMove became a zero. It seems that a ModifierMouseArgs.MousePoint in “data series” coordinate but i need a mouse screen coordinate. How i can get a mouse screen coordinate in OnMoidiferMouseMove?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Abt.Controls.SciChart.ChartModifiers;
using Abt.Controls.SciChart;
using Abt.Controls.SciChart.Visuals.Axes;
using Abt.Controls.SciChart.Visuals;
using System.Collections.Concurrent;
using Aton.Graphics.Models;
using System.Windows.Input;

namespace Aton.Graphics.Modifiers
{
public class BloombergModifier : ChartModifierBase
{
    private readonly ConcurrentDictionary<IAxis, Double> currentZoom = new ConcurrentDictionary<IAxis, Double>();
    private const Double deltaForMove = 30;
    private const Double scaleFactor = 0.008;
    private const Double scaleLowBound = -0.45;

    private Double yMinPixel = Double.NaN;
    private Double yMaxPixel = Double.NaN;
    private Double yScale = Double.NaN;
    private Double globalYDelta;
    private DoubleRange yRange = null;
    private Point? panLastPoint = null;
    private Point? zoomLastPoint = null;

    public override void OnParentSurfaceRendered(SciChartRenderedMessage e)
    {
        base.OnParentSurfaceRendered(e);

        System.Diagnostics.Debug.WriteLine("{0}: Render draw", DateTime.Now);
        using (ParentSurface.SuspendUpdates())
        {
            Draw();
        }
    }

    public override void OnModifierMouseDown(ModifierMouseArgs e)
    {
        base.OnModifierMouseDown(e);

        if (!e.IsMaster) return;

        if (!e.MouseButtons.HasFlag(MouseButtons.Left)) return;

        foreach (var series in ParentSurface.SeriesSource)
        {
            series.RenderSeries.IsSelected = false;
        }

        if (HitTestableContainsMousePoint(YAxis, e))
        {
            zoomLastPoint = e.MousePoint;
            ModifierSurface.CaptureMouse();
            e.Handled = true;
        }
        else if (!HitTestableContainsMousePoint(XAxis, e))
        {
            panLastPoint = e.MousePoint;
            ModifierSurface.CaptureMouse();
            e.Handled = true;
        }
    }

    public override void OnModifierMouseUp(ModifierMouseArgs e)
    {
        base.OnModifierMouseUp(e);
        if (!e.MouseButtons.HasFlag(MouseButtons.Left)) return;

        if (e.IsMaster)
        {
            ModifierSurface.ReleaseMouseCapture();
            zoomLastPoint = panLastPoint = null;
            e.Handled = true;
        }
    }

    public override void OnModifierMouseMove(ModifierMouseArgs e)
    {
        base.OnModifierMouseMove(e);
        if (!e.IsMaster) return;

        var currentPoint = e.MousePoint;

        if (zoomLastPoint != null)
        {
            if (yRange == null) return;
            var yDelta = zoomLastPoint.Value.Y - currentPoint.Y;

            currentZoom.AddOrUpdate(YAxis, 0.0, (k, v) => Math.Max(v + scaleFactor * (yDelta >= 0 ? 1 : -1), scaleLowBound));

            using (ParentSurface.SuspendUpdates())
            {
                Draw();
            }

            zoomLastPoint = currentPoint;
            e.Handled = true;
        }
        else if (panLastPoint != null)
        {
            var xDelta = currentPoint.X - panLastPoint.Value.X;
            var yDelta = panLastPoint.Value.Y - currentPoint.Y;
            globalYDelta += yDelta;
            System.Diagnostics.Debug.WriteLine("{1}: Scroll: {0}", xDelta, DateTime.Now);

            using (ParentSurface.SuspendUpdates())
            {
                Draw();
                XAxis.Scroll(xDelta, ClipMode.None);
            }

            panLastPoint = currentPoint;
            e.Handled = true;
        }
        else
        {
            if (HitTestableContainsMousePoint(YAxis, e))
            {
                SetCursor(System.Windows.Input.Cursors.SizeNS);
            }
            else
            {
                SetCursor(System.Windows.Input.Cursors.Arrow);
            }
        }
    }

    protected override void OnXAxesCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        base.OnXAxesCollectionChanged(sender, e);

        switch (e.Action)
        {
            case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                foreach (IAxis axis in e.NewItems)
                {
                    axis.VisibleRangeChanged += XAxisVisibleRangeChanged;
                }
                break;
            case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                foreach (IAxis axis in e.OldItems)
                {
                    axis.VisibleRangeChanged -= XAxisVisibleRangeChanged;
                }
                break;
        }
    }

    private void XAxisVisibleRangeChanged(object sender, VisibleRangeChangedEventArgs e)
    {
        SetYRange();
    }

    private void SetYRange()
    {
        this.yRange = YAxis != null ? (DoubleRange)YAxis.GetWindowedYRange(new Dictionary<String, IRange>
            {
                { "test", XAxis.VisibleRange }
            }) : null;
    }

    private Boolean HitTestableContainsMousePoint(IHitTestable hitTestable, ModifierMouseArgs e)
    {
        Rect bounds = hitTestable.GetBoundsRelativeTo(RootGrid);
        return bounds.Contains(e.MousePoint);
    }

    private void Draw()
    {
        if (yRange == null) { SetYRange(); }
        if (yRange == null) return;

        Double realYDelta = Math.Abs(globalYDelta) < deltaForMove ? 0 : globalYDelta;

        yMinPixel = YAxis.GetCoordinate(yRange.Min) + realYDelta;
        yMaxPixel = YAxis.GetCoordinate(yRange.Max) + realYDelta;
        yScale = currentZoom.GetOrAdd(YAxis, 0);

        if (!Double.IsNaN(yMinPixel) && !Double.IsNaN(yMaxPixel) && !Double.IsNaN(yScale))
        {
            YAxis.Zoom(yMinPixel, yMaxPixel);
            YAxis.ZoomBy(yScale, yScale);
        }
    }
}

}

  • You must to post comments
0
0

It’s funny about 5 people have asked in the last few days ‘how do I zoom with autorange’. We have some workarounds documented below

To answer your questions:

  1. OnParentSurfaceRendered should be called if the data series is changed. This is called whenever the chart redraws, which is whenever a property on the chart changes, or data changes. If not, you can always force it by calling SciChartSurface.InvalidateElement()

  2. To convert pixel to data coordinates, see our article ‘How to convert pixel to data coordinates

Finally, if you haven’t already seen it, you might want to check out our excellent series on the ChartModifier API.

Hope this helps!

Best regards,
Andrew

  • You must to post comments
Showing 1 result
Your Answer

Please first to submit.

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies