HTML 5 Canvas, rotate everything

3k views Asked by At

I made a cylinder gauge, very similar to this one:

similar to this

It is drawn using about 7 or so functions... mine is a little different. It is very fleixble in that I can set the colors, transparency, height, width, whether there is % text shown and a host of other options. But now I have a need for the same thing, but all rotated 90 deg so that I can set the height long and the width low to generate something more like this:

horizonatal

I found ctx.rotate, but no mater where it goes all the shapes fall apart.. ctx.save/restore appears to do nothing, I tried putting that in each shape drawing function. I tried modifying, for example, the drawOval function so that it would first rotate the canvas if horizontal was set to one; but it appeared to rotate it every single iteration, even with save/restore... so the top cylinder would rotate and the bottom would rotate twice or something. Very tough to tell what is really happening. What am I doing wrong? I don't want to duplicate all this code and spend hours customizing it, just to produce something I already have but turned horizontal. Erg! Help.

2

There are 2 answers

2
wolfhammer On

Look at the rotate function in this example. You want to do a translation to the point you want to rotate around.

example1();
example2();

function rotate(ctx, degrees, x, y, fn) {
  ctx.save();
  ctx.translate(x, y);
  ctx.rotate(degrees * (Math.PI / 180));
  fn();
  ctx.restore();
}

function rad(deg) {
  return deg * (Math.PI / 180);
}

function example2() {
  var can = document.getElementById("can2");
  var ctx = can.getContext('2d');
  var w = can.width;
  var h = can.height;

  function drawBattery() {
      var percent = 60;
    
      ctx.beginPath();
    
      ctx.arc(35,50, 25,0,rad(360));
      ctx.moveTo(35+percent+25,50);
      ctx.arc(35+percent,50,25,0,rad(360));
      ctx.stroke();
    
      ctx.beginPath();
      ctx.fillStyle = "rgba(0,255,0,.5)";
      ctx.arc(35,50,25,0,rad(360));
      ctx.arc(35+percent,50,25,0,rad(360));
      ctx.rect(35,25,percent,50);
      ctx.fill();
          
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.strokeStyle = "#666666";
      ctx.moveTo(135,25);
      ctx.arc(135,50,25, rad(270), rad(269.9999));
      //ctx.moveTo(35,75);
      ctx.arc(35,50,25,rad(270),rad(90), true);

      ctx.lineTo(135,75);
      ctx.stroke();
  }
  
  drawBattery();

  can = document.getElementById("can3");
  ctx = can.getContext('2d');
  w = can.width;
  h = can.height;
  rotate(ctx, -90, 0, h, drawBattery);
}


function example1() {
  var can = document.getElementById('can');
  var ctx = can.getContext('2d');
  var color1 = "#FFFFFF";
  var color2 = "#FFFF00";
  var color3 = "rgba(0,155,255,.5)"
  var text = 0;

  function fillBox() {
    ctx.save();
    ctx.fillStyle = color3;
    ctx.fillRect(0, 0, can.width / 2, can.height);
    ctx.restore();
  }

  function drawBox() {
    ctx.save();
    ctx.beginPath();
    ctx.strokeStyle = ctx.fillStyle = color1;
    ctx.rect(10, 10, 50, 180);
    ctx.font = "30px Arial";
    ctx.fillText(text, 25, 45);
    ctx.stroke();
    ctx.beginPath();
    ctx.strokeStyle = color2;
    ctx.lineWidth = 10;
    ctx.moveTo(10, 10);
    ctx.lineTo(60, 10);
    ctx.stroke();
    ctx.restore();
  }

  fillBox();
  rotate(ctx, 90, can.width, 0, fillBox);

  text = "A";
  drawBox();
  color1 = "#00FFFF";
  color2 = "#FF00FF";
  text = "B";
  rotate(ctx, 90, can.width, 0, drawBox);

  centerRotatedBox()

  function centerRotatedBox() {

    ctx.translate(can.width / 2, can.height / 2);
    for (var i = 0; i <= 90; i += 10) {
      var radians = i * (Math.PI / 180);
      ctx.save();
      ctx.rotate(radians);
      ctx.beginPath();
      ctx.strokeStyle = "#333333";
      ctx.rect(0, 0, 50, 50)
      ctx.stroke();
      ctx.restore();
    }
  }

}
#can,
#can2,
#can3 {
  border: 1px solid #333333
}
<canvas id="can" width="200" height="200"></canvas>
<canvas id="can2" width="200" height="100"></canvas>
<canvas id="can3" width="100" height="200"></canvas>

0
AudioBubble On

Option 1

To rotate everything just apply a transform to the element itself:

canvas.style.transform = "rotate(90deg)";         // or -90 depending on need
canvas.style.webkitTransform = "rotate(90deg)";

Option 2

Rotate context before drawing anything and before using any save(). Unlike the CSS version you will first need to translate to center, then rotate, and finally translate back.

You will need to make sure width and height of canvas is swapped before this is performed.

ctx.translate(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5);    // center
ctx.rotate(Math.PI * 0.5);                                         // 90°
ctx.translate(-ctx.canvas.width * 0.5, -ctx.canvas.height * 0.5);

And of course, as an option 3, you can recalculate all your values to go along the other axis.