Холст HTML5 - вращение объекта без перемещения координат

Что у меня есть: Tank

Я хочу повернуть прямоугольник красный, например. 20 градусов, но это то, что я получаю: Bad rotation

Как вы можете видеть, прямоугольник вращается отлично, но он перемещается и больше не соответствует черному объекту.

Мой код:

context.save();
context.rotate(angle * Math.PI / 180); // in the screenshot I used angle = 20
context.translate(angle * 4, 2);
context.fillStyle = "red";
context.fillRect(x + 14, y - 16, 5, 16);
context.restore();

Я хочу, чтобы прямоугольник поворачивался, не двигаясь со своего положения.

Спасибо.

Ответы

Ответ 1

Похоже, вы хотите повернуть прямоугольник вокруг его центральной точки.

Красный прямоугольник оригинален, желтый прямоугольник вращается вокруг центральной точки.

enter image description here

Для этого вам нужно сначала context.translate до центральной точки прямой перед вращением.

// move the rotation point to the center of the rect

    ctx.translate( x+width/2, y+height/2 );

// rotate the rect

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

Обратите внимание, что контекст теперь находится в его повернутом состоянии.

Это означает, что позиция чертежа [0,0] визуально находится на [x + width/2, y + height/2].

Итак, вы должны нарисовать вращающийся прямоугольник в [-width/2, -height/2] (не на исходном невращаемом x/y).

// draw the rect on the transformed context
// Note: after transforming [0,0] is visually [-width/2, -height/2]
//       so the rect needs to be offset accordingly when drawn

    ctx.rect( -width/2, -height/2, width,height);

Вот код и скрипт: http://jsfiddle.net/m1erickson/z4p3n/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

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

    var startX=50;
    var startY=80;

    // draw an unrotated reference rect
    ctx.beginPath();
    ctx.rect(startX,startY,100,20);
    ctx.fillStyle="blue";
    ctx.fill();

    // draw a rotated rect
    drawRotatedRect(startX,startY,100,20,45);

    function drawRotatedRect(x,y,width,height,degrees){

        // first save the untranslated/unrotated context
        ctx.save();

        ctx.beginPath();
        // move the rotation point to the center of the rect
        ctx.translate( x+width/2, y+height/2 );
        // rotate the rect
        ctx.rotate(degrees*Math.PI/180);

        // draw the rect on the transformed context
        // Note: after transforming [0,0] is visually [x,y]
        //       so the rect needs to be offset accordingly when drawn
        ctx.rect( -width/2, -height/2, width,height);

        ctx.fillStyle="gold";
        ctx.fill();

        // restore the context to its untranslated/unrotated state
        ctx.restore();

    }

}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Ответ 2

Вы можете использовать простую функцию для этого в качестве альтернативы переводу и вращению:

Эта функция позволит вам нарисовать линию, начинающуюся с x и y, и заканчивать ее под углом:

function lineToAngle(ctx, x1, y1, length, angle) {

    angle *= Math.PI / 180;

    var x2 = x1 + length * Math.cos(angle),
        y2 = y1 + length * Math.sin(angle);

    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);

    return {x: x2, y: y2};
}

Использование:

lineToAngle(ctx, x, y, length, angle);

Demo

var canvas = document.querySelector('canvas'),
    ctx = canvas.getContext('2d'),
    x = 100, y =50, length = 40, angle = 0, dlt = -2;

(function animate() {
    
    //clear
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    ctx.beginPath();
    lineToAngle(ctx, x, y, length, angle);
    ctx.lineWidth = 10;
    ctx.stroke();

    angle += dlt;
    if (angle < -90 || angle > 0) dlt = -dlt;
    
    requestAnimationFrame(animate);
})();

function lineToAngle(ctx, x1, y1, length, angle) {

    angle *= Math.PI / 180;
    
    var x2 = x1 + length * Math.cos(angle),
        y2 = y1 + length * Math.sin(angle);
    
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);

    return {x: x2, y: y2};
}
body {background-color:#555557}
canvas {background:#ddd;border:1px solid #000}
<canvas></canvas>