Petr Bečka
Petr Bečka

Reputation: 794

rotate one of the 2 canvas objects placed in canvas

I'm developing web app using canvas and I made three. canvas, canvas_panorama and canvas_image.
First one is something like main canvas, conteiner for the others. canvas_panorama is a background for canvas_image.

After canvas is right clicked, I'm computing angle to rotate canvas_image:

function getAngle( e, pw /*canvas*/ ){
      var offset = pw.offset();
      var center_x = (offset.left) + ($(pw).width() / 2);
      var center_y = (offset.top) + ($(pw).height() / 2);
      var mouse_x = e.pageX;
      var mouse_y = e.pageY;
      var radians = Math.atan2(mouse_x - center_x, mouse_y - center_y);
      angle = radians;
}

After I have an angle I'm trying to rotate canvas_image like this:

function redraw(){
    var p1 = ctx.transformedPoint(0,0);
    var p2 = ctx.transformedPoint(canvas.width,canvas.height);
    ctx.clearRect( p1.x, p1.y, p2.x-p1.x, p2.y-p1.y );

    canvas_image_ctx.drawImage(image_img, 0, 0, 150, 150);

    canvas_panorama_ctx.drawImage(panorama_img, 0, 0, 600, 300);
    canvas_panorama_ctx.drawImage(canvas_image, 20, 20);

    // rotate panorama_img around its center
    // x = x + 0.5 * width
    // y = y + 0.5 * height
    canvas_panorama_ctx.translate(95, 95);
    canvas_panorama_ctx.rotate(angle);
    // translate to back
    canvas_panorama_ctx.translate(-95, -95);

    ctx.drawImage(canvas_panorama, 0, 0);
 }

But this rotates both canvas_image and canvas_panorama. It should only rotate canvas_image

JSFiddle to show you my problem

Upvotes: 0

Views: 48

Answers (1)

Kaiido
Kaiido

Reputation: 137044

I think you are confusing yourself with this idea of multiple canvases.

Once in the drawImage() method, every of your canvases are just images, and could be just one or even just plain shapes.

Transformation methods do apply to the canvas' context's matrix, and will have effect only if you do some drawing operations when they are set.

Note : To reset your context matrix, you can either use save(); and restore() methods which will also save all other properties of your context, so if you only need to reset the transform, then it's preferred to simply reset the transformation matrix to its default : ctx.setTransform(1,0,0,1,0,0).

Here is a simplified example to make things clearer :

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

// a single shape, with the border of the context matrix
var drawRect = function(){
    ctx.beginPath();
    ctx.rect(10, 10, 50, 20);
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    ctx.rect(0, 0, canvas.width, canvas.height);
    ctx.stroke();
};

// set the color of our shapes
var gradient = ctx.createLinearGradient(0,0,70,0);
gradient.addColorStop(0,"green");
gradient.addColorStop(1,"yellow");
ctx.fillStyle = gradient;

// here comes the actual drawings

//we don't have modified the transform matrix yet
ctx.strokeStyle  = "green";
drawRect();

// here we translate of 100px then we do rotate the context of 45deg
ctx.translate(100, 0)
ctx.rotate(Math.PI/4)
ctx.strokeStyle = "red";
drawRect();

// reset the matrix
ctx.setTransform(1,0,0,1,0,0);

// here we move of 150px to the right and 25px to the bottom
ctx.translate(150, 25)
ctx.strokeStyle = "blue";
drawRect();

// reset the matrix
ctx.setTransform(1,0,0,1,0,0);
<canvas id="canvas" width="500" height="200"></canvas>

In your code, you are setting the transformations on the canvas that does represent your image, and you do draw every of your canvases at each call.

What you want instead, is to set the transformation on the main canvas only, and draw the non-transformed image :

var main_ctx = canvas.getContext('2d');

var img_canvas = canvas.cloneNode();

var bg_canvas = canvas.cloneNode();

var angle = 0;

// draw on the main canvas, and only on the main canvas
var drawToMain = function(){
  // first clear the canvas
  main_ctx.clearRect(0,0,canvas.width, canvas.height);
  // draw the background image
  main_ctx.drawImage(bg_canvas, 0,0);
  // do the transforms
  main_ctx.translate(img_canvas.width/2, img_canvas.height/2);
  main_ctx.rotate(angle);
  main_ctx.translate(-img_canvas.width/2, -img_canvas.height/2);
  // draw the img with the transforms applied
  main_ctx.drawImage(img_canvas, 0,0);
  // reset the transforms
  main_ctx.setTransform(1,0,0,1,0,0);
  };

// I changed the event to a simple onclick
canvas.onclick = function(e){
    e.preventDefault();
    angle+=Math.PI/8;
    drawToMain();
  }


// a dirty image loader
var init = function(){
  var img = (this.src.indexOf('lena')>0);
  var this_canvas = img ? img_canvas : bg_canvas;
  this_canvas.width = this.width;
  this_canvas.height = this.height;
  this_canvas.getContext('2d').drawImage(this, 0,0);
  if(!--toLoad){
      drawToMain();
    }
  };

var toLoad = 2;
var img = new Image();
img.onload = init;
img.src = "http://pgmagick.readthedocs.org/en/latest/_images/lena_scale.jpg";

var bg = new Image();
bg.onload = init;
bg.src = 'http://www.fnordware.com/superpng/pnggradHDrgba.png';
<canvas id="canvas" width="500" height="300"></canvas>

Upvotes: 2

Related Questions