2016-08-08 18 views
6

Ich versuche die Größe einer gedrehten Form auf der Leinwand zu ändern. Mein Problem ist, dass wenn ich die Rendering-Funktion aufrufen, die Form "driftet" abhängig vom Formwinkel. Wie kann ich das verhindern?Gedrehte Form bewegt sich auf der Y-Achse, wenn die Formbreite geändert wird

Ich habe eine vereinfachte Fiedel gemacht, die das Problem demonstriert, wenn die Leinwand angeklickt wird, die Form gewachsen ist und aus irgendeinem Grund nach oben driftet.

Hier ist die Geige: https://jsfiddle.net/x5gxo1p7/

<style> 
    canvas { 
     position: absolute; 
     box-sizing: border-box; 
     border: 1px solid red; 
    } 
</style> 
<body> 
<div> 
    <canvas id="canvas"></canvas> 
</div> 
</body> 

<script type="text/javascript"> 
    var canvas = document.getElementById('canvas'); 
    canvas.width = 300; 
    canvas.height= 150; 
    var ctx = canvas.getContext('2d'); 
    var counter = 0; 

    var shape = { 
     top: 120, 
     left: 120, 
     width: 120, 
     height: 60, 
     rotation: Math.PI/180 * 15 
    }; 



    function draw() { 
     var h2 = shape.height/2; 
     var w2 = shape.width/2; 

     var x = w2; 
     var y = h2; 


     ctx.save(); 
     ctx.clearRect(0, 0, canvas.width, canvas.height); 
     ctx.translate(75,37.5) 
     ctx.translate(x, y); 

     ctx.rotate(Math.PI/180 * 15); 
     ctx.translate(-x, -y); 

     ctx.fillStyle = '#000'; 
     ctx.fillRect(0, 0, shape.width, shape.height); 
     ctx.restore(); 
} 


canvas.addEventListener('click', function() { 

    shape.width = shape.width + 15; 
    window.requestAnimationFrame(draw.bind(this)); 
}); 

window.requestAnimationFrame(draw.bind(this)); 
</script> 

In dem „realen“ Code die Form der Größe verändert wird, wenn der Resize-Griff geklickt wird und bewegt, aber ich denke, dass dieses Beispiel ausreichend das Problem demonstriert.

EDIT: aktualisiert Geige, die Frage zu klären:

https://jsfiddle.net/x5gxo1p7/9/

+0

Es wegen 'ctx.translate trieb ist (x, y);' und 'ctx.translate (-x, -y);'. Versuche sie zu kommentieren! - https://jsfiddle.net/Pugazh/x5gxo1p7/3/ – Pugazh

+0

Ich brauche die übersetzt, um die Form um sein Zentrum zu drehen. – Jomppe

Antwort

0

eine Lösung gefunden, Problem war, dass ich nicht die neuen Mittelpunktkoordinaten rechnet.

Die neue Geige mit Lösung: https://jsfiddle.net/HTxGb/151/

var canvas = document.getElementById('canvas'); 
var ctx = canvas.getContext('2d'); 

canvas.width =500; 
canvas.height = 500; 

var x = canvas.width/2; 
var y = canvas.height/2; 
var rectw = 20; 
var recth = 20; 
var rectx = -rectw/2; 
var recty = -recth/2; 
var rotation = 0; 
var addedRotation = Math.PI/12; 
var addedWidth = 20; 
var addedHeight = 10; 

var draw = function() { 
    ctx.save(); 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
    ctx.translate(x, y); 
    ctx.rotate(rotation); 
    ctx.fillRect(rectx, recty, rectw, recth); 
    ctx.restore(); 
} 


document.getElementById('growXRight').addEventListener('click', function() { 
    rectx -= addedWidth/2; 
    x += addedWidth/2 * Math.cos(rotation); 
    y -= addedWidth/2 * Math.sin(-rotation); 
    rectw += addedWidth; 
    draw(); 
}) 

document.getElementById('growXLeft').addEventListener('click', function() { 
    rectx -= addedWidth/2; 
    x -= addedWidth/2 * Math.cos(rotation); 
    y += addedWidth/2 * Math.sin(-rotation); 
    rectw += addedWidth; 
    draw(); 
}) 

document.getElementById('growYTop').addEventListener('click', function() { 
    recty -= addedHeight/2; 
    x += addedHeight/2 * Math.sin(rotation); 
    y -= addedHeight/2 * Math.cos(-rotation); 
    recth += addedHeight; 
    draw(); 
}) 

