2016-06-20 74 views
1

嗨我想在我移動鼠標時圍繞其中心旋轉此形狀,但目前它正在旋轉(0,0)。如何更改我的代碼?如何在鼠標移動事件後圍繞其中心旋轉Canvas對象?

的源代碼(見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(); 

回答

1

您需要:

  • 首先轉化爲旋轉點(支點)
  • 然後旋轉
  • 則:
    • 答:畫在採用t(0,0)(-width/2,-height/2)作爲相對座標(居中附圖)
    • B:轉換回並使用對象的絕對位置和減去相對座標爲中心的繪圖

修改後的代碼:

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 

Modified Fiddle

獎勵建議:您目前正在使用save()/restore()調用來維護變換矩陣。另一種方法可能是使用設置絕對值最初更換save()/restore()矩陣 - 所以不是第一translate():就像每個個別款式

ctx.setTranform(1,0,0,1,this.cx, this.cy); // translate to pivot 

您還可以設置的東西。無論如何,它不會改變核心解決方案。

+1

感謝現在我知道爲什麼我嘗試翻譯沒有工作。我忘了在樞軸點呈現。 – newguy

+0

你的小費看起來很有趣。但是我無法在互聯網上找到'setTranslate()'的方法定義和文檔。每個參數是什麼意思?我怎樣才能找到這種方法的例子? – newguy

+0

@newguy oops,我的壞。我半睡半醒,當然應該是setTransform。我正在改變translate()的文本。更新。 – K3N

1

你必須先轉化爲圓心,使旋轉,然後轉換回

執行此渲染圈及以下

ctx.translate(this.cx, this.cy); 
ctx.rotate(this.toAngle - this.angle); 
ctx.translate(-this.cx, -this.cy); 

的jsfiddle廣場前: https://jsfiddle.net/1st8Lbu8/2/

2

所有好的答案,令人沮喪的是......他們沒有提到該解決方案僅適用於當前轉換處於默認狀態時。他們沒有提及如何恢復到默認狀態並保存和恢復狀態。

要獲取默認的轉換狀態

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

保存和恢復所有國家

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 

,他們可以被嵌套

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完全取代當前的轉型。同時轉換,縮放,旋轉,平移,將現有的變換與適當的變換相乘。如果你有一個對象連接到另一個對象,並且希望將第一個對象應用於第二個對象,並且將其他對象轉換爲第二個對象而不是第一個對象,那麼這很方便。

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 

而且不需要默認的替代變換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); 

或者,如果不是一個圖像,而是一個對象

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

不錯,我會嘗試在我的代碼中使用setTransform。 – newguy