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!

Please note: SciChart team will only answer questions from customers with active support subscriptions. Expired support questions will be ignored. If your support status shows incorrectly, contact us and we will be glad to help.

Answered
0
0

I need to graph have autorange and ZoomPanModifier. As a result the graph can moved only by X axis. But i want to be able to move by Y axis. It is behavior like a bloomberg.

  • You must to post comments
Best Answer
0
0

After a brainstorm i create this modifier, that satisfies my reqirements. If anyone sees an errors in my code write here please.

public class BloombergModifier : ChartModifierBase
{
    private class ChangableValue
    {
        public Double Current { get; private set; }
        public Double New { get; set; }
        public Boolean IsChange { get { return Math.Abs(New - Current) > Double.Epsilon; } }

        public ChangableValue()
        {
            Current = Double.NaN;
        }

        public void ApplyChange()
        {
            Current = New;
        }
    }

    private readonly ConcurrentDictionary<IAxis, Double> currentZoom = new ConcurrentDictionary<IAxis, Double>();
    private readonly ChangableValue yMinPixel = new ChangableValue();
    private readonly ChangableValue yMaxPixel = new ChangableValue();
    private readonly ChangableValue yScale = new ChangableValue();

    private Double globalYDelta;
    private DoubleRange yRange = null;
    private Point? panLastPoint = null;
    private Point? zoomLastPoint = null;

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

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

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

        if (!e.IsMaster) return;

        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);
        ModifierSurface.ReleaseMouseCapture();
        zoomLastPoint = panLastPoint = null;
    }

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

        var currentPoint = e.MousePoint;

        if (zoomLastPoint != null)
        {
            const Double factor = 0.008;
            const Double lowBound = -0.45;
            var yDelta = zoomLastPoint.Value.Y - currentPoint.Y;
            var r1 = YAxis.GetCoordinate(yRange.Min) + globalYDelta;
            var r2 = YAxis.GetCoordinate(yRange.Max) + globalYDelta;

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

            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;

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

            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()
    {
        yRange = (DoubleRange)YAxis.GetWindowedYRange(new Dictionary<String, IRange>
            {
                { "test", XAxis.VisibleRange }
            });
    }

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

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

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

        if (yMinPixel.IsChange || yMaxPixel.IsChange || yScale.IsChange)
        {
            YAxis.Zoom(yMinPixel.New, yMaxPixel.New);
            YAxis.ZoomBy(yScale.New, yScale.New);
        }

        yMinPixel.ApplyChange();
        yMaxPixel.ApplyChange();
        yScale.ApplyChange();
    }
}
  • You must to post comments
1
0

Hi there,

I think you can find some answers to your question in the article How to have a fixed scrolling time range that works with Modifiers. Here we present some ideas / examples of how to mimic AutoRange while keeping modifiers interactive. Some of our examples actually do this now.

Take a look above and see what you think.

Best regards,
Andrew

  • You must to post comments
0
0

Thank you for your answering. This article help me to create this modifier:

public class SimpleZoomPanModifier : ChartModifierBase
{
    private Point? _lastPoint;
    private Double _yDelta = 0;

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

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

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

        e.Handled = true;
        _lastPoint = e.MousePoint;
        ModifierSurface.CaptureMouse();
    }

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

        if (_lastPoint == null) return;

        var currentPoint = e.MousePoint;
        var xDelta = currentPoint.X - _lastPoint.Value.X;

        _yDelta += _lastPoint.Value.Y - currentPoint.Y;

        using (ParentSurface.SuspendUpdates())
        {
            XAxis.Scroll(XAxis.IsHorizontalAxis ? xDelta : -_yDelta, ClipMode.None);
            AutoRange();
        }

        _lastPoint = currentPoint;
    }

    private void AutoRange()
    {

        var rng = YAxis.GetWindowedYRange(new Dictionary<String, IRange>
            {
                { "test", XAxis.VisibleRange }
            });
        var r1 = YAxis.GetCoordinate(rng.Min);
        var r2 = YAxis.GetCoordinate(rng.Max);
        var yVMinPrev = YAxis.GetCoordinate((Double)YAxis.VisibleRange.Min);
        var yCurDelta = YAxis.GetCoordinate((Double)rng.Min) - yVMinPrev;

        YAxis.Zoom(r1, r2);
        YAxis.Scroll(_yDelta, ClipMode.None);
    }

    public override void OnModifierMouseUp(ModifierMouseArgs e)
    {
        base.OnModifierMouseUp(e);
        _lastPoint = null;
        ModifierSurface.ReleaseMouseCapture();
    }
}

