title: How to calculate coordinates of scaled canvas in Android
body: <p>I am working with Android project. I have trouble with understand how to use ScaleDetector and Canvas.</p>
  
  <p>I have list called printTable with Rectangles. I draw every Rectangle on screen in method onDraw(). 
  Then I have second list called listPointer with Rectangles and id's of Rectangles. I am checking that list onTouchEvent for rectangle that is draw on screen. If Rectangle contains X,Y I print information about id of clicked Rectangle. </p>
  
  <p>The problem is how to calculate my X,Y when I move my canvas or scale it?</p>
  
  <pre><code>public class Painter extends View {
  
      //
      private static final int INVALID_POINTER_ID = -1;
      private float mPosX;
      private float mPosY;
  
      private float mLastTouchX;
      private float mLastTouchY;
      private int mActivePointerId = INVALID_POINTER_ID;
  
      private ScaleGestureDetector mScaleDetector;
      private float mScaleFactor = 1.f;
      //
  
      Paint paint = new Paint();
  
      List&lt;Table&gt; printTable = new ArrayList&lt;Table&gt;(); // lista wyświetlanych stolików
  
      //
      List&lt;Pointer&gt; listPointer = new ArrayList&lt;Pointer&gt;();
      //
  
      public Painter(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public Painter(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
          mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
      }
  
      private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
          @Override
          public boolean onScale(ScaleGestureDetector detector) {
              mScaleFactor *= detector.getScaleFactor();
  
              // Don't let the object get too small or too large.
              mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
  
              invalidate();
              return true;
          }
      }
  
      @Override
      public boolean onTouchEvent(MotionEvent ev) {
          // Let the ScaleGestureDetector inspect all events.
          mScaleDetector.onTouchEvent(ev);
  
          final int action = ev.getAction();
          switch (action &amp; MotionEvent.ACTION_MASK) {
          case MotionEvent.ACTION_DOWN: {
              final float x = ev.getX();
              final float y = ev.getY();
  
              mLastTouchX = x;
              mLastTouchY = y;
              mActivePointerId = ev.getPointerId(0);
              for(int i = 0; i&lt;listPointer.size(); i++)
              {
                  if(listPointer.get(i).getRectangle().contains((int)(Math.round(x)), (int)(Math.round(y))))
                  {
                      if(listPointer.get(i).getIsItTable())
                      {
                          Log.e("Exc", "Stolik "+listPointer.get(i).getId());
                      }
                      else
                      {
                          Log.e("Exc", "Button "+listPointer.get(i).getId());
                      }
                  }
              }
              break;
          }
  
          case MotionEvent.ACTION_MOVE: {
              final int pointerIndex = ev.findPointerIndex(mActivePointerId);
              final float x = ev.getX(pointerIndex);
              final float y = ev.getY(pointerIndex);
  
              // Only move if the ScaleGestureDetector isn't processing a gesture.
              if (!mScaleDetector.isInProgress()) {
                  final float dx = x - mLastTouchX;
                  final float dy = y - mLastTouchY;
  
                  mPosX += dx;
                  mPosY += dy;
  
                  invalidate();
              }
  
              mLastTouchX = x;
              mLastTouchY = y;
  
              break;
          }
  
          case MotionEvent.ACTION_UP: {
              mActivePointerId = INVALID_POINTER_ID;
              break;
          }
  
          case MotionEvent.ACTION_CANCEL: {
              mActivePointerId = INVALID_POINTER_ID;
              break;
          }
  
          case MotionEvent.ACTION_POINTER_UP: {
              final int pointerIndex = (ev.getAction() &amp; MotionEvent.ACTION_POINTER_INDEX_MASK) 
                      &gt;&gt; MotionEvent.ACTION_POINTER_INDEX_SHIFT;
              final int pointerId = ev.getPointerId(pointerIndex);
              if (pointerId == mActivePointerId) {
                  // This was our active pointer going up. Choose a new
                  // active pointer and adjust accordingly.
                  final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                  mLastTouchX = ev.getX(newPointerIndex);
                  mLastTouchY = ev.getY(newPointerIndex);
                  mActivePointerId = ev.getPointerId(newPointerIndex);
              }
              break;
          }
          }
  
          return true;
      }
  
      //
  
      public Painter(Context context) {
  
          this(context, null, 0);
  
          paint.setColor(Color.BLACK);
  
          List&lt;Table&gt; printTable = Bridge.getTables(getContext()); 
  
      }
  
      @SuppressLint("DrawAllocation")
      @Override
      public void onDraw(Canvas canvas) {
  
          super.onDraw(canvas);
              Rect rect = null;
              RectF rectF = null;
              // czyszczenie tablicy
              listPointer.clear();
  
              for(int j = 0; j&lt;printTable.size(); j++)
              {
                  Table item = printTable.get(j);
                  // Obsługa rozciągania
  
                  canvas.save();
                  Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
                  canvas.translate(mPosX, mPosY);
                  canvas.scale(mScaleFactor, mScaleFactor);
  
                  // dodaje do tablicy stołów
                  paint.setColor(getResources().getColor(R.color.green));
                  rect = new Rect(item.getX1(), item.getY1(), item.getX2(), item.getY2());
                  rectF = new RectF(rect);
                  canvas.drawRoundRect(rectF, 0,0, paint);
                  listPointer.add(new Pointer(rect, true, j));
  
                  canvas.restore();
              }
      }
  </code></pre>