简体   繁体   中英

HTML5 canvas - rotate object without moving coordinates

What I have is this:坦克

What I want is to rotate the red rectangle eg 20 degrees, but this is what I end up with:旋转不好

As you can see, the rectangle is rotated perfectly, but it's moved and doesn't match the black object anymore.

My code is:

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

I want to make the rectangle turn without moving from its position.

Thanks.

Sounds like you want to rotate the rect around its centerpoint.

Red rectangle is original, Yellow rectangle is rotated around the centerpoint.

在此处输入图片说明

To do that you need to first context.translate to the rect's centerpoint before rotating.

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

Note that the context is now in its rotated state.

That means drawing position [0,0] is visually at [ x+width/2, y+height/2 ].

So you must draw the rotated rect at [ -width/2, -height/2 ] (not at the original unrotated 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);

Here is code and a Fiddle: 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>

You can use a simple function to do this as an alternative to translate and rotate:

This function will let you draw a line starting at x and y, and end at length at angle:

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};
}

Usage:

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>

在此处输入图片说明

In the specific case of a rectangle, you can just draw a line.

In HTML5 canvas, lines are drawn exactly like rectangles, as such, you can use this function:

 let canvas = document.getElementById('myCanvas') let ctx = canvas.getContext('2d') function drawRotatedRect(ctx, x, y, width, height, angle) { angle *= Math.PI / 180 ctx.lineWidth = height / 2 ctx.beginPath() ctx.moveTo(x, y) ctx.lineTo(x + width * Math.cos(angle), y + width * Math.sin(angle)) ctx.stroke() } drawRotatedRect(ctx, 30, 30, 200, 100, 20)
 canvas { border: 1px solid black; width: 100%; }
 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Rotated Rectangle</title> </head> <body> <canvas id='myCanvas'></canvas> </body> </html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM