battlenub
battlenub

Reputation: 187

Canvas arc offset to start at 1.5PI

I've been building a circle with 2 colors ( to show progress ) using 2 canvas on top of eachother

To ease the calculation of the percentage needed on the filler arc, I wanted to move the start position of it to 1.5PI but make it act like 0PI

I thought this would do the trick:

context.rotate(Math.PI * 1.5 ) I want to offset 1.5PI or 240 degrees.

This is not working and gives me a weird outcome.

// Filler
var canvas = document.getElementById('canvas_<?php echo $champions_['champion_id'];?>');
var context = canvas.getContext('2d');                   
context.rotate(1.5*Math.PI )
var x = canvas.width / 2;
var y = canvas.height / 2;                                          
var endAngle = 1.5 * Math.PI;
context.beginPath();
context.arc(x, y, 75, 0,<?php echo $percentage*2;?> * Math.PI, false);
context.lineWidth = 15;             
// line color
context.strokeStyle = '<?php echo $second_colour;?>';
context.stroke();                       
//Base        
var canvas = document.getElementById('canvas_main_<?php echo $champions_['champion_id'];?>');
var context = canvas.getContext('2d');                                      
context.beginPath();
context.arc((canvas.width / 2), (canvas.height / 2), 75, 2 * Math.PI, false);
context.lineWidth = 15;                      
// line color
context.strokeStyle = '<?php echo $base_colour;?>';
context.stroke();                 

Upvotes: 1

Views: 1154

Answers (1)

Kaiido
Kaiido

Reputation: 136668

Think of your canvas as a... canvas or a paper sheet if you're more used to it,

You are asking it to rotate by x radians, from the origin point (by default, the top-left corner). This origin point is not your arc's center, hence your circle (which could be thought as the pen in your hand) is offset.

var angle = 0;

var context = canvas.getContext('2d');
// move back from our canvas so we can see what we are doing
context.translate(canvas.width / 2, canvas.height / 2);
context.scale(.25, .25);

function draw() {
  // we need to multiply since we scaled down the canvas
  context.clearRect(-canvas.width * 2, -canvas.height * 2, canvas.width * 4, canvas.height * 4);
  // save the current sate of the context
  context.save();
  // here we rotate from the origin 0,0, the top-left corner
  context.rotate(angle);
  context.strokeStyle = '#000000';
  // draw the border of our canvas
  context.strokeRect(0, 0, canvas.width, canvas.height);

  var x = canvas.width / 2;
  var y = canvas.height / 2;
  var endAngle = 1.5 * Math.PI;
  context.beginPath();

  context.lineWidth = 15;
  context.strokeStyle = 'red';
  // as mentionned by @markE, we were leaking off the canvas
  var radius = 75 - (context.lineWidth / 2);
  context.arc(x, y, radius, 0, angle, false);

  context.stroke();
  // restore our context
  context.restore();
}

draw();

inp.oninput = inp.onchange = function() {
  angle = (2 * Math.PI * this.value) / 100;
  draw();
}
canvas {
  background: ivory;
}
<input id="inp" type="range" min="0" max="100" value="0" /><br>
<canvas id="canvas"></canvas>

What you need is to make the origin point at the center of your arc before you do the rotate :

var angle = 0;

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

function draw() {

  context.clearRect(0, 0, canvas.width, canvas.height);

  context.save();

  // the center of your arc
  var x = canvas.width / 2;
  var y = canvas.height / 2;
  // we modify the context's origin point
  context.translate(x, y);
  // here we rotate from the center of your circle
  context.rotate(angle);
  // we set the origin point back to the top left-corner
  context.translate(-x, -y);
  // note we could also have drawn our arc directly with
  // ctx.arc(0, 0, radius, sAngle, eAngle);

  // draw the border of our canvas
  context.strokeRect(0, 0, canvas.width, canvas.height);

  var endAngle = 1.5 * Math.PI;
  context.lineWidth = 15;
  context.strokeStyle = 'red';
  // as mentionned by @markE, we were leaking off the canvas
  var radius = 75 - (context.lineWidth / 2);
  context.beginPath();
  context.arc(x, y, radius, 0, angle, 0);

  context.stroke();

  // restore our context
  context.restore();
}

draw();

inp.oninput = inp.onchange = function() {
  angle = (2 * Math.PI * this.value) / 100;
  draw();
}
canvas {
  background: ivory;
}
<input id="inp" type="range" min="0" max="100" value="0" /><br>
<canvas id="canvas"></canvas>

But you'll notice that your whole arc is also rotated, and there is no way to rotate your context while drawing an arc (except using the arcTo method and a lot more calculations).

So the easiest way is to not rotate your context, there are startAngle and endAngle parameters to the arc() method, use it :

var angle = 0;

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

function draw() {

  context.clearRect(0, 0, canvas.width, canvas.height);
  var x = canvas.width / 2;
  var y = canvas.height / 2;

  var offset = 1.5 * Math.PI;

  context.beginPath();
  var start = offset;
  var end = angle + offset;

  context.lineWidth = 15;
  context.strokeStyle = 'red';
  // as mentionned by @markE, we were leaking off the canvas
  var radius = 75 - (context.lineWidth / 2);
  context.arc(x, y, radius, start, end);

  context.stroke();

  context.restore();
}

draw();

inp.oninput = inp.onchange = function() {
  angle = (2 * Math.PI * this.value) / 100;
  draw();
}
canvas {
  background: ivory;
}
<input id="inp" type="range" min="0" max="100" value="0" /><br>
<canvas id="canvas"></canvas>

Upvotes: 2

Related Questions