document.getElementById('growYBottom').addEventListener('click', function() { 
    recty -= addedHeight/2; 
    x -= addedHeight/2 * Math.sin(rotation); 
    y += addedHeight/2 * Math.cos(-rotation); 
    recth += addedHeight; 
    draw(); 
}) 

document.getElementById('rotatePlus').addEventListener('click', function() { 
    rotation += addedRotation; 
    rotation = rotation % (Math.PI*2); 
    if(rotation % Math.PI*2 < 0) { 
    rotation += Math.PI*2; 
    } 
    draw(); 
}) 

document.getElementById('rotateMinus').addEventListener('click', function() { 
    rotation -= addedRotation; 
    rotation = rotation % (Math.PI*2); 
    if(rotation % Math.PI*2 < 0) { 
    rotation += Math.PI*2; 
    } 
    draw(); 
}) 

draw(); 
0

bereits. Sie hatten ctx.translate() verwendet, wo es nicht ganz notwendig war. Das hat die Probleme verursacht.

<script type="text/javascript"> 
var canvas = document.getElementById('canvas'); 
canvas.width = 300; 
canvas.height= 150; 
var ctx = canvas.getContext('2d'); 
var counter = 0; 

var shape = { 
    top: 120, 
    left: 120, 
    width: 120, 
    height: 60, 
    rotation: Math.PI/180 * 15 
}; 

function draw() { 

    ctx.save(); 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
    ctx.translate(75,37.5) 

    ctx.rotate(Math.PI/180 * 15); 

    ctx.fillStyle = '#000'; 
    ctx.fillRect(0, 0, shape.width, shape.height); 
    ctx.restore(); 
} 

canvas.addEventListener('click', function() { 

    shape.width = shape.width + 15; 
    window.requestAnimationFrame(draw.bind(this)); 
}); 

window.requestAnimationFrame(draw.bind(this)); 
</script> 
+0

Ich muss die Form um ihre Mitte drehen, also muss ich auf den Mittelpunkt der Form übersetzen. – Jomppe

0

Dies geschieht, weil die x und y als halber Wert der Formgröße festgelegt sind, die ihre Position vollständig verändert.

Sie sollten trotzdem einen Punkt für die Mitte der Form festlegen. Ich setze diesen Punkt als ctx.canvas.[width or height]/2, die Hälfte der Leinwand.

var h2 = shape.height/2; 
var w2 = shape.width/2; 

var x = (ctx.canvas.width/2) - w2; 
var y = (ctx.canvas.height/2) - h2; 

ctx.save(); 

ctx.clearRect(0, 0, canvas.width, canvas.height); 
ctx.translate(x + (shape.width/2), y + (shape.height/2)); 

ctx.rotate(((shape.rotation * Math.PI)/180) * 15); 

ctx.fillStyle = '#000'; 
ctx.fillRect(-shape.width/2, -shape.height/2, shape.width, shape.height); 
ctx.restore(); 

Fiddle.

1

Verwenden Sie immer lokale Koordinaten, um Formen zu definieren.

Beim Rendern von Inhalten, die umgewandelt werden sollen, sollte der Inhalt in einem eigenen (lokalen) Koordinatensystem vorliegen. Denk an ein Bild. Der obere linke Pixel ist immer auf 0,0 auf dem Bild, egal wo Sie es rendern. Die Pixel befinden sich an ihren lokalen Koordinaten. Wenn sie gerendert werden, werden sie über die aktuelle Transformation in die (Welt-) Leinwandkoordinaten verschoben.

Also, wenn Sie Ihre Form mit Koordinaten auf seinem lokalen machen, den Drehpunkt an seinem lokalen Ursprung machen (0,0) die Anzeigekoordinaten werden separat als Welt gespeichert Koordinaten

var shape = { 
    top: -30, // local coordinates with rotation origin 
    left: -60, // at 0,0 
    width: 120, 
    height: 60, 
    world : { 
     x : canvas.width/2, 
     y : canvas.height/2, 
     rot : Math.PI/12, // 15deg clockwise 
    } 
}; 

Sie jetzt don‘ Ich muss mich damit beschäftigen, vorwärts und rückwärts zu übersetzen ... blah blah total pain.

Gerade

