Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

centered zoom in custom view - calculating canvas coordinates

I am working on my first "real" Android application, a graphical workflow editor. The drawing is done in a custom class, that is a subclass of View.At the moment my elements are rectangles, which are drawn on a canvas. To detect actions on elements I compare the coordinates and check for elements on the touch location.

To implement a zoom gesture I tried http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html

With the 4 argument canvas.scale(...) function the centered zooming works well, but I lose the ability to calculate the canvas coordinates using the offset with mPosX and mPosY to detect if the touch after a zoom is on an element.

I tried to change the example in the blogpost above to center the canvas on the zoom gesture with:

canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, mScalePivotX, mScalePivotY);
//drawing ....
canvas.restore();

I did not find any examples on how this could be done without losing the reference offset to calculate the coordinates. Is there an easy workaround? I tried to calculate the offset with the gesture center and the scaling factor, but failed :/

I have seen that other examples which use an ImageView often use a Matrix to transform the image. Could this be done with a custom View and a Canvas? If yes, how can I get the x and y offset to check the coordinates?

Also, if my ideas are completely wrong, I would be very happy to see some examples on how this is done properly.

Thx! ;)

like image 544
m4tt Avatar asked Mar 18 '11 20:03

m4tt


1 Answers

Perhaps the following code will help you to calculate coordinates with the gesture center and the scaling factor. I use this method in my class representing opengl-sprite.

void zoom(float scale, PointF midPoint) {
    if (zoomFactor == MAX_ZOOM_FACTOR && scale > 1) return;
    if (zoomFactor == MIN_ZOOM_FACTOR && scale < 1) return;

    zoomFactor *= scale;
    x = (x - midPoint.x) * scale + midPoint.x;
    y = (y - height + midPoint.y) * scale + height - midPoint.y;
    if (zoomFactor >= MAX_ZOOM_FACTOR) {
        zoomFactor = MAX_ZOOM_FACTOR;
    } else if (zoomFactor < MIN_ZOOM_FACTOR) {
        zoomFactor = MIN_ZOOM_FACTOR;
        x = 0;
        y = 0;
    }
}

X and Y coordinates are processed in different ways, because of distinction between directions of opengl coordinate system (right and up) and midPoint's coordinate system (right and down). midPoint is taken from MotionEvents coordinates.

All other operations are understandable, i think.

Hope it will help you.

like image 115
Andrei Buneyeu Avatar answered Nov 15 '22 03:11

Andrei Buneyeu