1

I followed a tutorial for building a JS analogue clock and now I'd like to create an identical second clock on the page to experiment with.

When I've tried adding a second clock it overwrites the first clock - I believe this is because the variables ctx and radius are set globally.

Working example:

var canvas = document.getElementById("cambs_clock");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;

//drawClock();
setInterval(drawClock, 1000);

function drawClock() 
{
  drawFace(ctx, radius);
  drawNumbers(ctx, radius);
  drawTime(ctx, radius);
}

I tried turning the block of code that generates the ctx and radius variables into a function and adding params to the drawClock function but that resulted in no clocks being drawn whatsoever:

function setupClock(clock)
{
    var canvas = document.getElementById("cambs_clock");
    var ctx = canvas.getContext("2d");
    var radius = canvas.height / 2;
    ctx.translate(radius, radius);
    radius = radius * 0.90;
    setInterval(drawClock(ctx, radius), 1000);
}

//drawClock();
//setInterval(drawClock, 1000);
setupClock();

function drawClock(ctx,radius) 
{
  drawFace(ctx, radius);
  drawNumbers(ctx, radius);
  drawTime(ctx, radius);
}

function drawFace(ctx, radius) {
  var grad;

  ctx.beginPath();
  ctx.arc(0, 0, radius, 0, 2 * Math.PI);
  ctx.fillStyle = 'red';
  ctx.fill();

  grad = ctx.createRadialGradient(0, 0 ,radius * 0.95, 0, 0, radius * 1.05);
  grad.addColorStop(0, '#333');
  grad.addColorStop(0.5, 'black');
  grad.addColorStop(1, '#333');
  ctx.strokeStyle = grad;
  ctx.lineWidth = radius*0.05;
  ctx.stroke();

  ctx.beginPath();
  ctx.arc(0, 0, radius * 0.1, 0, 2 * Math.PI);
  ctx.fillStyle = '#333';
  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 < 13; num++){
    ang = num * Math.PI / 6;
    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){
  var now = new Date();
  var hour = now.getHours();
  var minute = now.getMinutes();
  var second = now.getSeconds();
  //hour
  hour = hour%12;
  hour = (hour*Math.PI/6)+(minute*Math.PI/(6*60))+(second*Math.PI/(360*60));
  drawHand(ctx, hour, radius*0.5, radius*0.07);
  //minute
  minute = (minute*Math.PI/30)+(second*Math.PI/(30*60));
  drawHand(ctx, minute, radius*0.8, radius*0.07);
  // second
  second = (second*Math.PI/30);
  drawHand(ctx, second, radius*0.9, radius*0.02);
}

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);
}
</script>

The above code results in no clocks being drawn. How would I be able to expand this code to accommodate multiple clocks?

(The end game is to have several clocks for different timezones in case that makes a difference)

3
  • 1
    The crucial line is this: var canvas = document.getElementById("cambs_clock"); Make "cambs_clock" into a variable, create multiple <canvas> elements each with its own id, then pass the id to the setup function. Commented Oct 5, 2019 at 12:04
  • 2
    And you will have to adjust the setInterval() call because setInterval(drawClock(ctx, radius), 1000) does not what you might think it does. Commented Oct 5, 2019 at 12:05
  • Thanks andreas that was exactly the issue as user super pointed out in another reply. Commented Oct 5, 2019 at 12:35

2 Answers 2

2

You have tried the following:

function setupClock(clock)
{
    var canvas = document.getElementById("cambs_clock");
    var ctx = canvas.getContext("2d");
    var radius = canvas.height / 2;
    ctx.translate(radius, radius);
    radius = radius * 0.90;
    setInterval(() => drawClock(ctx, radius), 1000);
}

setupClock();

Notice that that function has an argument, clock which is not used. Furthermore, with document.getElementById("cambs_clock"); you always target the same canvas. So what you need in your case are two canvas's like

<canvas id="clock1"></canvas>
<canvas id="clock2"></canvas>

And the following script

function setupClock(clock)
{
    var canvas = document.getElementById(clock);
    var ctx = canvas.getContext("2d");
    var radius = canvas.height / 2;
    ctx.translate(radius, radius);
    radius = radius * 0.90;
    setInterval(drawClock(ctx, radius), 1000);
}

setupClock('clock1');
setupClock('clock2');

You can pass the radius as well as an argument if you like:

function setupClock(clock, radius) { ... }

setupClock('clock2', 20);

Endless possibilities, good luck!

Sign up to request clarification or add additional context in comments.

1 Comment

Whoops I forgot I had hard-coded cambs_clock during testing. Unfortunately even changing that still didn't work as the setInterval command was setup incorrectly as @super pointed out in another reply. Thanks for your help!
0

Change

 setInterval(drawClock(ctx, radius), 1000);

to

  setInterval(() => {
       drawClock(ctx, radius);
  }, 1000);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.