16224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalapackage com.androidplot.xy;
26224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
36224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.content.Context;
46224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.graphics.PointF;
56224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.util.AttributeSet;
66224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.view.MotionEvent;
76224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.view.View;
86224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalaimport android.view.View.OnTouchListener;
96224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvalapublic class XYPlotZoomPan extends XYPlot implements OnTouchListener {
116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private static final float MIN_DIST_2_FING = 5f;
126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    // Definition of the touch states
146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private enum State
156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    {
166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        NONE,
176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        ONE_FINGER_DRAG,
186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        TWO_FINGERS_DRAG
196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private State mode = State.NONE;
226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float minXLimit = Float.MAX_VALUE;
236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float maxXLimit = Float.MAX_VALUE;
246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float minYLimit = Float.MAX_VALUE;
256224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float maxYLimit = Float.MAX_VALUE;
266224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float lastMinX = Float.MAX_VALUE;
276224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float lastMaxX = Float.MAX_VALUE;
286224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float lastMinY = Float.MAX_VALUE;
296224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float lastMaxY = Float.MAX_VALUE;
306224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private PointF firstFingerPos;
316224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float mDistX;
326224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mZoomEnabled; //default is enabled
336224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mZoomVertically;
346224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mZoomHorizontally;
356224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mCalledBySelf;
366224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mZoomEnabledInit;
376224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mZoomVerticallyInit;
386224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private boolean mZoomHorizontallyInit;
396224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
406224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public XYPlotZoomPan(Context context, String title, RenderMode mode) {
416224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super(context, title, mode);
426224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        setZoomEnabled(true); //Default is ZoomEnabled if instantiated programmatically
436224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
446224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
456224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public XYPlotZoomPan(final Context context, final AttributeSet attrs) {
466224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super(context, attrs);
476224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mZoomEnabled || !mZoomEnabledInit) {
486224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            setZoomEnabled(true);
496224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
506224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(!mZoomHorizontallyInit) {
516224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mZoomHorizontally = true;
526224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
536224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(!mZoomVerticallyInit) {
546224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mZoomVertically = true;
556224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
566224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
576224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
586224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public XYPlotZoomPan(final Context context, final AttributeSet attrs, final int defStyle) {
596224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super(context, attrs, defStyle);
606224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mZoomEnabled || !mZoomEnabledInit) {
616224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            setZoomEnabled(true);
626224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
636224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(!mZoomHorizontallyInit) {
646224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mZoomHorizontally = true;
656224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
666224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(!mZoomVerticallyInit) {
676224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mZoomVertically = true;
686224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
696224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
706224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
716224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public XYPlotZoomPan(final Context context, final String title) {
726224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super(context, title);
736224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
746224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
756224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    @Override
766224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public void setOnTouchListener(OnTouchListener l) {
776224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(l != this) {
786224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mZoomEnabled = false;
796224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
806224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super.setOnTouchListener(l);
816224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
826224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
836224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public boolean getZoomVertically() {
846224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return mZoomVertically;
856224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
866224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
876224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public void setZoomVertically(boolean zoomVertically) {
886224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mZoomVertically = zoomVertically;
896224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mZoomVerticallyInit = true;
906224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
916224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
926224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public boolean getZoomHorizontally() {
936224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return mZoomHorizontally;
946224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
956224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
966224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public void setZoomHorizontally(boolean zoomHorizontally) {
976224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mZoomHorizontally = zoomHorizontally;
986224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mZoomHorizontallyInit = true;
996224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1006224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1016224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public void setZoomEnabled(boolean enabled) {
1026224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(enabled) {
1036224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            setOnTouchListener(this);
1046224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
1056224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            setOnTouchListener(null);
1066224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1076224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mZoomEnabled = enabled;
1086224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mZoomEnabledInit = true;
1096224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public boolean getZoomEnabled() {
1126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return mZoomEnabled;
1136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getMinXLimit() {
1166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(minXLimit == Float.MAX_VALUE) {
1176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            minXLimit = getCalculatedMinX().floatValue();
1186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinX = minXLimit;
1196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return minXLimit;
1216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getMaxXLimit() {
1246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(maxXLimit == Float.MAX_VALUE) {
1256224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            maxXLimit = getCalculatedMaxX().floatValue();
1266224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxX = maxXLimit;
1276224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1286224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return maxXLimit;
1296224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1306224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1316224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getMinYLimit() {
1326224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(minYLimit == Float.MAX_VALUE) {
1336224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            minYLimit = getCalculatedMinY().floatValue();
1346224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinY = minYLimit;
1356224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1366224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return minYLimit;
1376224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1386224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1396224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getMaxYLimit() {
1406224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(maxYLimit == Float.MAX_VALUE) {
1416224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            maxYLimit = getCalculatedMaxY().floatValue();
1426224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxY = maxYLimit;
1436224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1446224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return maxYLimit;
1456224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1466224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1476224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getLastMinX() {
1486224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(lastMinX == Float.MAX_VALUE) {
1496224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinX = getCalculatedMinX().floatValue();
1506224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1516224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return lastMinX;
1526224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1536224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1546224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getLastMaxX() {
1556224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(lastMaxX == Float.MAX_VALUE) {
1566224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxX = getCalculatedMaxX().floatValue();
1576224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1586224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return lastMaxX;
1596224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1606224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1616224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getLastMinY() {
1626224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(lastMinY == Float.MAX_VALUE) {
1636224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinY = getCalculatedMinY().floatValue();
1646224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1656224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return lastMinY;
1666224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1676224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1686224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getLastMaxY() {
1696224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(lastMaxY == Float.MAX_VALUE) {
1706224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxY = getCalculatedMaxY().floatValue();
1716224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1726224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return lastMaxY;
1736224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1746224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1756224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    @Override
1766224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public synchronized void setDomainBoundaries(final Number lowerBoundary, final BoundaryMode lowerBoundaryMode, final Number upperBoundary, final BoundaryMode upperBoundaryMode) {
1776224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super.setDomainBoundaries(lowerBoundary, lowerBoundaryMode, upperBoundary, upperBoundaryMode);
1786224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mCalledBySelf) {
1796224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = false;
1806224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
1816224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            minXLimit = lowerBoundaryMode == BoundaryMode.FIXED ? lowerBoundary.floatValue() : getCalculatedMinX().floatValue();
1826224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            maxXLimit = upperBoundaryMode == BoundaryMode.FIXED ? upperBoundary.floatValue() : getCalculatedMaxX().floatValue();
1836224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinX = minXLimit;
1846224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxX = maxXLimit;
1856224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1866224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
1876224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
1886224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    @Override
1896224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public synchronized void setRangeBoundaries(final Number lowerBoundary, final BoundaryMode lowerBoundaryMode, final Number upperBoundary, final BoundaryMode upperBoundaryMode) {
1906224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super.setRangeBoundaries(lowerBoundary, lowerBoundaryMode, upperBoundary, upperBoundaryMode);
1916224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mCalledBySelf) {
1926224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = false;
1936224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
1946224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            minYLimit = lowerBoundaryMode == BoundaryMode.FIXED ? lowerBoundary.floatValue() : getCalculatedMinY().floatValue();
1956224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            maxYLimit = upperBoundaryMode == BoundaryMode.FIXED ? upperBoundary.floatValue() : getCalculatedMaxY().floatValue();
1966224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinY = minYLimit;
1976224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxY = maxYLimit;
1986224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
1996224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
2006224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
2016224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    @Override
2026224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public synchronized void setDomainBoundaries(final Number lowerBoundary, final Number upperBoundary, final BoundaryMode mode) {
2036224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super.setDomainBoundaries(lowerBoundary, upperBoundary, mode);
2046224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mCalledBySelf) {
2056224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = false;
2066224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
2076224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            minXLimit = mode == BoundaryMode.FIXED ? lowerBoundary.floatValue() : getCalculatedMinX().floatValue();
2086224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            maxXLimit = mode == BoundaryMode.FIXED ? upperBoundary.floatValue() : getCalculatedMaxX().floatValue();
2096224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinX = minXLimit;
2106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxX = maxXLimit;
2116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
2126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
2136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
2146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    @Override
2156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public synchronized void setRangeBoundaries(final Number lowerBoundary, final Number upperBoundary, final BoundaryMode mode) {
2166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        super.setRangeBoundaries(lowerBoundary, upperBoundary, mode);
2176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mCalledBySelf) {
2186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = false;
2196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
2206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            minYLimit = mode == BoundaryMode.FIXED ? lowerBoundary.floatValue() : getCalculatedMinY().floatValue();
2216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            maxYLimit = mode == BoundaryMode.FIXED ? upperBoundary.floatValue() : getCalculatedMaxY().floatValue();
2226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinY = minYLimit;
2236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxY = maxYLimit;
2246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
2256224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
2266224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
2276224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    @Override
2286224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    public boolean onTouch(final View view, final MotionEvent event) {
2296224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        switch (event.getAction() & MotionEvent.ACTION_MASK)
2306224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        {
2316224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            case MotionEvent.ACTION_DOWN: // start gesture
2326224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                firstFingerPos = new PointF(event.getX(), event.getY());
2336224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                mode = State.ONE_FINGER_DRAG;
2346224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                break;
2356224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            case MotionEvent.ACTION_POINTER_DOWN: // second finger
2366224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            {
2376224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                mDistX = getXDistance(event);
2386224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                // the distance check is done to avoid false alarms
2396224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                if(mDistX > MIN_DIST_2_FING || mDistX < -MIN_DIST_2_FING) {
2406224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                    mode = State.TWO_FINGERS_DRAG;
2416224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                }
2426224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                break;
2436224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
2446224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            case MotionEvent.ACTION_POINTER_UP: // end zoom
2456224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                mode = State.NONE;
2466224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                break;
2476224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            case MotionEvent.ACTION_MOVE:
2486224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                if(mode == State.ONE_FINGER_DRAG) {
2496224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                    pan(event);
2506224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                } else if(mode == State.TWO_FINGERS_DRAG) {
2516224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                    zoom(event);
2526224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                }
2536224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                break;
2546224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
2556224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return true;
2566224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
2576224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
2586224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private float getXDistance(final MotionEvent event) {
2596224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        return event.getX(0) - event.getX(1);
2606224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
2616224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
2626224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private void pan(final MotionEvent motionEvent) {
2636224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final PointF oldFirstFinger = firstFingerPos; //save old position of finger
2646224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        firstFingerPos = new PointF(motionEvent.getX(), motionEvent.getY()); //update finger position
2656224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        PointF newX = new PointF();
2666224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mZoomHorizontally) {
2676224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            calculatePan(oldFirstFinger, newX, true);
2686224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = true;
2696224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            super.setDomainBoundaries(newX.x, newX.y, BoundaryMode.FIXED);
2706224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinX = newX.x;
2716224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxX = newX.y;
2726224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
2736224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mZoomVertically) {
2746224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            calculatePan(oldFirstFinger, newX, false);
2756224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = true;
2766224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            super.setRangeBoundaries(newX.x, newX.y, BoundaryMode.FIXED);
2776224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinY = newX.x;
2786224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxY = newX.y;
2796224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
2806224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        redraw();
2816224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
2826224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
2836224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private void calculatePan(final PointF oldFirstFinger, PointF newX, final boolean horizontal) {
2846224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float offset;
2856224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        // multiply the absolute finger movement for a factor.
2866224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        // the factor is dependent on the calculated min and max
2876224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(horizontal) {
2886224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            newX.x = getLastMinX();
2896224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            newX.y = getLastMaxX();
2906224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            offset = (oldFirstFinger.x - firstFingerPos.x) * ((newX.y - newX.x) / getWidth());
2916224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
2926224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            newX.x = getLastMinY();
2936224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            newX.y = getLastMaxY();
2946224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            offset = -(oldFirstFinger.y - firstFingerPos.y) * ((newX.y - newX.x) / getHeight());
2956224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
2966224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        // move the calculated offset
2976224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        newX.x = newX.x + offset;
2986224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        newX.y = newX.y + offset;
2996224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        //get the distance between max and min
3006224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float diff = newX.y - newX.x;
3016224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        //check if we reached the limit of panning
3026224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(horizontal) {
3036224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.x < getMinXLimit()) {
3046224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.x = getMinXLimit();
3056224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.y = newX.x + diff;
3066224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3076224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.y > getMaxXLimit()) {
3086224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.y = getMaxXLimit();
3096224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.x = newX.y - diff;
3106224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3116224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
3126224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.x < getMinYLimit()) {
3136224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.x = getMinYLimit();
3146224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.y = newX.x + diff;
3156224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3166224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.y > getMaxYLimit()) {
3176224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.y = getMaxYLimit();
3186224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.x = newX.y - diff;
3196224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3206224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3216224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
3226224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
3236224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private void zoom(final MotionEvent motionEvent) {
3246224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float oldDist = mDistX;
3256224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float newDist = getXDistance(motionEvent);
3266224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        // sign change! Fingers have crossed ;-)
3276224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(oldDist > 0 && newDist < 0 || oldDist < 0 && newDist > 0) {
3286224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            return;
3296224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3306224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        mDistX = newDist;
3316224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        float scale = (oldDist / mDistX);
3326224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        // sanity check
3336224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(Float.isInfinite(scale) || Float.isNaN(scale) || scale > -0.001 && scale < 0.001) {
3346224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            return;
3356224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3366224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        PointF newX = new PointF();
3376224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mZoomHorizontally) {
3386224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            calculateZoom(scale, newX, true);
3396224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = true;
3406224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            super.setDomainBoundaries(newX.x, newX.y, BoundaryMode.FIXED);
3416224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinX = newX.x;
3426224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxX = newX.y;
3436224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3446224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(mZoomVertically) {
3456224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            calculateZoom(scale, newX, false);
3466224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            mCalledBySelf = true;
3476224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            super.setRangeBoundaries(newX.x, newX.y, BoundaryMode.FIXED);
3486224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMinY = newX.x;
3496224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            lastMaxY = newX.y;
3506224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3516224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        redraw();
3526224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
3536224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala
3546224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    private void calculateZoom(float scale, PointF newX, final boolean horizontal) {
3556224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float calcMax;
3566224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float span;
3576224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(horizontal) {
3586224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            calcMax = getLastMaxX();
3596224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            span = calcMax - getLastMinX();
3606224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
3616224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            calcMax = getLastMaxY();
3626224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            span = calcMax - getLastMinY();
3636224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3646224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float midPoint = calcMax - (span / 2.0f);
3656224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        final float offset = span * scale / 2.0f;
3666224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        newX.x = midPoint - offset;
3676224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        newX.y = midPoint + offset;
3686224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        if(horizontal) {
3696224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.x < getMinXLimit()) {
3706224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.x = getMinXLimit();
3716224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3726224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.y > getMaxXLimit()) {
3736224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.y = getMaxXLimit();
3746224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3756224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        } else {
3766224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.x < getMinYLimit()) {
3776224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.x = getMinYLimit();
3786224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3796224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            if(newX.y > getMaxYLimit()) {
3806224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala                newX.y = getMaxYLimit();
3816224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala            }
3826224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala        }
3836224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala    }
3846224eda509d436a575f801942337da92a6c18767Eino-Ville Talvala}
385