Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
523 views
in Technique[技术] by (71.8m points)

javascript - How to rotate a Canvas object around its center following mouse move event?

Hi I want to rotate this shape around its center when I move my mouse, but currently it's rotating around (0, 0). How to change my code?

Source code (also see jsfiddle):

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

class Circle {
    constructor(options) {
    this.cx = options.x;
    this.cy = options.y;
    this.radius = options.radius;
    this.color = options.color;
    this.angle = 0;
    this.toAngle = this.angle;

    this.binding();
  }

  binding() {
    const self = this;
    window.addEventListener('mousemove', (e) => {
        self.update(e.clientX, e.clientY);
    });
  }

  update(nx, ny) {
    this.toAngle = Math.atan2(ny - this.cy, nx - this.cx);
  }

  render() {
    ctx.clearRect(0,0,canvas.width,canvas.height);

    ctx.save();

    ctx.beginPath();

    ctx.lineWidth = 1;

    if (this.toAngle !== this.angle) {
      ctx.rotate(this.toAngle - this.angle);
    }

    ctx.strokeStyle = this.color;
    ctx.arc(this.cx, this.cy, this.radius, 0, Math.PI * 2);

    ctx.stroke();
    ctx.closePath();

    ctx.beginPath();

    ctx.fillStyle = 'black';
    ctx.fillRect(this.cx - this.radius / 4, this.cy - this.radius / 4, 20, 20);

    ctx.closePath();
    ctx.restore();
  }
}

var rotatingCircle = new Circle({
  x: 150,
  y: 100,
  radius: 40,
  color: 'black'
});

function animate() {
    rotatingCircle.render();
    requestAnimationFrame(animate);
}

animate();
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

All good answers, well frustratingly no... they fail to mention that the solution only works if the current transform is at it default. They fail to mention how to get back to the default state and save and restore states.

To get the default transformation state

ctx.setTransform(1,0,0,1,0,0);

To save and restore all states

ctx.save();
ctx.transform(10,0,0,2,200,100); // set some transform state
ctx.globalAlpha = 0.4;
ctx.restore(); // each save must be followed by a restore at some point

and they can be nested

ctx.save();  // save default state
ctx.globalAlpha = 0.4;
ctx.save();  // save state with alpha = 0.4
ctx.transform(10,0,0,2,200,100); // set some transform state
ctx.restore(); // restore to alpha at 0.4
ctx.restore(); // restore to default.

setTransform completely replaces the current transformation. while transform, scale, rotate, translate, multiply the existing transform with the appropriate transform. This is handy if you have an object attached to another, and want the transformation of the first to apply to the second, and additional transforms to the second but not to the first.

ctx.rotate(Math.PI /2); // Rotates everything 90 clockwise
ctx.rotate(Math.PI /2); // Rotates everything another 90 clockwise so that
                        // everything is 180 from default

ctx.translate(1,1); // move diagonally down by 1. Origin is now at 1,1
ctx.translate(1,1); // move diagonally down by 1. Origin is now at 2,2
ctx.translate(1,1); // move diagonally down by 1. Origin is now at 3,3
ctx.translate(1,1); // move diagonally down by 1. Origin is now at 4,4

ctx.scale(2,2); // scale by 2 everything twice as big
ctx.scale(2,2); // scale by 2 everything four times as big

And an alternative that does not require the default transform state of ctx

// scaleX, scaleY are scales along axis x,y
// posX, posY is position of center point
// rotate is in radians clockwise with 0 representing the x axis across the screen
// image is an image to draw.
ctx.setTransform(scaleX,0,0,scaleY, posX, posY);
ctx.rotate(rotate);
ctx.drawImage(image,-image.width / 2, -image.height / 2);

Or if not a image but a object

ctx.setTransform(scaleX,0,0,scaleY, posX, posY);
ctx.rotate(rotate);
ctx.translate(-object.width / 2, -object.height / 2);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...