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

Answered
0
0

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.

Version
3.0
  • You must to post comments
Best Answer
0
0

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

  • You must to post comments
0
0

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.

  • You must to post comments
0
0

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;
    }
}

}

  • Yura Khariton
    I’m sorry but I don’t understand what is expected behavior in this case. What do you do in myCode() method? Have you tried to override onScroll() method which should be called when there should be no inertial scroll and set isInertialAnimation = false there?
  • Gang Xu
    Sorry for the confusion. myCode() is my own method to re-render the heatmap surface. My task is to re-render the heatmap whenever the x-axis visible range changed by swiping the surface to left or right with a single finger. I used onUp() to capture the gesture of the first scenario and onRenderSurfaceRendered() to capture the gesture of the second scenario. first scenario: finger down, swipe to left/right, finger up when chart surface stopped moving second scenario: finger down, swipe to left/right, finger up while the chart surface still moving But there’s a chance both onUp() and onRenderSurfaceRendered() failed to capture the event when isInertialAnimation just turned to true and onRenderSurfaceRendered() already stopped. If it’s still not clear to you, I will make a video clip to explain. Thanks for your patience. And would you elaborate on how onRenderSurfacedRendered() works? I couldn’t find any description on the documentation. And how onScroll() help in my case?
  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.