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.
- l1pton17 asked 10 years ago
- You must login to post comments
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();
}
}
- l1pton17 answered 10 years ago
- You must login to post comments
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
- Andrew Burnett-Thompson answered 10 years ago
- You must login to post comments
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 answered 10 years ago
-
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(); } }
-
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 login to post comments
Please login first to submit.