1
votes

I have a path that I want to render fully in a canvas. I know the initial width and height on the path but I want to rotate and scale it.

So I figured out how to determine the new canvas size but this code isn't doing what I'd like:

            let [w, h] = json.imgSize;
            ctx.translate(-w / 2, -h / 2);
            ctx.scale(json.scale, json.scale);
            ctx.rotate(json.rotation);
            [w, h] = [canvas.width, canvas.height];
            ctx.translate(w / 2, h / 2);

I would expect the result to be the path scaled and rotated but still in the center of the canvas. Instead it is rotating about the top-left corner of the path.

My reasoning is this:

  • move the path center to coordinate 0,0
  • scale the resulting image about its center
  • rotate the image about its center
  • move the resulting image to the canvas center

Here is how I calculate the canvas size:

        // rotate a rectangle and get the resulting extent
        let [x, y] = json.imgSize;
        let coords = [[-x, -y], [-x, y], [x, y], [x, -y]];
        let rect = new ol.geom.MultiPoint(coords);
        rect.rotate(json.rotation, [0, 0]);
        let extent = rect.getExtent();            
        [canvas.width, canvas.height] = [ol.extent.getWidth(extent), ol.extent.getHeight(extent)].map(v => v * 0.5);
1

1 Answers

2
votes

How to rotate and scale a drawing at center-canvas:

  • Translate the canvas [0,0] origin to center canvas
  • Scale the canvas
  • Rotate the canvas
  • Translate to pull the img leftward & upward so it's center is center-canvas.
  • Draw the img (or path drawing).
  • Always clean up! Set transformations back to their default

Example code and a Demo:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// create a rect to rotate
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=100;
c.height=75;
cctx.fillStyle='skyblue';
cctx.lineWidth=8;
cctx.fillRect(0,0,c.width,c.height);
cctx.strokeRect(0,0,c.width,c.height);

var scale=1;
var direction=1;
var angle=0;
requestAnimationFrame(animate);
function animate(time){
    // draw
    ctx.clearRect(0,0,cw,ch);
    rotateScaleImgAtCenterCanvas(c,scale,angle);
    // update
    scale+=0.02*direction;
    if(scale<0){scale=0;direction=1;}
    if(scale>3){scale=3;direction=-1;}
    angle+=Math.PI/120;
    // request another animation loop
    requestAnimationFrame(animate);
}


function rotateScaleImgAtCenterCanvas(img,scale,rotation){
    // set the canvas [0,0] origin to center canvas
    ctx.translate(canvas.width/2,canvas.height/2);
    // scale the canvas 
    ctx.scale(scale,scale);
    // rotate the canvas
    ctx.rotate(rotation);
    // pull the img leftward & upward so it's center is center-canvas
    ctx.translate(-img.width/2,-img.height/2);
    // draw the img
    ctx.drawImage(img,0,0);
    // set transformations back to default
    ctx.setTransform(1,0,0,1,0,0);
}
body{ background-color:white; }
#canvas{border:1px solid red; }
<canvas id="canvas" width=378 height=378></canvas>