All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lecho.lib.hellocharts.gesture.ChartScroller Maven / Gradle / Ivy

The newest version!
package lecho.lib.hellocharts.gesture;

import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.support.v4.widget.ScrollerCompat;

import lecho.lib.hellocharts.computator.ChartComputator;
import lecho.lib.hellocharts.model.Viewport;

/**
 * Encapsulates scrolling functionality.
 */
public class ChartScroller {

    private Viewport scrollerStartViewport = new Viewport(); // Used only for zooms and flings
    private Point surfaceSizeBuffer = new Point();// Used for scroll and flings
    private ScrollerCompat scroller;

    public ChartScroller(Context context) {
        scroller = ScrollerCompat.create(context);
    }

    public boolean startScroll(ChartComputator computator) {
        scroller.abortAnimation();
        scrollerStartViewport.set(computator.getCurrentViewport());
        return true;
    }

    public boolean scroll(ChartComputator computator, float distanceX, float distanceY, ScrollResult scrollResult) {

        // Scrolling uses math based on the viewport (as opposed to math using pixels). Pixel offset is the offset in
        // screen pixels, while viewport offset is the offset within the current viewport. For additional
        // information on
        // surface sizes and pixel offsets, see the docs for {@link computeScrollSurfaceSize()}. For additional
        // information about the viewport, see the comments for {@link mCurrentViewport}.

        final Viewport maxViewport = computator.getMaximumViewport();
        final Viewport visibleViewport = computator.getVisibleViewport();
        final Viewport currentViewport = computator.getCurrentViewport();
        final Rect contentRect = computator.getContentRectMinusAllMargins();

        final boolean canScrollLeft = currentViewport.left > maxViewport.left;
        final boolean canScrollRight = currentViewport.right < maxViewport.right;
        final boolean canScrollTop = currentViewport.top < maxViewport.top;
        final boolean canScrollBottom = currentViewport.bottom > maxViewport.bottom;

        boolean canScrollX = false;
        boolean canScrollY = false;

        if (canScrollLeft && distanceX <= 0) {
            canScrollX = true;
        } else if (canScrollRight && distanceX >= 0) {
            canScrollX = true;
        }

        if (canScrollTop && distanceY <= 0) {
            canScrollY = true;
        } else if (canScrollBottom && distanceY >= 0) {
            canScrollY = true;
        }

        if (canScrollX || canScrollY) {

            computator.computeScrollSurfaceSize(surfaceSizeBuffer);

            float viewportOffsetX = distanceX * visibleViewport.width() / contentRect.width();
            float viewportOffsetY = -distanceY * visibleViewport.height() / contentRect.height();

            computator
                    .setViewportTopLeft(currentViewport.left + viewportOffsetX, currentViewport.top + viewportOffsetY);
        }

        scrollResult.canScrollX = canScrollX;
        scrollResult.canScrollY = canScrollY;

        return canScrollX || canScrollY;
    }

    public boolean computeScrollOffset(ChartComputator computator) {
        if (scroller.computeScrollOffset()) {
            // The scroller isn't finished, meaning a fling or programmatic pan operation is
            // currently active.

            final Viewport maxViewport = computator.getMaximumViewport();

            computator.computeScrollSurfaceSize(surfaceSizeBuffer);

            final float currXRange = maxViewport.left + maxViewport.width() * scroller.getCurrX() /
                    surfaceSizeBuffer.x;
            final float currYRange = maxViewport.top - maxViewport.height() * scroller.getCurrY() /
                    surfaceSizeBuffer.y;

            computator.setViewportTopLeft(currXRange, currYRange);

            return true;
        }

        return false;
    }

    public boolean fling(int velocityX, int velocityY, ChartComputator computator) {
        // Flings use math in pixels (as opposed to math based on the viewport).
        computator.computeScrollSurfaceSize(surfaceSizeBuffer);
        scrollerStartViewport.set(computator.getCurrentViewport());

        int startX = (int) (surfaceSizeBuffer.x * (scrollerStartViewport.left - computator.getMaximumViewport().left)
                / computator.getMaximumViewport().width());
        int startY = (int) (surfaceSizeBuffer.y * (computator.getMaximumViewport().top - scrollerStartViewport.top) /
                computator.getMaximumViewport().height());

        // TODO probably should be mScroller.forceFinish but ScrollerCompat doesn't have that method.
        scroller.abortAnimation();

        final int width = computator.getContentRectMinusAllMargins().width();
        final int height = computator.getContentRectMinusAllMargins().height();
        scroller.fling(startX, startY, velocityX, velocityY, 0, surfaceSizeBuffer.x - width + 1, 0,
                surfaceSizeBuffer.y - height + 1);
        return true;
    }

    public static class ScrollResult {
        public boolean canScrollX;
        public boolean canScrollY;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy