title: Getting correct coordinates after pinch zoom (drawing line) Android Canvas
body: <p>I am trying to draw the line following by the users finger(touch). It is quite easy task to implement if there is no scaling.<br>
  Drawing without scaling works perfectly here is an screenshot     </p>
  
  <p><a href="https://i.stack.imgur.com/SMciL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/SMciL.png" alt="enter image description here"></a></p>
  
  <p>Works well. As you can see.    </p>
  
  <p>But if I scale an canvas it begins to draw points with some margin/measurement error/tolerance. It seems that I have not taken some value in advance while calculating scaled touch points, I have tried a lot of different formulas, but nothing helped.    </p>
  
  <p>Here is the result of zooming the canvas.
  <a href="https://i.stack.imgur.com/Cd05G.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Cd05G.png" alt="enter image description here"></a></p>
  
  <p>It seems that the problem in some delta value that I have to take into consideration</p>
  
  <p>Because if I use this version of scale function it works well but scales only to the left top corner.</p>
  
  <pre><code>canvas.scale(mScaleFactor, mScaleFactor); 
  </code></pre>
  
  <p>With this scaling </p>
  
  <pre><code>canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
  </code></pre>
  
  <p>Multitouch zoom (pinch) works well but coordinates are not correct.    </p>
  
  <p>Please help to solve the problem, it seems that I have to take these <code>scalePointX, scalePointY</code> variables when calculating scaled x and y.   </p>
  
  <p>Here is my code. Any help will be highly appreciated.   </p>
  
  <pre><code>private void initWorkSpace(Context context) {
          mPaint = new Paint();
          mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
          mRect = new Rect();
          mPath = new Path();
          mPaint.setAntiAlias(true);
          mPaint.setColor(Color.BLACK);
          mPaint.setStyle(Paint.Style.STROKE);
          mPaint.setStrokeJoin(Paint.Join.ROUND);
          mPaint.setStrokeWidth(10f);
      }
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
          canvas.getClipBounds(mRect);
          canvas.save();
          canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
          canvas.translate(mRect.top,mRect.left);
          canvas.drawPath(mPath, mPaint);
          canvas.restore();
  
      }
      // when ACTION_DOWN start touch according to the x,y values
      private void startTouch(float x, float y) {
          mPath.moveTo(x, y);
          mX = x;
          mY = y;
      }
  
      // when ACTION_MOVE move touch according to the x,y values
      private void moveTouch(float x, float y) {
          float dx = Math.abs(x - mX);
          float dy = Math.abs(y - mY);
          if (dx &gt;= TOLERANCE || dy &gt;= TOLERANCE) {
              mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
              mX = x;
              mY = y;
          }
      }
  
      public void clearCanvas() {
          mPath.reset();
          invalidate();
      }
  
      // when ACTION_UP stop touch
      private void upTouch() {
          mPath.lineTo(mX, mY);
      }
  
      @Override
      public boolean onTouchEvent(MotionEvent ev) {
          // Let the ScaleGestureDetector inspect all events.
          mScaleDetector.onTouchEvent(ev);
  
          final int action = ev.getAction();
          Log.e("TOUCH","REAL X :" + ev.getX() + " REAL Y : " + ev.getY());
          Log.e("TOUCH","RECT TOP :" + mRect.top + " RECT LEFT : " + mRect.left + " RECT RIGHT : " + mRect.right + " RECT BOTTOM :" + mRect.bottom);
          final float scaledX = ev.getX()/mScaleFactor+mRect.left*mScaleFactor;
          final float scaledY = ev.getY()/mScaleFactor+mRect.top*mScaleFactor;
          switch (action &amp; MotionEvent.ACTION_MASK) {
              case MotionEvent.ACTION_DOWN: {
  
                  /*final float x = (ev.getX() - scalePointX) / mScaleFactor;
                  final float y = (ev.getY() - scalePointY) / mScaleFactor;
                  cX = x - mPosX + scalePointX; // canvas X
                  cY = y - mPosY + scalePointY; // canvas Y*/
  
                  // Remember where we started
                  mLastTouchX = scaledX;
                  mLastTouchY = scaledY;
                  Log.e("DOWN","Scale FACTOR : " + mScaleFactor);
                  Log.e("DOWN","X : " +mLastTouchX + " Y :" + mLastTouchY + " scalePointX : " + scalePointX + " scalePointY : " + scalePointY );
  
                  Log.e("DOWN","Last X : " + mLastTouchY + " Last Y :" + mLastTouchY);
                  startTouch(mLastTouchX, mLastTouchY);
                  invalidate();
                  break;
              }
              case MotionEvent.ACTION_MOVE: {
                 /* final float x = (ev.getX() - scalePointX) / mScaleFactor;
                  final float y = (ev.getY() - scalePointY) / mScaleFactor;
                  cX = x - mPosX + scalePointX; // canvas X
                  cY = y - mPosY + scalePointY; // canvas Y
  
                  // Only move if the ScaleGestureDetector isn't processing a gesture.
                  if (!mScaleDetector.isInProgress()) {
                      final float dx = x - mLastTouchX; // change in X
                      final float dy = y - mLastTouchY; // change in Y
  
                      mPosX += dx;
                      mPosY += dy;
  
                      invalidate();
                  }*/
                  Log.e("ACTION_MOVE","Scale FACTOR : " + mScaleFactor);
                  Log.e("ACTION_MOVE","X : " + scaledX + " Y :" + scaledY + " cX : " + cX + " cY : " + cY );
                  Log.e("ACTION_MOVE","Last X : " + mLastTouchX + " Last Y :" + mLastTouchY);
                  mLastTouchX = scaledX;
                  mLastTouchY = scaledY;
                  moveTouch(scaledX, scaledY);
                  invalidate();
                  break;
  
              }
              case MotionEvent.ACTION_UP: {
                  mLastTouchX = 0;
                  mLastTouchY = 0;
                  upTouch();
                  invalidate();
              }
          }
          return true;
      }
  
      private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
          @Override
          public boolean onScale(ScaleGestureDetector detector) {
              mScaleFactor *= detector.getScaleFactor();
              scalePointX = detector.getFocusX();
              scalePointY = detector.getFocusY();
              // Don't let the object get too small or too large.
              mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
              mScaleFactor = (mScaleFactor &lt; 1 ? 1 : mScaleFactor);
              invalidate();
              return true;
          }
      }
  </code></pre>