Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Canvas - Fill a specific area of an arc/circle

Starting from a W3School example I've created a canvas timer clock.

I would like to fill with another color (Yellow), the area where the hand is passed.

The clock is available here: https://jsfiddle.net/nzexyd6j/1/

And here is the code:

<canvas id="canvas" width="400" height="400" style="background-color:#fff">
</canvas>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height /2;
var minuti = 3;
var tempoInit = minuti * 60;
var tempo = tempoInit;
//var tempo = 180;
var lancetta;
ctx.translate(radius, radius);
radius = radius * 0.90
setInterval(drawClock, 1000);

function drawClock() {
  drawFace(ctx, radius);
 // drawNumbers(ctx, radius);
  drawTime(ctx, radius);
}
//f2634a
function drawFace(ctx, radius) {
  var grad;
  ctx.beginPath();
  ctx.arc(0, 0, radius, 0, 2*Math.PI);
  ctx.fillStyle = '#fff';
  ctx.fill();
  grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
  grad.addColorStop(0, '#f2634a');
  grad.addColorStop(1, '#f2634a');
  ctx.strokeStyle = grad;
  ctx.lineWidth = radius*0.1;
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
  ctx.fillStyle = '#f2634a';
 // ctx.fill();
}

function drawNumbers(ctx, radius) {
  var ang;
  var num;
  ctx.font = radius*0.15 + "px arial";
  ctx.textBaseline="middle";
  ctx.textAlign="center";
  for(num = 1; num < (minuti + 1); num++){
    ang = (num * Math.PI / minuti ) * 2;
    ctx.rotate(ang);
    ctx.translate(0, -radius*0.85);
    ctx.rotate(-ang);
    ctx.fillText(num.toString(), 0, 0);
    ctx.rotate(ang);
    ctx.translate(0, radius*0.85);
    ctx.rotate(-ang);
  }
}

function drawTime(ctx, radius){
    tempo--;
    lancetta = (tempo*Math.PI/tempoInit) * 2;
    drawHand(ctx, lancetta, radius*1, radius*0.07);
    drawHand(ctx, (180*Math.PI/tempoInit) * 2, radius*1, radius*0.07);
}

function drawHand(ctx, pos, length, width) {
    ctx.beginPath();
    ctx.lineWidth = width;
    ctx.lineCap = "round";
    ctx.moveTo(0,0);
    ctx.rotate(pos);
    ctx.lineTo(0, -length);
    ctx.stroke();
    ctx.rotate(-pos);
}

I've tried using lineWidth, but without success.

Do you have any suggestions?

like image 880
s.milziadi Avatar asked May 25 '16 14:05

s.milziadi


People also ask

How do I fill an arc in canvas?

How it works: First, select the canvas by using the querySelector() method. Next, get the 2D drawing context if the canvas API is supported. Then, set the stroke, fill, and line width by using the strokeStyle , fillStyle , and lineWidth property of the 2D drawing context.

How do you make a half circle on canvas?

To create a semicircle with HTML5 Canvas, we can create an arc using the arc() method and define the ending angle has startAngle + PI.

How do you make a circle on a canvas?

To draw arcs or circles, we use the arc() or arcTo() methods. Draws an arc which is centered at (x, y) position with radius r starting at startAngle and ending at endAngle going in the given direction indicated by counterclockwise (defaulting to clockwise).


1 Answers

Your clock seems to be running backwards?!

Anyway, you want to fill a wedge based on how many clock minutes have elapsed.

enter image description here

So given a time in clock minutes, this function returns the angle at that clock time.

// given minutes (a minute-hand on a clock)
// return the associated angle in radians
function minutesToAngle(minutes){
    var twelveOClock=-Math.PI/2;
    var fullCircle=Math.PI*2;
    return(twelveOClock+fullCircle*(minutes/60));
}

The returned angle is in radians, which is the unit-of-measure used to draw an arc on the canvas.

To draw a wedge, you simply fill an arc from the arc's centerpoint like this:

function fillWedge(cx,cy,radius,startAngle,endAngle,fillcolor){
    ctx.beginPath();
    ctx.moveTo(cx,cy);
    ctx.arc(cx,cy,radius,startAngle,endAngle);
    ctx.closePath();
    ctx.fillStyle=fillcolor;
    ctx.fill();
}

Putting the 2 functions together, you can fill your elapsed time like this:

// fill 5 elapsed minutes
var cx=canvas.width/2;  // or your clock's centerX
var cy=canvas.height/2; // or your clock's centerY
var radius=Math.min(canvas.width,canvas.height)*.90; // or your clock's radius
var startMinutes=0; // start at 12 o'clock
var endMinutes=5;   // end at 5 minutes past 12
var startAngle=minutesToAngle(0); // the angle at 12 o'clock
var endAngle=minutesToAngle(5);   // the angle at 5 minutes past 12

// fill the wedge for 5 elapsed minutes
fillWedge(cx,cy,radius,startAngle,endAngle,'gold');

By adding these 2 functions to your existing code, you can:

  1. Erase the canvas,
  2. Fill the background of the elapsed time with yellow,
  3. Stroke the clock face and clock hands.

Example code and a Demo:

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

var cx=cw/2;
var cy=ch/2;
var radius=135;
var minutes=0;
var minutesIncrement=0.334;

animate();

function animate(time){
    ctx.clearRect(0,0,cw,ch);
    ctx.beginPath();
    ctx.arc(cx,cy,radius,0,Math.PI*2);
    ctx.strokeStyle='indianred';
    ctx.lineWidth=10;
    ctx.lineJoin='round';
    ctx.stroke();
    fillWedge(cx,cy,radius,minutesToAngle(0),minutesToAngle(minutes),'gold');
    ctx.stroke();
    minutes+=minutesIncrement;
    if(minutes>60){minutes=0;}
    requestAnimationFrame(animate);
}

    var cx=canvas.width/2;
    var cy=canvas.height/2;
    var radius=Math.min(canvas.width,canvas.height)*.90/2;
    var startMinutes=0; // start at 12 o'clock
    var endMinutes=5;   // end at 5 minutes past 12
    var startAngle=minutesToAngle(0); // the angle at 12 o'clock
    var endAngle=minutesToAngle(5);   // the angle at 5 minutes past 12

    // fill the wedge for 5 elapsed minutes
    fillWedge(cx,cy,radius,startAngle,endAngle,'gold');

    function fillWedge(cx,cy,radius,startAngle,endAngle,fillcolor){
        ctx.beginPath();
        ctx.moveTo(cx,cy);
        ctx.arc(cx,cy,radius,startAngle,endAngle);
        ctx.closePath();
        ctx.fillStyle=fillcolor;
        ctx.fill();
    }

    function minutesToAngle(minutes){
        var twelveOClock=-Math.PI/2;
        var fullCircle=Math.PI*2;
        return(twelveOClock+fullCircle*(minutes/60));
    }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
like image 87
markE Avatar answered Oct 28 '22 13:10

markE