23

I'm developing an application in which I'm pasting images, doing drawing and painting on canvas. This app can also Scale up/down the canvas or drag it to different location. My problem is: I can't get the correct canvas coordinates after scaling or dragging the canvas. I want to draw finger paint after the canvas is scaled or dragged but unable to retrieve the right place where i've touched..:( Also I'm new bee. Here is the code.

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    //canvas.translate(mPosX, mPosY);
    canvas.scale(mScaleFactor, mScaleFactor, super.getWidth() * 0.5f,
            super.getHeight() * 0.5f);
    mIcon.draw(canvas);
    for (Path path : listPath) {
        canvas.drawPath(path, paint);
    }
    canvas.restore();
}

public TouchExampleView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // Let the ScaleGestureDetector inspect all events.
    mScaleDetector.onTouchEvent(ev);

    final int action = ev.getAction();
    switch (action & 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);
        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() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> 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;
    }
    }

    float objectNewX,objectNewY;
    if (mScaleFactor >= 1) {
        objectNewX = ev.getX() + (ev.getX() - super.getWidth() * 0.5f) * (mScaleFactor - 1);
        objectNewY = ev.getY() + (ev.getY() - super.getHeight() * 0.5f) * (mScaleFactor - 1);
    } else {
        objectNewX = ev.getX() - (ev.getX() - super.getWidth() * 0.5f) * (1 - mScaleFactor);
        objectNewY = ev.getY() - (ev.getY() - super.getHeight() * 0.5f) * (1 - mScaleFactor);
    }

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        path = new Path();
        path.moveTo(objectNewX,objectNewY);
        path.lineTo(objectNewX,objectNewY);
    } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
        path.lineTo(objectNewX,objectNewY);
        listPath.add(path);
    } else if (ev.getAction() == MotionEvent.ACTION_UP) {
        path.lineTo(objectNewX,objectNewY);
        listPath.add(path);
    }

    return true;
}

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, 5.0f));

        invalidate();
        return true;
    }
}
Marek Grzenkowicz
  • 17,024
  • 9
  • 81
  • 111
Awais Tariq
  • 7,724
  • 5
  • 31
  • 54
  • *I can't get the correct canvas coordinates*. You have to be more specific. Does the scale itself work? Define what you expect as *correct canvas coordinates*? What is wrong with them right now? – Knickedi Sep 23 '11 at 14:01
  • try to zoom the image and then paint something on canvas..then u'll come to know. – Awais Tariq Sep 23 '11 at 16:03
  • also uncomment canvas.translate(mPosX, mPosY); – Awais Tariq Sep 23 '11 at 16:04
  • If I draw something on canvas prior to translation or scaling it works fine. But after translation / scaling it don't. I need a way to draw correctly even after scaling or translating...:> – Awais Tariq Sep 26 '11 at 05:14

2 Answers2

27

Done it finally by myself.

Draw everything by applying this formula to (px,py) coordinates:

float px = ev.getX() / mScaleFactor + rect.left;
float py = ev.getY() / mScaleFactor + rect.top;
rect = canvas.getClipBounds();
//Get them in on Draw function and apply above formula before drawing
random
  • 9,774
  • 10
  • 66
  • 83
Awais Tariq
  • 7,724
  • 5
  • 31
  • 54
  • Hey awais I am also stuck at the same thing. I did not understood your solution properly can you please share ur code or help me with the same ? – user1169079 Apr 09 '12 at 07:51
  • where is your problem??? In my case, where I have to draw something on screen I used float x = ev.getX() / mScaleFactor + rect.left; for X instead of event.getX(); similarly for Y axis. Rect is the clipbounds of the drawn canvas. We have to save it in some rectangle variable. They are continuously updating in onDraw function. – Awais Tariq Apr 09 '12 at 10:01
  • http://stackoverflow.com/questions/9989170/clickable-area-after-scaling-with-respect-to-positions-of-touch-event .. check this if u can help it will be great... – user1169079 Apr 10 '12 at 06:00
  • Need your help again ... I have achieved that zooming thanks to you for that offset value. Now I have added scrolling in that using ScaleGestureDetector.SimpleOnScaleGestureListener - onScroll method... Now again i have stuck to that offset thing ? It would be gr8 again if you help me with that – user1169079 Jun 09 '12 at 07:52
  • http://stackoverflow.com/questions/10800555/how-should-i-implement-scrolling/10959399#10959399 – user1169079 Jun 09 '12 at 09:30
  • this px and py will go with canvas.scale(). Awesome – Prabs Apr 06 '17 at 12:35
  • can someone please tell me what is mScaleFactor in this code? and where should i need to set it. – Mubashir Murtaza Aug 10 '20 at 07:23
10
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    clipBounds_canvas = canvas.getClipBounds();
    /////Do whatever you want to do..!!!            
};

@Override
public boolean onTouchEvent(MotionEvent ev) {
    int x = ev.getX() / zoomFactor + clipBounds_canvas.left;
    int y = ev.getY() / zoomFactor + clipBounds_canvas.top;
    //Use the above two values insted of ev.getX() and ev.getY();
}

Hope this will help.

dakshbhatt21
  • 3,558
  • 3
  • 31
  • 40
Awais Tariq
  • 7,724
  • 5
  • 31
  • 54
  • Those above two values x and y are the offset where my hit area / click are will be ? Or I need to update my draw objects using the above x and y value ? – user1169079 Apr 10 '12 at 10:30
  • you need to update draw objects i guess according to above mentioned relative x and y's. – Awais Tariq Apr 10 '12 at 10:58
  • Thanks mate!!! I have got where my object is moving ..but I do not how to move the clickable area to the same position I am working on..if you have any idea do suggest !!! I tried getHitRect and add the offset it to it ? dint work !!! – user1169079 Apr 10 '12 at 11:17
  • bro Need your help again ... I added the scroll functionality to layout after zoom .. Again stuck at the offset point ? Check out the answer of this link http://stackoverflow.com/questions/10800555/how-should-i-implement-scrolling – user1169079 Jun 13 '12 at 03:56
  • paste some code boy... I guess the above calculations should work for both zooming and scaling..:\ – Awais Tariq Jun 13 '12 at 04:26
  • I will send you the whole code ? where should i send u ? actually check out the answer of that question d oly changes i have done in that questions code... – user1169079 Jun 13 '12 at 05:25
  • I mean just change that onScroll of the question code... from the answer which I have posted in down in that link. Its the whole code of the custom relative layout.. and i tried old calculation did not work .. please help ... thanks bro !! – user1169079 Jun 13 '12 at 05:27
  • ok here is the link of myquestion http://stackoverflow.com/questions/11012213/offset-of-hitarea-after-zooming-and-scrolling – user1169079 Jun 13 '12 at 09:44
  • @Awais Tariq I'm facing the similar problem but since i'm using the Matrix for zoom and purpose i'm not able to understand how to zoom the Path drawn over the Canvas , here is my question. http://stackoverflow.com/questions/12312617/android-canvas-zoom-and-drag-while-drawing – strike Sep 08 '12 at 07:30
  • what is zoom factor here? can someone please define this? – Mubashir Murtaza Aug 10 '20 at 07:26