Image in Canvas with Touch Events

Image in Canvas with touch events

You can use this:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

public class MyImageView extends View {

private static final int INVALID_POINTER_ID = -1;

private Drawable mImage;
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;

public MyImageView(Context context) {
this(context, null, 0);
mImage = getResources().getDrawable(R.drawable.imagename);

mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
}

public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}

@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;
}
}

return true;
}

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

canvas.save();
Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mImage.draw(canvas);
canvas.restore();
}

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;
}
}

}

How to move images over canvas by touch event?

you also need to take care of MSPointer events, that are events from Microsoft to manage touch (it was introduced with Win8 and WinPhone 8).

The steps needed, each frame:

  1. detect mouse, touch and MSPointer events
  2. check the cursor position colliding the images
  3. move the image

For the first point:

function getCursorPositions (event, canvas) {
var element = canvas, offsetX = 0, offsetY = 0, positions = [];

if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}

// Add padding and border style widths to offset
/*offsetX += stylePaddingLeft;
offsetY += stylePaddingTop;

offsetX += styleBorderLeft;
offsetY += styleBorderTop;*/

var touch = event;
//if multi-touch, get all the positions
if (event.targetTouches) { // or changedTouches
var touchPoints = (typeof event.targetTouches !== 'undefined') ? event.targetTouches : [event];
for (var i = 0; i < touchPoints.length; i++) {
touch = touchPoints[i];

positions.push({touch.pageX - offsetX, touch.pageY - offsetY});
}
}
else {
positions.push({touch.pageX - offsetX}, {touch.pageY - offsetY});
}

//return positions for mouse or fingers
return positions;
}

For the second point, you have at least 2 ways to detect the collision:

you can check whether the mouse position is inside the bounding box of your item :

function pointIsInRegion (point, targetRegion, threshold) {
return point.x >= (targetRegion.position.x - threshold) &&
point.y >= (targetRegion.position.y - threshold) &&
point.x <= (targetRegion.position.x + targetRegion.dimension.width + threshold) &&
point.y <= (targetRegion.position.y + targetRegion.dimension.height + threshold);
}

Or you can be more accurate by checking the pixels collision.
To achieve this second method, you have to render your items in a temporary canvas and check if there is at least pixels from your 2 items that collide (it can be accelerated by using masks).

For the third point (move the image), all you have to do is to move your image from "currentCursorPosition - previousCursorPosition". That's ths easiest part.

Anyway, I suggest you to use a framework. The code is already done and It will help you to go faster.
cgSceneGraph, (I'm the designer of this framework) will do the Job for you in just few lines.
Have a look at the "planner 2D" and "collision" examples (http://gwennaelbuchet.github.com/cgSceneGraph/examples.html)

Hope this can help you.

Assigning touch events to elements within canvas - iPad

You can't assign touch events to an image object. The only valid attributes are
onerror, onload, src, validate.

A related thread: Bind event to shape on canvas

Draw a Square on the HTML5 Canvas With Touch Events

Tested in Chrome with emulated touch events works with this jsFiddle The problem seems to be the way you bind your click event. I just used jQuery.

Or without jQuery: just a plain addEventListener



Related Topics



Leave a reply



Submit