SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, and now iOS Charting & Android Chart Components

Welcome to the SciChart Community Forums!

Please use the forums below to ask questions about SciChart. Take a moment to read our Question asking guidelines on how to ask a good question and our support policy

We also have a tag=SciChart on Stackoverflow.com where you can earn rep for your questions!

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.