Malleys,
вариант, с перезапуском в любой момент(с новым или старым counter) и остановкой animate в конце цикла.
<!DOCTYPE html>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
</head>
<body>
<canvas id="canvas" width=300 height="300"></canvas>
<script>
function Timer(canvas, num = 90) {
this.canvas = canvas;
this.context = canvas.getContext("2d");
this.x = canvas.width / 2;
this.y = canvas.height / 2;
this.counter = num;
this.activity();
}
Timer.prototype.activity = function activity(num = this.counter){
cancelAnimationFrame(this.timer);
this.lastTime = performance.now();
this.counter = num;
this.txt = this.counter;
this.timer = requestAnimationFrame(this.animate.bind(this));
}
Timer.prototype.draw = function draw() {
var color = "blue";
var ctx = this.context;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
ctx.fill();
ctx.font = "40px Times New Roman";
ctx.textAlign = 'center';
ctx.textBaseline = "middle";
ctx.fillStyle = color;
ctx.fillText(this.txt, this.x, this.y);
ctx.strokeStyle = color;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(this.canvas.width / 2, this.canvas.height / 2, 30, 0, Math.PI * 2, false);
ctx.stroke();
};
Timer.prototype.animate = function animate(time) {
if(time - this.lastTime >= 1000 && this.txt > 0) {
this.txt--;
this.lastTime = time;
}
if(this.txt === 0)
"counterendCallback" in this && this.counterendCallback.bind(this);
else this.timer = requestAnimationFrame(this.animate.bind(this));
this.draw();
};
var timer = new Timer(document.getElementById("canvas"));
setTimeout(()=> timer.activity(10), 3000);
setTimeout(()=> timer.activity(), 15000);
</script>
</body>
</html>