ctx.save(); 
ctx.translate(shape.world.x,shape.world.y); 
ctx.rotate(shape.world.rot); 
ctx.fillRect(shape.left, shape.top, shape.width, shape.height) 
ctx.restore(); 

oder Ereignis schneller und die Notwendigkeit speichern verwenden zu beseitigen und

ctx.setTransform(1,0,0,1,shape.world.x,shape.world.y); 
ctx.rotate(shape.world.rot); 
ctx.fillRect(shape.left, shape.top, shape.width, shape.height); 

Die lokale Form Ursprung (0,0) wieder herzustellen ist, wo die Transformation Übersetzung platziert.

vereinfacht dies erheblich viel von der Arbeit, die

getan werden muss, um

var canvas = document.getElementById('canvas'); 
 
canvas.width = 300; 
 
canvas.height= 150; 
 
var ctx = canvas.getContext('2d'); 
 
ctx.fillStyle = "black"; 
 
ctx.strokeStyle = "red"; 
 
ctx.lineWidth = 2; 
 

 

 
var shape = { 
 
    top: -30, // local coordinates with rotation origin 
 
    left: -60, // at 0,0 
 
    width: 120, 
 
    height: 60, 
 
    world : { 
 
     x : canvas.width/2, 
 
     y : canvas.height/2, 
 
     rot : Math.PI/12, // 15deg clockwise 
 
    } 
 
}; 
 

 
function draw() { 
 
    ctx.setTransform(1,0,0,1,0,0); // to clear use default transform 
 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 

 
    // you were scaling the shape, that can be done via a transform 
 
    // once you have moved the shape to the world coordinates. 
 
    ctx.setTransform(1,0,0,1,shape.world.x,shape.world.y); 
 
    ctx.rotate(shape.world.rot); 
 
    
 
    // after the transformations have moved the local to the world 
 
    // you can ignore the canvas coordinates and work within the objects 
 
    // local. In this case showing the unscaled box 
 
    ctx.strokeRect(shape.left, shape.top, shape.width, shape.height); 
 
    // and a line above the box 
 
    ctx.strokeRect(shape.left, shape.top - 5, shape.width, 1); 
 
    
 
    ctx.scale(0.5,0.5); // the scaling you were doing 
 
    ctx.fillRect(shape.left, shape.top, shape.width, shape.height); 
 
} 
 

 
canvas.addEventListener('click', function() { 
 
    shape.width += 15; 
 
    shape.left -= 15/2; 
 
    shape.world.rot += Math.PI/45; // rotate to illustrate location 
 
            // of local origin 
 
    var distToMove = 15/2; 
 
    shape.world.x += Math.cos(shape.world.rot) * distToMove; 
 
    shape.world.y += Math.sin(shape.world.rot) * distToMove; 
 
    draw(); 
 
}); 
 
// no need to use requestAnimationFrame (RAF) if you are not animation 
 
// but its not wrong. Nor do you need to bind this (in this case 
 
// this = window) to the callback RAF does not bind a context 
 
// to the callback 
 
/*window.requestAnimationFrame(draw.bind(this));*/ 
 
requestAnimationFrame(draw); // functionaly identical 
 
// or just 
 
/*draw()*/ //will work
body { font-family : Arial,"Helvetica Neue",Helvetica,sans-serif; font-size : 12px; color : #242729;} /* SO font currently being used */ 
 

 
canvas { border: 1px solid red; }
<canvas id="canvas"></canvas> 
 
<p>Click to grow "and rotate" (I add that to illustrate the local origin)</p> 
 
<p>I have added a red box and a line above the box, showing how using the local coordinates to define a shape makes it a lot easier to then manipulate that shape when rendering "see code comments".</p>

+0

Sehr nette Antwort, aber es löst das Problem nicht. Ich muss die Form nur in einer Richtung wachsen lassen und dennoch um ihr "neues" Zentrum rotieren. In deinem Beispiel dreht sich die Form um ihren alten Mittelpunkt, wenn ich die Form entferne - = 15/2. – Jomppe

+0

@Jompe Wenn du sie wachsen und entlang ihrer Richtung bewegen willst. Add distance to the world coords mit 'world.x + = Math.cos (world.rot) * dist; world.y + = Math.sin (world.rot) * dist; ' – Blindman67

+0

@Jompe Ich habe das Antwort-Snippet aktualisiert, um Bewegung im Welt-Raum entlang der x-Achse der Formen anzuzeigen. – Blindman67