2016-06-20 15 views
1

Hallo Ich möchte diese Form um ihre Mitte drehen, wenn ich meine Maus bewege, aber derzeit rotiert sie (0, 0). Wie ändere ich meinen Code?Wie wird ein Canvas-Objekt nach dem Mausbewegungsereignis um sein Zentrum gedreht?

Quellcode (auch jsfiddle sehen):

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(); 

Antwort

1

Sie müssen:

  • ersten bis zum Drehpunkt (Pivot) übersetzen
  • dann drehen
  • dann entweder:
    • A: in a zeichnen t (0,0) unter Verwendung von (-Breite/2, -Höhe/2) als relative Koordinate (für zentrierte Zeichnungen)
    • B: übersetzen zurück und verwenden das absolute Position des Objekts und subtrahieren relative Koordinaten zentrierte Zeichnung

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 

Modified Fiddle

Bonus-Tipp: Sie verwenden derzeit save()/restore() Aufrufe, um die Transformationsmatrix beizubehalten. Eine weitere Möglichkeit könnte die Matrix mit absoluten Werte eingestellt werden zunächst die save()/restore() ersetzen - so anstelle des ersten translate():

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

Sie können auch festlegen Dinge wie Stile auf individueller Basis für jeden. Unabhängig davon ändert es jedoch nicht die Kernlösung.

+1

Danke jetzt weiß ich, warum mein Versuch zu übersetzen hat nicht funktioniert. Ich habe vergessen, am Drehpunkt zu rendern. – newguy

+0

Ihr Tipp sieht interessant aus. Aber ich konnte die Methodendefinition und Dokumentation von 'setTranslate()' nicht im Internet finden. Was bedeutet jeder Parameter? Wie finde ich Beispiele für diese Methode? – newguy

+0

@newguy oops, mein Schlechter. Ich bin im Halbschlaf +, sollte natürlich Transform sein. Ich habe den Text von translate() geändert. Aktualisiert. – K3N

1

Sie müssen zuerst auf die Kreismitte übersetzen, um die Drehung zu machen und dann übersetzen zurück

dies tun, bevor der Kreis-Rendering und den Platz

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

jsfiddle unter: https://jsfiddle.net/1st8Lbu8/2/

2

Alle guten Antworten, frustrierend nein ... sie erwähnen nicht, dass die Lösung nur funktioniert, wenn die aktuelle Transformation standardmäßig ist. Sie erwähnen nicht, wie Sie zum Standardzustand zurückkehren und Zustände speichern und wiederherstellen können.

Um den Standard-Transformationszustand

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

zum Sichern und Wiederherstellen alle Staaten

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 

zu bekommen und sie können

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 vollständig die aktuelle Transformation ersetzt verschachtelt werden. Während Sie transformieren, skalieren, drehen, übersetzen, multiplizieren Sie die vorhandene Transformation mit der entsprechenden Transformation. Dies ist praktisch, wenn Sie ein Objekt an ein anderes angehängt haben und möchten, dass die erste Transformation auf die zweite und die zweite auf die zweite Transformation und nicht auf die erste Transformation angewendet wird.

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 

Und eine Alternative, die nicht den Standard erfordert Zustand ctx verwandelt

// 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); 

Oder wenn kein Bild, sondern ein Objekt

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

Schön, ich werde versuchen, setTransform in meinem Code zu verwenden. – newguy