Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dragging rotated text inside android canvas does not work as expected

There is something I am missing inhere so I hope you can share some light on me.

I am drawing some text inside canvas. For this I have a class Word

public class Word {
     private int    x;
     private int    y;
     private String text;
}

The app allows the user to rotate the text, and I handle the rotation withing onDraw

protected void onDraw(Canvas canvas) {
    canvas.save(Canvas.MATRIX_SAVE_FLAG);
    canvas.rotate(angle, centerX, centerY)
    ...
    canvas.drawText(word.getText(), word.getX(), word.getY())
    ....
    canvas.restore();
}

The problem I get is when the user drags the canvas and there is a rotation set. When angle=0 the movement is going as expected.

@Override
    public boolean onTouchEvent(MotionEvent event) {
       case MotionEvent.ACTION_DOWN:
            initialX = (int) event.getX();
            initialY = (int) event.getY();
        break;
      case MotionEvent.ACTION_MOVE:
             int currentX = (int) event.getX();
             int currentY = (int) event.getY();
             int xMovement = currentX - initialX;
             int yMovement = currentY - initialY;

            dragWords(xMovement, yMovement);
   .....

and on dragWords for each word I do:

private void dragText(int xMovement, int yMovement){
for (Word word : words) {
    word.setX(word.getX() + xMovement);
    word.setY(word.getY() + yMovement);
}
invalidate();

}

When rotation angle is 0, moving up/down/left/right makes the words move by the same distance. As angle gets bigger, the words start to move in different dirrections, for instance at 60, it is starting to go diagonally up, when 180 it only moves up/down and not left/right.

I think I need to calculate some sort of a difference based on angle and add it to xMovement/yMovement... but how should I do this ?

LE: Here is an image on how it behaves: enter image description here The blue lines is how the text is moving on drag while the orange is the finger dragging on the screen. When angle is 0 it works quite well, when angle increases, it starts to move diagonally on left/right, while when angle is even bigger, it only moves up and down and does not respond to left/right

like image 582
Alin Avatar asked Jul 24 '14 16:07

Alin


1 Answers

If I understand correctly, the issue is that Canvas.rotate() does not only rotate the text direction, but rather the whole canvas. Therefore, the x-y coordinates of the words are also rotated from the specified pivot point.

In order to match the dragging movement, you can use a Matrix for this, more specifically the inverse matrix of the one you're using to rotate the canvas. It will be used to convert the x-y coordinates of the words to their original, pre-rotate locations.

For example, calculate this once, and update it whenever angle, centerX, or centerY changes.

// rotMatrix is the same operation applied on the canvas.
Matrix rotMatrix = new Matrix();
rotMatrix.postRotate(mAngle, centerX, centerY);

// Invert it to convert x, y to their transformed positions.
Matrix matrix = new Matrix();
rotMatrix.invert(matrix);

Then, when drawing each word:

int wordX = ... 
int wordY = ...
String text = ...

float[] coords = new float[] { wordX, wordY };
matrix.mapPoints(coords);
canvas.drawText(text, coords[0], coords[1], paint);
like image 138
matiash Avatar answered Sep 28 '22 01:09

matiash