@Override
  public boolean onDoubleTap(MotionEvent e) {

    mLastGesture = ChartGesture.DOUBLE_TAP;

    OnChartGestureListener l = mChart.getOnChartGestureListener();

    if (l != null) {
      l.onChartDoubleTapped(e);
      return super.onDoubleTap(e);
    }

    // check if double-tap zooming is enabled
    if (mChart.isDoubleTapToZoomEnabled()) {

      PointF trans = getTrans(e.getX(), e.getY());

      mChart.zoom(
          mChart.isScaleXEnabled() ? 1.4f : 1f,
          mChart.isScaleYEnabled() ? 1.4f : 1f,
          trans.x,
          trans.y);

      if (mChart.isLogEnabled())
        Log.i("BarlineChartTouch", "Double-Tap, Zooming In, x: " + trans.x + ", y: " + trans.y);
    }

    return super.onDoubleTap(e);
  }
  private void performDrag(MotionEvent event) {

    mLastGesture = ChartGesture.DRAG;

    mMatrix.set(mSavedMatrix);

    OnChartGestureListener l = mChart.getOnChartGestureListener();

    float dX, dY;

    // check if axis is inverted
    if (mChart.isAnyAxisInverted()
        && mClosestDataSetToTouch != null
        && mChart.getAxis(mClosestDataSetToTouch.getAxisDependency()).isInverted()) {

      // if there is an inverted horizontalbarchart
      if (mChart instanceof HorizontalBarChart) {
        dX = -(event.getX() - mTouchStartPoint.x);
        dY = event.getY() - mTouchStartPoint.y;
      } else {
        dX = event.getX() - mTouchStartPoint.x;
        dY = -(event.getY() - mTouchStartPoint.y);
      }
    } else {
      dX = event.getX() - mTouchStartPoint.x;
      dY = event.getY() - mTouchStartPoint.y;
    }

    mMatrix.postTranslate(dX, dY);

    if (l != null) l.onChartTranslate(event, dX, dY);
  }
  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

    OnChartGestureListener l = mChart.getOnChartGestureListener();

    if (l != null) l.onChartFling(e1, e2, velocityX, velocityY);

    return super.onFling(e1, e2, velocityX, velocityY);
  }
  @Override
  public void onLongPress(MotionEvent e) {

    OnChartGestureListener l = mChart.getOnChartGestureListener();

    if (l != null) {

      l.onChartLongPressed(e);
    }
  }
  @Override
  public boolean onSingleTapConfirmed(MotionEvent e) {

    OnChartGestureListener l = mChart.getOnChartGestureListener();

    if (l != null) {
      l.onChartSingleTapped(e);
    }

    return super.onSingleTapConfirmed(e);
  }
  @Override
  public boolean onSingleTapUp(MotionEvent e) {

    mLastGesture = ChartGesture.SINGLE_TAP;

    OnChartGestureListener l = mChart.getOnChartGestureListener();

    if (l != null) {
      l.onChartSingleTapped(e);
    }

    if (!mChart.isHighlightPerTapEnabled()) {
      return false;
    }

    Highlight h = mChart.getHighlightByTouchPoint(e.getX(), e.getY());
    performHighlight(h, e);

    return super.onSingleTapUp(e);
  }
  /**
   * Performs the all operations necessary for pinch and axis zoom.
   *
   * @param event
   */
  private void performZoom(MotionEvent event) {

    if (event.getPointerCount() >= 2) {

      OnChartGestureListener l = mChart.getOnChartGestureListener();

      // get the distance between the pointers of the touch
      // event
      float totalDist = spacing(event);

      if (totalDist > 10f) {

        // get the translation
        PointF t = getTrans(mTouchPointCenter.x, mTouchPointCenter.y);

        // take actions depending on the activated touch
        // mode
        if (mTouchMode == PINCH_ZOOM) {

          mLastGesture = ChartGesture.PINCH_ZOOM;

          float scale = totalDist / mSavedDist; // total scale

          boolean isZoomingOut = (scale < 1);
          boolean canZoomMoreX =
              isZoomingOut
                  ? mChart.getViewPortHandler().canZoomOutMoreX()
                  : mChart.getViewPortHandler().canZoomInMoreX();

          float scaleX = (mChart.isScaleXEnabled()) ? scale : 1f;
          float scaleY = (mChart.isScaleYEnabled()) ? scale : 1f;

          if (mChart.isScaleYEnabled() || canZoomMoreX) {

            mMatrix.set(mSavedMatrix);
            mMatrix.postScale(scaleX, scaleY, t.x, t.y);

            if (l != null) l.onChartScale(event, scaleX, scaleY);
          }

        } else if (mTouchMode == X_ZOOM && mChart.isScaleXEnabled()) {

          mLastGesture = ChartGesture.X_ZOOM;

          float xDist = getXDist(event);
          float scaleX = xDist / mSavedXDist; // x-axis scale

          boolean isZoomingOut = (scaleX < 1);
          boolean canZoomMoreX =
              isZoomingOut
                  ? mChart.getViewPortHandler().canZoomOutMoreX()
                  : mChart.getViewPortHandler().canZoomInMoreX();

          if (canZoomMoreX) {

            mMatrix.set(mSavedMatrix);
            mMatrix.postScale(scaleX, 1f, t.x, t.y);

            if (l != null) l.onChartScale(event, scaleX, 1f);
          }

        } else if (mTouchMode == Y_ZOOM && mChart.isScaleYEnabled()) {

          mLastGesture = ChartGesture.Y_ZOOM;

          float yDist = getYDist(event);
          float scaleY = yDist / mSavedYDist; // y-axis scale

          mMatrix.set(mSavedMatrix);

          // y-axis comes from top to bottom, revert y
          mMatrix.postScale(1f, scaleY, t.x, t.y);

          if (l != null) l.onChartScale(event, 1f, scaleY);
        }
      }
    }
  }