[英]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).嗨,当我移动鼠标时,我想围绕它的中心旋转这个形状,但目前它正在围绕 (0, 0) 旋转。 How to change my code?
如何更改我的代码?
Source code (also see jsfiddle ):源代码(另见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();
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. setTransform 完全取代了当前的转换。 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以及不需要 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);
You need to:你需要:
Modified code:修改后的代码:
ctx.beginPath();
ctx.lineWidth = 1;
ctx.translate(this.cx, this.cy); // translate to pivot
if (this.toAngle !== this.angle) {
ctx.rotate(this.toAngle - this.angle);
}
ctx.strokeStyle = this.color;
ctx.arc(0, 0, this.radius, 0, Math.PI * 2); // render at pivot
ctx.closePath(); // must come before stroke() btw.
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = 'black';
ctx.fillRect(-this.radius / 4, -this.radius / 4, 20, 20); // render at pivot
Bonus tip: you're currently using save()
/ restore()
calls to maintain the transformation matrix.额外提示:您目前正在使用
save()
/ restore()
调用来维护转换矩阵。 Another way could be to set the matrix using absolute values initially replacing the save()
/ restore()
- so instead of the first translate()
:另一种方法是使用最初替换
save()
/ restore()
绝对值来设置矩阵 - 所以而不是第一个translate()
:
ctx.setTranform(1,0,0,1,this.cx, this.cy); // translate to pivot
You can also set things like styles on an individual basis for each.您还可以为每个人单独设置样式之类的东西。 Regardless, it doesn't change the core solution though.
无论如何,它不会改变核心解决方案。
You have to first translate to the circle centre, make the rotation and then translate back您必须先平移到圆心,进行旋转,然后再平移回来
Do this before rendering the circle and the square在渲染圆形和正方形之前执行此操作
ctx.translate(this.cx, this.cy);
ctx.rotate(this.toAngle - this.angle);
ctx.translate(-this.cx, -this.cy);
jsfiddle below: https://jsfiddle.net/1st8Lbu8/2/下面的jsfiddle: https ://jsfiddle.net/1st8Lbu8/2/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.