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

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

There is a newer version: 1.5.8
Show newest version
package lecho.lib.hellocharts.gesture;

import android.content.Context;
import android.graphics.RectF;
import android.support.v4.widget.ScrollerCompat;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;

import lecho.lib.hellocharts.view.PieChartView;

/**
 * Touch handler for PieChart. It doesn't handle zoom and scroll like default ChartTouchHandler. Instead it uses
 * Scroller(ScrollerCompat) directly to compute PieChart rotation when user scroll. ChartScroller and ChartZoomer are
 * not really used here.
 */
public class PieChartTouchHandler extends ChartTouchHandler {
    /**
     * The initial fling velocity is divided by this amount.
     */
    public static final int FLING_VELOCITY_DOWNSCALE = 4;
    /**
     * PieChartTouchHandler uses its own instance of Scroller.
     */
    protected ScrollerCompat scroller;
    /**
     * Reference to PieChartView to use some methods specific for that kind of chart.
     */
    protected PieChartView pieChart;

    private boolean isRotationEnabled = true;

    public PieChartTouchHandler(Context context, PieChartView chart) {
        super(context, chart);
        pieChart = (PieChartView) chart;
        scroller = ScrollerCompat.create(context);
        gestureDetector = new GestureDetector(context, new ChartGestureListener());
        scaleGestureDetector = new ScaleGestureDetector(context, new ChartScaleGestureListener());
        isZoomEnabled = false;// Zoom is not supported by PieChart.
    }

    @Override
    public boolean computeScroll() {
        if (!isRotationEnabled) {
            return false;
        }
        if (scroller.computeScrollOffset()) {
            pieChart.setChartRotation(scroller.getCurrY(), false);
            // pieChart.setChartRotation() will invalidate view so no need to return true;
        }
        return false;
    }

    @Override
    public boolean handleTouchEvent(MotionEvent event) {
        boolean needInvalidate = super.handleTouchEvent(event);

        if (isRotationEnabled) {
            needInvalidate = gestureDetector.onTouchEvent(event) || needInvalidate;
        }
        return needInvalidate;
    }

    public boolean isRotationEnabled() {
        return isRotationEnabled;
    }

    public void setRotationEnabled(boolean isRotationEnabled) {
        this.isRotationEnabled = isRotationEnabled;
    }

    private class ChartScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // No scale for PieChart.
            return false;
        }
    }

    private class ChartGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            if (isRotationEnabled) {
                scroller.abortAnimation();
                return true;
            }

            return false;

        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (isRotationEnabled) {
                // Set the pie rotation directly.
                final RectF circleOval = pieChart.getCircleOval();
                final float centerX = circleOval.centerX();
                final float centerY = circleOval.centerY();
                float scrollTheta = vectorToScalarScroll(distanceX, distanceY, e2.getX() - centerX, e2.getY() - centerY);
                pieChart.setChartRotation(pieChart.getChartRotation() - (int) scrollTheta / FLING_VELOCITY_DOWNSCALE,
                        false);
                return true;
            }

            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (isRotationEnabled) {
                // Set up the Scroller for a fling
                final RectF circleOval = pieChart.getCircleOval();
                final float centerX = circleOval.centerX();
                final float centerY = circleOval.centerY();
                float scrollTheta = vectorToScalarScroll(velocityX, velocityY, e2.getX() - centerX, e2.getY() - centerY);
                scroller.abortAnimation();
                scroller.fling(0, (int) pieChart.getChartRotation(), 0, (int) scrollTheta / FLING_VELOCITY_DOWNSCALE,
                        0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
                return true;
            }

            return false;
        }

        /**
         * Helper method for translating (x,y) scroll vectors into scalar rotation of the pie.
         *
         * @param dx The x component of the current scroll vector.
         * @param dy The y component of the current scroll vector.
         * @param x  The x position of the current touch, relative to the pie center.
         * @param y  The y position of the current touch, relative to the pie center.
         * @return The scalar representing the change in angular position for this scroll.
         */
        private float vectorToScalarScroll(float dx, float dy, float x, float y) {
            // get the length of the vector
            float l = (float) Math.sqrt(dx * dx + dy * dy);

            // decide if the scalar should be negative or positive by finding
            // the dot product of the vector perpendicular to (x,y).
            float crossX = -y;
            float crossY = x;

            float dot = (crossX * dx + crossY * dy);
            float sign = Math.signum(dot);

            return l * sign;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy