class PanZoom implements View.OnTouchListener {

    protected void zoom(final MotionEvent motionEvent) {
        if (zoom == Zoom.NONE) {
            return;
        }
        final RectF oldFingersRect = getFingersRect();
        final RectF newFingersRect = fingerDistance(motionEvent);
        setFingersRect(newFingersRect);
        if(oldFingersRect == null || RectFUtils.areIdentical(oldFingersRect, newFingersRect)) {
            // zooming gesture has not happened yet so skip:
            return;
        }
        RectF newRect = new RectF();

        float scaleX = 1;
        float scaleY = 1;
        switch (zoom) {
            case STRETCH_HORIZONTAL:
                scaleX = oldFingersRect.width() / getFingersRect().width();
                if (!isValidScale(scaleX)) {
                    return;
                }
                break;
            case STRETCH_VERTICAL:
                scaleY = oldFingersRect.height() / getFingersRect().height();
                if (!isValidScale(scaleY)) {
                    return;
                }
                break;
            case STRETCH_BOTH:
                scaleX = oldFingersRect.width() / getFingersRect().width();
                scaleY = oldFingersRect.height() / getFingersRect().height();
                if (!isValidScale(scaleX) || !isValidScale(scaleY)) {
                    return;
                }
                break;
            case SCALE:
                float sc1 = (float) Math.hypot(oldFingersRect.height(), oldFingersRect.width());
                float sc2 = (float) Math.hypot(getFingersRect().height(), getFingersRect().width());
                float sc = sc1 / sc2;
                scaleX = sc;
                scaleY = sc;
                if (!isValidScale(scaleX) || !isValidScale(scaleY)) {
                    return;
                }
                break;
        }

        if (EnumSet.of(
                Zoom.STRETCH_HORIZONTAL,
                Zoom.STRETCH_BOTH,
                Zoom.SCALE).contains(zoom)) {
            calculateZoom(newRect, scaleX, true);
            adjustDomainBoundary(newRect.left, newRect.right, BoundaryMode.FIXED);
        }
        if (EnumSet.of(
                Zoom.STRETCH_VERTICAL,
                Zoom.STRETCH_BOTH,
                Zoom.SCALE).contains(zoom)) {
            calculateZoom(newRect, scaleY, false);
            adjustRangeBoundary(newRect.top, newRect.bottom, BoundaryMode.FIXED);
        }
        plot.redraw();
    }

    protected  PanZoom(@NonNull XYPlot plot, Pan pan, Zoom zoom);
    protected  PanZoom(@NonNull XYPlot plot, Pan pan, Zoom zoom, ZoomLimit limit);

}