0

I have to make an analog clock in canvas. Wrote some code and I need help with how to adjust speed of the hands (hours, mins and seconds). When I start the app hands are just spinning around really fast. I am ending up with hands line allover the clock. Is there any way to remove those lines?

I tried adjusting the rotation but that didn't help. I just started learning about canvas and am really not sure how to fix this problem.

window.onload = draw;


function draw() {
  let myCanvas = document.getElementById("my-canvas");
  if (myCanvas.getContext) {
    let ctx = myCanvas.getContext('2d');
    var img = new Image();
    img.addEventListener('load', function() {
      ctx.drawImage(img, 0, 0, 400, 400);
    }, false);
    img.src = 'image.png';
    update(ctx);
  } else {
    alert("Canvas is not supported.");
  }
}


let angle = 0;

function update(ctx) {

  ctx.save();


  ctx.translate(200, 200);
  ctx.rotate((Math.PI / 180) * angle);
  ctx.translate(-200, -200);

  ctx.beginPath();
  ctx.moveTo(200, 200);
  ctx.lineTo(200, 150);
  ctx.closePath();
  ctx.stroke();


  ctx.beginPath();
  ctx.moveTo(200, 200);
  ctx.lineTo(200, 100);
  ctx.closePath();
  ctx.stroke();



  ctx.beginPath();
  ctx.moveTo(200, 150);
  ctx.lineTo(200, 30);
  ctx.closePath();
  ctx.stroke();



  ctx.restore();
  angle++;

  requestAnimationFrame(function() {
    update(ctx);
  });
}
#my-canvas {
  border: #cacaca 1px solid;
}
<canvas id="my-canvas" width="400" height="400">
        Your web browser does not support canvas element.
    </canvas>
j08691
  • 204,283
  • 31
  • 260
  • 272
  • 1
    Works fine in the example – Konrad Dec 05 '22 at 23:24
  • I'm having a hard time understanding why using a canvas for dynamic drawing like a clock. The SVG really seems more appropriate to me! – Mister Jojo Dec 05 '22 at 23:27
  • The code you've put in your post works perfectly fine, so if your own code doesn't: copy-paste _this_ code and overwrite what you have? – Mike 'Pomax' Kamermans Dec 05 '22 at 23:29
  • This is a school project, teacher insists on using canvas. I copied wrong link, will edit question. Thank you guys! – Marija Jovanovic Dec 05 '22 at 23:32
  • What's there to edit, the code you were showing before worked just fine? Please at the very least re-edit your post so that it's a runnable snippet again. – Mike 'Pomax' Kamermans Dec 05 '22 at 23:38
  • I copied the wrong one. That was an app we should use as a template to build our own app of analog clock. This one now is my code for clock. – Marija Jovanovic Dec 05 '22 at 23:40
  • 1
    You forgot the line of code that clears the canvas. By default, the canvas just draws and draws and draws, it is just a pixel bitmap. If you need it to clear between draw calls, you need to remember to do that yourself, otherwise you're just drawing "most stuff" on top of what's already there. Look at the template code you showed earlier to find the line that does that. – Mike 'Pomax' Kamermans Dec 05 '22 at 23:45
  • `requestAnimationFrame` doesn't work that way. this is the callback function argument first is a timestamp, and you should use it to regulate the display of your clock hands – Mister Jojo Dec 06 '22 at 00:02
  • sample chrono code using `requestAnimationFrame()` https://stackoverflow.com/questions/70208375/js-how-to-write-a-time-limit-function-for-my-stopwatch – Mister Jojo Dec 06 '22 at 00:20

1 Answers1

0

I'm not going to write code for you, since this is homework, but I can walk you through some of the changes I think you need to make.

First off, instead of incrementing your "angle" variable for every iteration, I'd suggest using basic geometry or algebra to figure out where the hand needs to be based on what second, minute, or hour you are wanting to display on a 360 degree circle. You already have some of it, you just need to make it work for time, instead of an ever increasing variable. This will help you reuse the "update" method for each hand.

Next, don't use a recursive method. Use a timer. Since this is a clock, I'd suggest setInterval(), but there's some caveats to this, so look at the link below. Also, I would play around with the timer delay to match the smoothness you want. Do you want the hands to smoothly go around the clock face or do you want them to snap to the next number? You can do some of that in your angle calculations too, but I'd suggest starting at 250ms and see how that looks. If it's not smooth enough, reduce the delay.

How to create an accurate timer in javascript?

Instead of calling "update" directly in the "draw" method, you'll instead set up the timer/interval.

Having this as a recursive method prevents other events from happening in your code, so if you have to add other features, they won't work without some complicated logic. Setting up the timer/interval will allow your code to act in a more multi-threaded way, but not true parallel threads. This gets into somewhat advanced topics, so I'll just stop there.

Third, you will want to add parameters to the "update" method for which hand you are updating and the time. This is because you will be calling it from a new method you create that calls "update" for each hand. This new method is the one that is fed into setInterval. You can use these parameters to determine the length and/or width of your clock hands. Doing it this way avoids you having to create duplicate methods for each hand.

Fourth, now that you have the correct code in the question, you need to add back in the line that clears the canvas, as Mike 'Pomax' Kamermans mentions in the comments. This comes after the "cts.save()" line in your "update" method. Also, your clock is apparently a different size than the original code, so your have to clear a larger area.

ctx.clearRect(0, 0, 400, 400);
computercarguy
  • 2,173
  • 1
  • 13
  • 27