This works good with one chart. But when i create two charts with common MouseEventGroup that i can scroll by yAxis only upper chart (OnModifierMouseDown called only for first chart).

<s:SciChartSurface s:SciChartGroup.VerticalChartGroup="{Binding Parent.VerticalChartGroupId}"
                   ViewportManager="{Binding Parent.ViewportManager}">
    <s:SciChartSurface.ChartModifier>
        <s:ModifierGroup s:MouseManager.MouseEventGroup="{Binding Parent.SharedMouseGroupId, Mode=TwoWay}">
            <c:SimpleZoomPanModifier ExecuteOn="MouseLeftButton"/>
            <s:MouseWheelZoomModifier />
            <s:YAxisDragModifier/>
            <s:XAxisDragModifier/>
            <s:ZoomExtentsModifier ExecuteOn="MouseDoubleClick"/>
        </s:ModifierGroup>
    </s:SciChartSurface.ChartModifier>
  • l1pton17
    I solve the problem by using property IsMaster:public class SimpleZoomPanModifier : ChartModifierBase { private Point? _lastPoint; private Double _yDelta;public override void OnParentSurfaceRendered(SciChartRenderedMessage e) { base.OnParentSurfaceRendered(e);System.Diagnostics.Debug.WriteLine("{0}: Render not master for {1}", DateTime.Now.TimeOfDay, ParentSurface.RenderableSeries.FirstOrDefault().DataSeries.SeriesName); using (ParentSurface.SuspendUpdates()) { AutoRange(); } }public override void OnModifierMouseDown(ModifierMouseArgs e) { base.OnModifierMouseDown(e);if (!e.IsMaster) return;System.Diagnostics.Debug.WriteLine("{0} for {1}", e.IsMaster, ParentSurface.RenderableSeries.FirstOrDefault().DataSeries.SeriesName);e.Handled = true;_lastPoint = e.MousePoint; ModifierSurface.CaptureMouse(); System.Diagnostics.Debug.WriteLine("{0}: Mouse down for {1}", DateTime.Now.TimeOfDay, ParentSurface.RenderableSeries.FirstOrDefault().DataSeries.SeriesName); }public override void OnModifierMouseMove(ModifierMouseArgs e) { base.OnModifierMouseMove(e);if (_lastPoint == null) return;var currentPoint = e.MousePoint; var xDelta = currentPoint.X - _lastPoint.Value.X;_yDelta += _lastPoint.Value.Y - currentPoint.Y;using (ParentSurface.SuspendUpdates()) { XAxis.Scroll(XAxis.IsHorizontalAxis ? xDelta : -_yDelta, ClipMode.None); AutoRange(); }_lastPoint = currentPoint; }private void AutoRange() { var rng = YAxis.GetWindowedYRange(new Dictionary<String, IRange> { { "test", XAxis.VisibleRange } }); var r1 = YAxis.GetCoordinate(rng.Min); var r2 = YAxis.GetCoordinate(rng.Max); var yVMinPrev = YAxis.GetCoordinate((Double)YAxis.VisibleRange.Min); var yCurDelta = YAxis.GetCoordinate((Double)rng.Min) - yVMinPrev;YAxis.Zoom(r1, r2); YAxis.Scroll(_yDelta, ClipMode.None); }public override void OnModifierMouseUp(ModifierMouseArgs e) { base.OnModifierMouseUp(e); _lastPoint = null; ModifierSurface.ReleaseMouseCapture(); } }
  • l1pton17
    But now YAxisDragModifier doesn't work, because i zoom manually if my modifier. I'm trying to implement YAxisDragModifier behaviour but i don't know how to check that mouse down event occured on axis. Could you help me?
  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.