Is it possible to pause a requestAnimationFrame?
When i click on a specific button, the animation has to be paused.
And by click the button another time the animation has to be continued.
public addProgressbar() {
const progressbar = $('.progressbar__value');
const max = this.$progressMax;
const time = (1000 / max) * 5;
let start = null;
this.progress = 0;
const step = timestamp => {
if (start === null) {
start = timestamp;
}
this.progress = timestamp - start;
progressbar[0].style.width = Math.min(this.progress / 50, 2000).toFixed() + '%';
if (this.progress < 5000) {
requestAnimationFrame(step);
}
};
setTimeout(() => {
window.requestAnimationFrame(step);
}, 1000);
}
Related
Cant get, why it doesn't work;
I added new boolean 'keyPressed' to check if the key space was pressed. When it pressed, it's going to start the timer and, doing it again, stop the timer. But in my code this boolean doesn't help and only one part of my 'if' works: i can only stop or start by pressing space
const timeDisplay = document.querySelector("#timeDisplay");
const startBtn = document.querySelector("#startBtn");
const pauseBtn = document.querySelector("#pauseBtn");
const resetBtn = document.querySelector("#resetBtn");
let startTime = 0;
let elapsedTime = 0;
let currentTime = 0;
let paused = true;
let intervalId;
let hrs = 0;
let mins = 0;
let secs = 0;
let keyPressed = false;
document.addEventListener('keydown', function(event) {
if (event.code == 'Space') {
if (keyPressed) {
if (paused) {
paused = false;
keyPressed = true;
startTime = Date.now() - elapsedTime;
intervalId = setInterval(updateTime, 1000);
}
}
}
});
document.addEventListener('keydown', function(event) {
if (event.code == 'Space') {
if (!keyPressed) {
if (!paused) {
paused = true;
keyPressed = false;
elapsedTime = Date.now() - startTime;
clearInterval(intervalId);
}
}
}
});
startBtn.addEventListener("click", () => {
if (paused) {
paused = false;
keyPressed = true;
startTime = Date.now() - elapsedTime;
intervalId = setInterval(updateTime, 1000);
}
});
pauseBtn.addEventListener("click", () => {
if (!paused) {
paused = true;
keyPressed = false;
elapsedTime = Date.now() - startTime;
clearInterval(intervalId);
}
});
resetBtn.addEventListener("click", () => {
paused = true;
clearInterval(intervalId);
startTime = 0;
elapsedTime = 0;
currentTime = 0;
hrs = 0;
mins = 0;
secs = 0;
timeDisplay.textContent = "00:00:00";
});
function updateTime() {
elapsedTime = Date.now() - startTime;
secs = Math.floor((elapsedTime / 1000) % 60);
mins = Math.floor((elapsedTime / (1000 * 60)) % 60);
hrs = Math.floor((elapsedTime / (1000 * 60 * 60)) % 60);
secs = pad(secs);
mins = pad(mins);
hrs = pad(hrs);
timeDisplay.textContent = `${hrs}:${mins}:${secs}`;
function pad(unit) {
return (("0") + unit).length > 2 ? unit : "0" + unit;
}
}
<span id="timeDisplay"></span><br />
<button type="button" id="startBtn">Start</button>
<button type="button" id="pauseBtn">Pause</button>
<button type="button" id="resetBtn">Reset</button>
You shouldn't have two handlers for the same event because they will produce unpredictable behavior due to unpredictable order of execution.
Additionally, I would recommend avoiding duplicated code in multiple handlers because it is hard to keep them consistent. It also makes it hard to track state changes performed in multiple places.
The final thing is that I would recommend to use keyup instead of keydown. There could be many keydowns but only one keyup :)
Here is how I would improve your code to fix the problem.
Please let me know if this helps.
const timeDisplay = document.querySelector("#timeDisplay");
const startBtn = document.querySelector("#startBtn");
const pauseBtn = document.querySelector("#pauseBtn");
const resetBtn = document.querySelector("#resetBtn");
let startTime = 0;
let elapsedTime = 0;
let currentTime = 0;
let paused = true;
let intervalId;
let hrs = 0;
let mins = 0;
let secs = 0;
let keyPressed = false;
const start = () => {
if (!paused) return;
paused = false;
startTime = Date.now() - elapsedTime;
intervalId = setInterval(updateTime, 1000);
};
const pause = () => {
if (paused) return;
paused = true;
elapsedTime = Date.now() - startTime;
clearInterval(intervalId);
};
const reset = () => {
paused = true;
clearInterval(intervalId);
startTime = 0;
elapsedTime = 0;
currentTime = 0;
hrs = 0;
mins = 0;
secs = 0;
timeDisplay.textContent = "00:00:00";
};
document.addEventListener('keyup', (event) => {
if (event.code == 'Space') {
if (paused) {
start();
} else {
pause();
}
}
});
startBtn.addEventListener("click", start);
pauseBtn.addEventListener("click", pause);
resetBtn.addEventListener("click", reset);
function updateTime() {
elapsedTime = Date.now() - startTime;
secs = Math.floor((elapsedTime / 1000) % 60);
mins = Math.floor((elapsedTime / (1000 * 60)) % 60);
hrs = Math.floor((elapsedTime / (1000 * 60 * 60)) % 60);
secs = pad(secs);
mins = pad(mins);
hrs = pad(hrs);
timeDisplay.textContent = `${hrs}:${mins}:${secs}`;
function pad(unit) {
return (("0") + unit).length > 2 ? unit : "0" + unit;
}
}
<span id="timeDisplay"></span><br />
<button type="button" id="startBtn">Start</button>
<button type="button" id="pauseBtn">Pause</button>
<button type="button" id="resetBtn">Reset</button>
Im making a blackjack game which contains a timer. Timer should restart if player decides to draw a new card. When i press draw button it does reset but increments interval speed by 1.
const createCountDown = (isPlayerDrawed = false) => {
delay = 10;
let Timer = document.getElementById('timer');
if (isPlayerDrawed == true) {
delay = 10;
clearInterval(timer);
createCountDown(false);
} else {
let timer = setInterval(() => {
if (delay <= 0) {
clearInterval(timer);
stay();
} else {
delay--;
Timer.innerHTML = delay;
}
}, 1000)
console.log(timer)
}
}
How can i fix this problem ?
const createCountDown = (isPlayerDrawed = false, delay) => {
counter = delay;
let Timer = document.getElementById('timer');
let interval = null
if (isPlayerDrawed === true) {
clearInterval(interval);
} else {
interval = setInterval(() => {
Timer.innerHTML = counter;
if (counter <= 0) {
clearInterval(interval);
stay();
} else {
counter--;
}
}, 1000)
}
}
changing function like this worked for me.
Your let timer is only scoped to the else block. Other references will refer to a global variable.
Here is how you can make it work:
let Timer = document.getElementById('timer');
const stay = () => Timer.textContent = "timer expired!";
const createCountDown = (function () {
let delay, timer;
function reset() {
delay = 10;
clearInterval(timer);
timer = 0;
Timer.textContent = "";
}
reset();
return function () {
reset();
Timer.textContent = delay;
timer = setInterval(() => {
if (delay <= 0) {
reset();
stay();
} else {
delay--;
Timer.textContent = delay;
}
}, 1000);
}
})();
// Optionally start timer immediately:
createCountDown();
document.getElementById('draw').addEventListener("click", createCountDown);
<button id="draw">Draw</button>
<p id="timer"></p>
I'm writing a fadeIn function for an HTMLElement, the animation works but it's a bit choppy at the moment. what it does is animate a fadeIn from 0 opacity to 1, it also animates over a duration using requestFrameAnimation that's why it's probably so choppy, can someone help me make my animation run more smoothly. and example is on codepen.io look at the header fadeIn and see what I mean
fadeIn: function(duration) {
var el = this.$el,
duration,
end = 0;
el.style.opacity = 0;
el.style.display = "block";
var step = function() {
var current = +new Date(),
remaining = end - current;
if(remaining < 60) {
if(el) {
end = current + duration;
var val = parseFloat(el.style.opacity);
if (!((val += .1) > 1)) {
el.style.opacity = val;
}
} else {
return;
}
}
requestAnimationFrame(step);
};
step();
},
The smoothest one you can do is using CSS transition. But if you want to do with pure Javascript, you can do something like this
function fadeIn(dom, duration) {
let start = null;
const step = (end) => {
if (start === null) start = end;
let dt = end - start;
dom.style.opacity = Math.min(1, dt / duration);
if (dt < duration) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
function fadeOut(dom, duration) {
let start = null;
const step = (end) => {
if (start === null) start = end;
let dt = end - start;
dom.style.opacity = Math.max(0, 1 - dt / duration);
if (dt < duration) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
fadeIn(document.getElementById('your_dom'), 2000);
I'm a completely beginner and I write code in my free time. Can anyone explain me please why sometimes my Pomodore Clock is stuck when it hits 0 0 1. (hours, minutes, seconds)
I can start it in one tab in chrome and it will work for unpredictable amount of cycles and then for no reason it will stop at 0 0 1, just before starting next cycle. I want it to work continuous (work, break, work, break, etc.) until I hit reset button...
Is there better way to handle time in JS?
Code:
// Code wrapped in a closure to avoid global variables
(function () {
let countdown;
let timeIsRunnig = false;
let actionTypeSwitch = "Work";
const timerDisplay = document.querySelector(".display__time-left");
const infoDisplay = document.querySelector(".display__info");
const endTime = document.querySelector(".display__end-time");
const buttons = document.querySelectorAll("[data-time]");
const breakSettings = document.querySelectorAll(".settings__breakButton");
const workSettings = document.querySelectorAll(".settings__workButton");
const breakValue = document.querySelector("#valueBreak");
const workValue = document.querySelector("#valueWork");
const buttonMain = document.querySelector("#buttonMain");
let workValueSettings = 25; // Default work session value in min
let breakValueSettings = 5; // Default break session value in min
workValue.textContent = workValueSettings + ' min';
breakValue.textContent = breakValueSettings + ' min';
timerDisplay.textContent = `${ workValueSettings}:00`;
infoDisplay.textContent = "Are you ready?";
endTime.textContent = "Press START";
function timer(seconds) {
// Clear any existing timers
clearInterval(countdown);
// Current time in ms
const now = Date.now();
const future = now + seconds * 1000;
displayTimeLeft(seconds);
displayEndTime(future);
function timeCalc() {
const secondsLeft = Math.round((future - Date.now()) / 1000);
// Check if we should stop it
if (secondsLeft < 0) {
clearInterval(countdown);
return;
}
// Display it
displayTimeLeft(secondsLeft);
}
countdown = setInterval(timeCalc, 1000);
}
function startTimer() {
const seconds = workValueSettings * 60;
actionTypeSwitch = "Work";
infoDisplay.textContent = "Working hard!";
timer(seconds);
}
function startBreak() {
const seconds = breakValueSettings * 60;
actionTypeSwitch = "Break";
infoDisplay.textContent = "Short break!";
timer(seconds);
}
function resetTimer() {
const seconds = workValueSettings * 60;
// Clear any existing timers
clearInterval(countdown);
// Refresh display
displayTimeLeft(seconds);
infoDisplay.textContent = "Are you ready?";
endTime.textContent = "Press START";
}
function startAndReset() {
let name = "START";
if (timeIsRunnig === false) {
timeIsRunnig = true;
name = "RESET";
this.innerHTML = name;
startTimer();
} else {
timeIsRunnig = false;
name = "START";
this.innerHTML = name;
resetTimer();
}
}
function playSoundStartBreak() {
// Returns the first Element within the document
// that matches the specified group of selectors.
const audio = document.querySelector(`audio[data-sound="workDone"]`);
if(!audio) return; // Stop the function from running
audio.currentTime = 0; // Rewind to the start
audio.play();
}
function playSoundBackToWork() {
// Returns the first Element within the document
// that matches the specified group of selectors.
const audio = document.querySelector(`audio[data-sound="backToWork"]`);
if(!audio) return; // Stop the function from running
audio.currentTime = 0; // Rewind to the start
audio.play();
}
function displayTimeLeft(sec) {
const hours = parseFloat(Math.floor(sec / 3600));
const minutes = parseFloat(Math.floor(sec / 60));
const remainderMinutes = parseFloat(minutes % 60);
const remainderSeconds = parseFloat(sec % 60);
console.log(hours, remainderMinutes, remainderSeconds);
// Play sound when timer gets to 0
if (parseFloat(sec) === 0) {
if (actionTypeSwitch === "Work") {
playSoundStartBreak()
startBreak();
} else {
playSoundBackToWork();
startTimer();
}
}
// Hide hours when hours is 0
let hoursFirstStatement = hours < 10 ? "0" : "";
let hoursSecondStatement = hours;
let colon = ":";
if (hours === 0) {
hoursFirstStatement = "";
hoursSecondStatement = "";
colon = "";
}
// This `${}` allows adding javascript variables in strings
const display = `${hoursFirstStatement}${hoursSecondStatement}${colon}${
remainderMinutes < 10 ? "0" : ""}${remainderMinutes}:${
remainderSeconds < 10 ? "0" : ""}${remainderSeconds}`;
timerDisplay.textContent = display;
document.title = display + " " + "(" + actionTypeSwitch + ")";
}
function displayEndTime(timestamp) {
const end = new Date(timestamp);
const hours = end.getHours();
const minutes = end.getMinutes();
endTime.textContent = `This session ends at ${hours < 10 ? "0" : ""}${hours}:${
minutes < 10 ? "0" : ""}${minutes}`;
}
function changeBreakSettings() {
const breakChangeValue = parseInt(this.dataset.settings);
if ((breakValueSettings <= 1 && breakChangeValue === -1) ||
(breakValueSettings >= 30 && breakChangeValue === 1)) {
return; // Do nothing when this conditions are fulfilled
} else {
breakValueSettings = breakValueSettings + breakChangeValue;
breakValue.textContent = breakValueSettings + ' min';
}
}
function changeWorkSettings() {
const workChangeValue = parseInt(this.dataset.settings);
if ((workValueSettings <= 5 && workChangeValue === -1) ||
(workValueSettings >= 120 && workChangeValue === 1)) {
return; // Do nothing when this conditions are fulfilled
} else {
workValueSettings = workValueSettings + workChangeValue;
workValue.textContent = workValueSettings + ' min';
}
}
breakSettings.forEach(button => button.addEventListener("click", changeBreakSettings));
workSettings.forEach(button => button.addEventListener("click", changeWorkSettings));
buttonMain.addEventListener("click", startAndReset);
}());
You need to do clearInterval() against timeCalc & update the display on the case of secondsLeft < 0. Because when you do not clear it, when it is showing "1 second left", the call of timeCalc will goes into the if statement and return, and never update the display and timeCalc is never clear and you get into infinite loop.
I am making a simple podomoro clock, and everything seems to work fine except when timer reaches 0 its doesn't entirely stop. Minutes seem to stop but seconds keep decrementing. I think there might be something wrong with my startTimer function but I've tried tinkering with it for hours to no result.
JS:
$(document).ready(function() {
var pomoTime = $('#pomodoroNum');
var breakTime = $('#breakNum');
var status = $('#timerStatus');
var timerDisplay = $('#timer');
var startButton = $('#startBtn');
var stopButton = $('#stopBtn');
var state = 1; // 1=stopped 2=running
var countDown; // intervalID;
var minutes = 0;
var seconds = 60;
startButton.click(function() {
if (state == 1) { // if timer is not running then start timer
startTimer(minutes, seconds);
$('#breakMinus').off("click");
$('#breakPlus').off("click");
$('#workMinus').off("click");
$('#workPlus').off("click"); // disable +- controls when timer starts
};
});
updateDisplay(); // initially controls are enabled at the start
stopButton.on("click", function() {
if (state == 2) {
pauseTimer();
state = 1;
updateDisplay(); // renable +- controls when timer stops
}
});
function startTimer(m, s) {
state = 2;
var startMinutes = m;
var startSeconds = s;
countDown = setInterval(function() {
startSeconds--;
startMinutes = ("0" + startMinutes).slice(-2); // double digits conversion if <10
startSeconds = ("0" + startSeconds).slice(-2);
minutes = ("0" + startMinutes).slice(-2); // update minutes and seconds so when timer is stopped, it can resume from where it left off when startButton is pressed.
seconds = ("0" + startSeconds).slice(-2);
timerDisplay.html(startMinutes + ":" + startSeconds);
if (startSeconds == 0 && startMinutes > 0) {
startMinutes-- // decerement minutes when seconds 0...
startSeconds = 60; // ..and reset seconds to 60
}
}, 1000);
if (startMinutes == 0 && startSeconds == 0) {
clearInterval(countDown);// <-- not clearing here
}
};
function pauseTimer() {
clearInterval(countDown);
};
function updateDisplay() {
// break +-
$('#breakMinus').on("click", function() {
status.html("Break");
if (breakTime.text() > 1) {
breakTime.text(+breakTime.text() - 1);
};
timerDisplay.text(breakTime.text());
});
$('#breakPlus').on("click", function() {
status.html("Break");
breakTime.text(+breakTime.text() + 1); // parseInt to covert string into number so it doesn't concatanate.
timerDisplay.text(breakTime.text());
});
// work +-
$('#workMinus').on("click", function() {
status.html("Work");
if (pomoTime.text() > 1) {
minutes = pomoTime.text() - 2;
}
seconds = 60;
if (pomoTime.text() > 1) {
pomoTime.text(+pomoTime.text() - 1);
};
timerDisplay.text(pomoTime.text());
});
$('#workPlus').on("click", function() {
minutes = pomoTime.text();
seconds = 60;
status.html("Work");
pomoTime.text(+pomoTime.text() + 1); // parseInt to covert string into number to prevent concatanation.
timerDisplay.html(pomoTime.html());
});
};
});
example: http://codepen.io/aliz16/pen/OXMwRJ
Your check for the stop condition is outside of your interval function. That's why it's never stopping. Move the condition inside the function and use <= to be extra safe:
if (startSeconds <= 0 && startMinutes > 0) {
startMinutes -= 1; // decerement minutes when seconds 0...
startSeconds += 60; // ..and reset seconds to 60
}
if (startMinutes <= 0 && startSeconds <= 0) {
clearInterval(countDown);
}
}, 1000);