SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
Hello,
I have a SciChart with multiple y-axes. Thanks to the ZoomPanModifier the user can pan the whole chart by dragging (holding the left mouse button down and moving the mouse). Good! But it should also be possible for the user to pan a certain axis (meaning : changing the min and max values of the axis) and that doesn’t seem to be possible with the built-in ChartModifiers.
So then I thought, no problem, I make my own ChartModifier to handle this (I already implemented two other modifiers for other mouse interactions before, so I get the hang of this :-)). But I don’t get this to work correctly.
My first attempt was to derive from ChartModifierBase and then handle events like OnModifierMouseDown and OnModifierMouseUp. Problem there is that OnModifierMouseUp doesn’t get called when the mouse is not over the chart surface anymore. That is a problem because the user can release the mouse button when the mouse is over another part of the WPF window or even outside of the application window and somewhere else on the screen.
My second attempt was to inherit from ZoomPanModifierBase because the ZoomPanModifier handles these ‘mouseups’ correctly. I try by overriding the Pan(System.Windows.Point currentPoint, System.Windows.Point lastPoint, System.Windows.Point startPoint) method but this method only gets called when the panning starts on the chart area itself, not on one of the axes, so it doesn’t seem to be a solution either.
public class AxisPanModifier : ZoomPanModifierBase
{
public override void Pan(System.Windows.Point currentPoint, System.Windows.Point lastPoint, System.Windows.Point startPoint) {
// Does not get called when the dragging starts on an axis.
}
}
Can someone give me a tip on how to proceed or does someone already have a solution for this ? Thanks for any help in advance. đŸ™‚
Best greetings,
Stefaan
Hi Stefaan,
It is possible to pan a single axis by dragging the axis. Please see the XAxisDragModifier and YAxisDragModifier. The property you need to set to enable panning on an axis is *AxisDragModifier.DragMode, which has values of Pan and Scale.
If you wanted to go one further you could create your own ChartModifier (as you have done) to pan a single axis. Please see our tutorial on Creating a Custom ZoomPanModifier. If you take this code (found in the first tutorial) and add an AxisId DependencyProperty you could make it generic to filter on a specific axis by using the ChartModifierBase.GetYAxis(string id) and GetXAxis methods.
Hope this helps!
Andrew
Hello,
here my code if other people later want to have some similar dragging behavior. Works with a flexible collection of x-axes and y-axis (although I only tested with one x-axis). Please feel free to use the code.
/// <summary>
/// ChartModifier for panning through dragging the mouse, allows for panning a specific axis.
/// </summary>
/// <remarks>
/// See : https://www.scichart.com/questions/question/panning-an-axis-by-dragging-the-mouse
/// </remarks>
public class PanModifier : ChartModifierBase
{
private class PanningState
{
public Point LastPoint;
public IEnumerable<IAxis> XAxesToScroll;
public IEnumerable<IAxis> YAxesToScroll;
}
private PanningState _state;
private PanningState CreateInitialPanningState(ModifierMouseArgs e) {
foreach (var xAxis in XAxes) {
if (HitTestableContainsMousePoint(xAxis, e)) {
// Dragging started on an x-axis, only pan that x-axis.
return new PanningState {
LastPoint = e.MousePoint,
XAxesToScroll = new IAxis[] { xAxis },
YAxesToScroll = new IAxis[0]
};
}
}
foreach (var yAxis in YAxes) {
if (HitTestableContainsMousePoint(yAxis, e)) {
// Dragging started on an y-axis, only pan that y-axis.
return new PanningState {
LastPoint = e.MousePoint,
XAxesToScroll = new IAxis[0],
YAxesToScroll = new IAxis[] { yAxis }
};
}
}
// Dragging started on the main chart area, pan all the axes.
return new PanningState {
LastPoint = e.MousePoint,
XAxesToScroll = XAxes,
YAxesToScroll = YAxes
};
}
private bool HitTestableContainsMousePoint(IHitTestable hitTestable, ModifierMouseArgs e) {
Rect bounds = hitTestable.GetBoundsRelativeTo(RootGrid);
return bounds.Contains(e.MousePoint);
}
public override void OnModifierMouseDown(ModifierMouseArgs e) {
base.OnModifierMouseDown(e);
ModifierSurface.CaptureMouse();
_state = CreateInitialPanningState(e);
e.Handled = true;
}
public override void OnModifierMouseMove(ModifierMouseArgs e) {
base.OnModifierMouseMove(e);
if (_state == null) return;
var currentPoint = e.MousePoint;
var xDelta = currentPoint.X - _state.LastPoint.X;
var yDelta = _state.LastPoint.Y - currentPoint.Y;
using (ParentSurface.SuspendUpdates()) {
foreach (var xAxis in _state.XAxesToScroll) {
xAxis.Scroll(XAxis.IsHorizontalAxis ? xDelta : -yDelta, ClipMode.None);
}
foreach (var yAxis in _state.YAxesToScroll) {
yAxis.Scroll(YAxis.IsHorizontalAxis ? -xDelta : yDelta, ClipMode.None);
}
}
_state.LastPoint = currentPoint;
}
public override void OnModifierMouseUp(ModifierMouseArgs e) {
base.OnModifierMouseUp(e);
ModifierSurface.ReleaseMouseCapture();
_state = null;
}
}
Best greetings,
Stefaan
Please login first to submit.