I have an image loaded into the canvas. I can't (drag) move the image properly, after it is rotated. Actually, it moves but it moves based on the image's coordinate plane. So moving a 90 degree rotated image to the right, moves down and not to the right as expected. What could be a good way to solve this problem?
This is my draw function:
function draw(){
var im_width = parseInt( imageObj.width + resizeAmount );
var im_height = parseInt( imageObj.height + resizeAmount );
var rotationAmount = rotationVal - prevRotation;
prevRotation = rotationVal;
context.clearRect( 0, 0, canvas.width, canvas.height );
context.translate( canvas.width/2, canvas.height/2 );
context.rotate( rotationAmount * Math.PI / 180 );
context.translate( -canvas.width/2, -canvas.height/2 );
context.drawImage( imageObj, moveXAmount, moveYAmount, im_width, im_height );
}
Here is the jsdiddle where you can simulate it and see what I mean.
PS: You can rotate the image with the slider on the left. The bottom slider is for zooming. Please re-run the fiddle if the image does not appear in the first load.
I have an image loaded into the canvas. I can't (drag) move the image properly, after it is rotated. Actually, it moves but it moves based on the image's coordinate plane. So moving a 90 degree rotated image to the right, moves down and not to the right as expected. What could be a good way to solve this problem?
This is my draw function:
function draw(){
var im_width = parseInt( imageObj.width + resizeAmount );
var im_height = parseInt( imageObj.height + resizeAmount );
var rotationAmount = rotationVal - prevRotation;
prevRotation = rotationVal;
context.clearRect( 0, 0, canvas.width, canvas.height );
context.translate( canvas.width/2, canvas.height/2 );
context.rotate( rotationAmount * Math.PI / 180 );
context.translate( -canvas.width/2, -canvas.height/2 );
context.drawImage( imageObj, moveXAmount, moveYAmount, im_width, im_height );
}
Here is the jsdiddle where you can simulate it and see what I mean.
PS: You can rotate the image with the slider on the left. The bottom slider is for zooming. Please re-run the fiddle if the image does not appear in the first load.
Share Improve this question asked May 18, 2015 at 19:14 SkeletorSkeletor 3,4135 gold badges36 silver badges56 bronze badges2 Answers
Reset to default 8Reset the transformations after drawing. The mouse events are transformed as well when applied to the canvas context so using transforms only when drawing can solve this. However, this also require the code to use absolute values, for example:
function draw(){
var im_width = parseInt( imageObj.width + resizeAmount, 10 );
var im_height = parseInt( imageObj.height + resizeAmount, 10 );
var rotationAmount = rotationVal; // disabled: - prevRotation;
context.clearRect( 0, 0, canvas.width, canvas.height );
// move to origin first
context.translate( moveXAmount, moveYAmount );
// rotate
context.rotate( rotationAmount * Math.PI / 180 );
// change to translate back based on image size
// (remember to pensate for scale, not shown here)
context.translate( -imageObj.width/2, -imageObj.height/2 );
context.drawImage( imageObj, 0, 0, im_width, im_height );
// reset transforms (identity matrix)
context.setTransform(1,0,0,1,0,0);
}
Modified fiddle
Optionally you would need to use inverse matrix. This is something that will bee available later when we can take out a SVGMatrix based on the current transformation matrix, but this is not widely available at this time. Otherwise the inverse matrix would be applied to the mouse x/y position to sort of, as the name implies, inverse the effect of the main transformation.
Optionally use a custom transformation matrix solution to keep track of transform (I'll invite you to check out my own approach to this here, it's free).
PS: also fixed the image loading problem (see fiddle).
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
var x = 250;
var y = 500;
var width = 100;
var height = 100
var cx = x + 0.5 * width; // x of shape center
var cy = y + 0.5 * height; // y of shape center
class Meteor {
constuctor(degrees){
this.degrees = degrees;
//this.y = 0;
}
draw(d){
//this.y = y++
ctx.save();
ctx.translate(x,d)
ctx.rotate( (Math.PI / 180) * d); //rotate 25 degrees.
ctx.translate(-cx, -cy); //translate center
ctx.fillStyle = "#0000ff";
ctx.fillRect(x, y, width, height);
ctx.restore();
//ctx.setTransform(1, 0, 0, 1, 0, 0);
}
}
let m = new Meteor(90)
d = 0;
function animate(){
ctx.clearRect(0,0,canvas.width,canvas.height)
// Save the default state
d++;
m.draw(d)
// Restore the default state
ctx.fillRect(250, 40, 10, 10); //spaceship
ctx.fillRect(150, d, 100, 100);
window.requestAnimationFrame(animate)
}
animate()
function draw(){
var im_width = parseInt( imageObj.width + resizeAmount, 10 );
var im_height = parseInt( imageObj.height + resizeAmount, 10 );
var rotationAmount = rotationVal; // disabled: - prevRotation;
context.clearRect( 0, 0, canvas.width, canvas.height );
// move to origin first
context.translate( moveXAmount, moveYAmount );
// rotate
context.rotate( rotationAmount * Math.PI / 180 );
// change to translate back based on image size
// (remember to pensate for scale, not shown here)
context.translate( -imageObj.width/2, -imageObj.height/2 );
context.drawImage( imageObj, 0, 0, im_width, im_height );
// reset transforms (identity matrix)
context.setTransform(1,0,0,1,0,0);
}
https://codepen.io/niko8888/pen/NWKXgdX?editors=0010