SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
I am working on the spectrogram (heatmap) that can be interacted with fingers. It can only pan horizontally, and the Z values from heatmap will be updated whenever panning stopped.
I override onUp function from ZoomPanModifier to fetch the latest x range, which is temporarily logged by VisiableRangeChangeListener. But the issue is, when I’m panning with the finger horizontally, the chart will always be moving a little bit after onUp() occurred. So there’s a difference between the desired x range and actual x range.
Is there a way to get the final x range after a panning action?
Thanks.
Hi Gang Xu,
Unfortunately we don’t support such behavior out of the box and it will be quite tricky to implement, because of how inertial scroll is implemented, but it’s possible to do by tracking changes in VisibleRange of target axis. Here a custom modifier which allow to do this:
class CustomZoomPanModifier extends ZoomPanModifier {
private boolean isInertialAnimation = false;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
isInertialAnimation = true; // we use inertial scroll for handling fling gesture
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public void onRenderSurfaceRendered(RenderedMessage message) {
final IRange visibleRange = getXAxis().getVisibleRange();
final double oldMin = visibleRange.getMinAsDouble();
final double oldMax = visibleRange.getMaxAsDouble();
// if we still animating using inertial scroll visible range will change in this call
super.onRenderSurfaceRendered(message);
final double newMin = visibleRange.getMinAsDouble();
final double newMax = visibleRange.getMaxAsDouble();
// detect when inertial scroll ended
if(isInertialAnimation && Double.compare(oldMin, newMin) == 0 && Double.compare(oldMax, newMax) == 0) {
Log.d(TAG, "animation ended");
// here goes your code
isInertialAnimation = false; // animation ended
}
}
}
Is this suitable for your needs?
Hope this will help you!
Best regards,
Yura
Thanks for your prompt reply Yura, it works like a charm.
Even though it only works on the event of the inertial scroll, not the finger down-scroll-up action. But I managed to combine two events together for both scenarios.
Hi Yura,
With the solution you provided, I randomly had glitches that the event has not been triggered. I use onUp() and onRenderSurfaceRendered() to capture the panning events with or without isInertialAnimation enabled. But I found there’s a scenario both methods cannot trigger the events, which is when the methods occurred in the order listed below.
onRenderSurfaceRendered();
onRenderSurfaceRendered();
onRenderSurfaceRendered(); # not able to trigger event when isInertialAnimation is false
onFling(); # isInertialAnimation switch from false to true
onUp(); # not able to trigger event when isInertialAnimation is true
I hope I made my point clear, and please let me know if you have a solution for this. Thanks.
public class CustomZoomPanModifier extends ZoomPanModifier {
private boolean isInertialAnimation = false;
private static final String TAG = "CustomZoomPanModifier";
@Override
protected void onUp(MotionEvent e) {
if (!isInertialAnimation) {
myCode();
}
super.onUp(e);
}
// use onFling and onRenderSurfaceRendered to trigger event of panning with inertial scroll
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
isInertialAnimation = true; // we use inertial scroll for handling fling gesture
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public void onRenderSurfaceRendered(RenderedMessage message) {
final IRange visibleRange = getXAxis().getVisibleRange();
final double oldMin = visibleRange.getMinAsDouble();
final double oldMax = visibleRange.getMaxAsDouble();
// if we still animating using inertial scroll visible range will change in this call
super.onRenderSurfaceRendered(message);
final double newMin = visibleRange.getMinAsDouble();
final double newMax = visibleRange.getMaxAsDouble();
// determine if fling stopped
boolean isMinEqual = Double.compare(oldMin, newMin) == 0;
boolean isMaxEqual = Double.compare(oldMax, newMax) == 0;
if (isInertialAnimation && isMinEqual && isMaxEqual) {
myCode();
isInertialAnimation = false;
}
}
}
Please login first to submit.