I am creating a wheres waldo web app. When creating the timer i have been able to get the timer working with the data in useRef, but i can not figure out how to update the div everytime the timer changes. Some help would be much appreciated.
Javascript:
const hour = useRef('00');
const second = useRef('00');
const stopTime = useRef(false);
const timerCycle = () => {
if (stopTime.current === false) {
second.current = parseInt(second.current);
minute.current = parseInt(minute.current);
hour.current = parseInt(hour.current)
second.current = second.current + 1;
if (second.current === 60) {
minute.current = minute.current + 1;
second.current = 0;
}
if (minute === 60) {
hour.current = hour.current + 1;
minute.current = 0;
second.current = 0;
}
if (second.current < 10 || second.current === 0) {
second.current = '0' + second.current;
}
if (minute.current < 10 || minute.current === 0) {
minute.current = '0' + minute.current;
}
if (hour.current < 10 || hour.current === 0) {
hour.current = '0' + hour.current;
}
console.log(second.current, minute.current, hour.current);
setTimeout(timerCycle, 1000);
}
}
JSX:
<div id="stopwatch">{hour.current}:{minute.current}:{second.current}</div>
We can take a look how different libraries do this:
From react-use
import { useReducer } from 'react';
const updateReducer = (num) => (num + 1) % 1_000_000;
export default function useUpdate() {
const [, update] = useReducer(updateReducer, 0);
return update;
}
Usage:
const update = useUpdate();
if (hour.current < 10 || hour.current === 0) {
hour.current = '0' + hour.current;
update()
}
Related
I am looking to have my grid style game start once I click the start button on my page. Currently the game starts as soon as I click the grid, but I want this function to be invoked only when the you click the Start Button.
I already created my game Board. Which can be called using this function: createBoard(). Styling for this board is full of my divs and working.
I tried the solutions previously given in my other thread and still had an issue with the function not invoking only at the click of a start button.
Here is my replit: Any feedback on what I'm doing wrong? Thanks! :)
https://replit.com/#batb/WholeFrostyLocus
document.addEventListener('DOMContentLoaded', () => {
const grid = document.querySelector('.grid')
const startBtn = document.querySelector('.button-one')
const pauseBtn = document.querySelector('.button-two')
const scoreDisplay = document.querySelector('.score')
const countdown = document.querySelector('.countdown')
let paused = true
let score = 100
const width = 8
const squares = []
let isGameOver = false
let buzzyAmount = 12
let result = 0
const fiBuzz = [
'url(images/purple-fizzy.png)',
'url(images/buzzy-green.png)',
'url(images/new-moo-buzzy.png)',
'url(images/new-shiny-fizzy.png)'
]
//shuffled Arrays
function createBoard() {
const buzzArray = Array(buzzyAmount).fill('buzzy')
const emptyArray = Array(width * width - buzzyAmount).fill('valid')
const gameArray = emptyArray.concat(buzzArray)
const shuffledArray = gameArray.sort(() => Math.random() - 0.5)
for (let i = 0; i < width * width; i++) {
let randomNumber = Math.floor(Math.random() * fiBuzz.length)
let square = document.createElement('div')
square.setAttribute('id', i)
square.setAttribute('draggable', 'true')
square.classList.add(shuffledArray[i])
grid.appendChild(square)
squares.push(square)
square.style.backgroundImage = fiBuzz[randomNumber]
//normal click
square.addEventListener('click', function(e) {
click(square)
})
}
}
createBoard()
//check neighboring squares once square is clicked
function checkSquare(square, currentId) {
const isLeftEdge = (currentId % width === 0)
const isRightEdge = (currentId % width === width -1)
setTimeout(() => {
if (currentId > 0 && !isLeftEdge) {
const newId = squares[parseInt(currentId) -1].id
//const newId = parseInt(currentId) - 1 ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId > 7 && !isRightEdge) {
const newId = squares[parseInt(currentId) +1 -width].id
//const newId = parseInt(currentId) +1 -width ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId > 10) {
const newId = squares[parseInt(currentId -width)].id
//const newId = parseInt(currentId) -width ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId > 11 && !isLeftEdge) {
const newId = squares[parseInt(currentId) -1 -width].id
//const newId = parseInt(currentId) -1 -width ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId < 38 && !isRightEdge) {
const newId = squares[parseInt(currentId) +1].id
//const newId = parseInt(currentId) +1 ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId < 40 && !isLeftEdge) {
const newId = squares[parseInt(currentId) -1 +width].id
//const newId = parseInt(currentId) -1 +width ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId < 45 && !isRightEdge) {
const newId = squares[parseInt(currentId) +1 +width].id
//const newId = parseInt(currentId) +1 +width ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
if (currentId < 48) {
const newId = squares[parseInt(currentId) +width].id
//const newId = parseInt(currentId) +width ....refactor
const newSquare = document.getElementById(newId)
click(newSquare)
}
}, 10)
}
// game over
function gameOver(square) {
scoreDisplay.innerHTML = score + '<br>'+ ' You Lose :('
isGameOver = true
clearInterval(timerId)
// show ALL the badStars in gameOver
squares.forEach(square => {
if (square.classList.contains('buzzy')) {
square.appendChild(document.createElement('img')).src = 'images/fizz-buzz-mix.png'
square.classList.remove('buzzy')
square.classList.add('checked')
clearInterval(timerId)
}
})
}
function checkForWin() {
let matches = 0
for (let i = 0; i < squares.length; i++) {
if (score >= 100) {
scoreDisplay.innerHTML = score + ': ' + ' You Win!'
} else {
scoreDisplay.innerHTML = score + ': ' + ' You Lose!'
}
clearInterval(timerId)
}
}
// TIMER LOGIC
const startingMinutes = .25
let time = startingMinutes * 60
let timerId
let square
function countDown() {
let minutes = Math.floor(time / 60)
let seconds = time % 60
time--
console.log(minutes, 'minutes:', seconds, 'seconds')
if (time <= 0) {
checkForWin()
gameOver()
}
countdown.innerHTML = minutes + ' minutes ' + ': ' + seconds + ' seconds '
}
// add to right click
function click(square) {
let currentId = square.id
if (isGameOver) return
if (square.classList.contains('checked')) return score++
if (square.classList.contains('buzzy')) {
gameOver(square)
} else {
let total = square.getAttribute('data')
if (total !=0) {
square.classList.add('checked')
if (total == 1) square.classList.add('one')
if (total == 2) square.classList.add('two')
if (total == 3) square.classList.add('three')
if (total == 4) square.classList.add('four')
square.innerHTML = total
return
}
checkSquare(square, currentId)
}
square.classList.add('checked')
}
// START AND PAUSE LOGIC
function scoreFunction() {
if(square.classList.contains('valid')) {
score+=3
}
}
startBtn.addEventListener('click', () => {
if (paused === false) {
score++
return
}
scoreDisplay.innerHTML = 'Score' + ': ' + score++
paused = false
timerId = setInterval(countDown, 1000)
})
function pauseGame() {
paused = true
clearInterval(timerId)
}
pauseBtn.addEventListener('click', () => {
pauseGame()
})
})
Try changing up your html button so it calls the function you want once you click the button:
<button class="button-one" onclick="function_name"> Start </button>
instead of fucntion_name put the name of the function you want to call on the button click.
I'm trying to create a chess clock using JavaScript. I've settle almost all of the issues with the clock's functionality except for this one. I'm using setInterval to essentially create the "countdown" effect on each player's clock. However, when it is triggered with the method I'm currently using the clock flickers. From my understanding/research, this is likely because there are overlapping 'intervals' that cause the code to try to display multiple intervals at the same time. Essentially the clock buttons (stopclock and stopclock2) when clicked call the functions on the bottom of my code. Could anyone provide some input on my code (below) and why this might be occurring?
clear1mils = "";
clear2mils = "";
//Clock Functions
function countdownmils2() {
document.getElementById("milsvalue2").innerHTML = --mil2;
if (mil2 == 0) {
mil2 = mil2 + 59;
if (sec2 == 0) {
if (min2 == 0) {
clearInterval(clear2mils);
document.getElementById("milsvalue2").innerHTML = "00";
}else if (min2 !== 0) {
sec2 = 60;
document.getElementById("minutesvalue2").innerHTML = --min2;
document.getElementById("secondsvalue2").innerHTML = --sec2;
}
}else if (sec2 !== 0) {
document.getElementById("secondsvalue2").innerHTML = --sec2;
if (sec2 <= 10) {
document.getElementById("secondsvalue2").innerHTML = "0" + sec2;
}
}
}else if (mil2 <= 10) {
document.getElementById("milsvalue2").innerHTML = "0" + mil2;
}
}
function countdownmils() {
document.getElementById("milsvalue").innerHTML = --mil;
if (mil == 0) {
mil = mil + 59;
if (sec == 0) {
if (min == 0) {
clearInterval(clear1mils);
document.getElementById("milsvalue").innerHTML = "00";
}else if (min !== 0) {
sec = 60;
document.getElementById("minutesvalue").innerHTML = --min;
document.getElementById("secondsvalue").innerHTML = --sec;
}
}else if (sec !== 0) {
document.getElementById("secondsvalue").innerHTML = --sec;
if (sec <= 10) {
document.getElementById("secondsvalue").innerHTML = "0" + sec;
}
}
}else if (mil <= 10) {
document.getElementById("milsvalue").innerHTML = "0" + mil;
}
}
//Clock 1
document.querySelector("#stopclock").addEventListener("click", () => {
clear2mils = setInterval(countdownmils2, 10);
clearInterval(clear1mils);
document.getElementById("stopclock").innerHTML = "DOWN";
document.getElementById("stopclock2").innerHTML = "UP";
document.getElementById("stopclock").setAttribute("disabled", "true");
document.getElementById("stopclock2").removeAttribute("disabled", "true");
});
//Clock 2
document.querySelector("#stopclock2").addEventListener("click", () => {
clear1mils = setInterval(countdownmils, 10);
clearInterval(clear2mils);
document.getElementById("stopclock2").innerHTML = "DOWN";
document.getElementById("stopclock").innerHTML = "UP";
document.getElementById("stopclock2").setAttribute("disabled", "true");
document.getElementById("stopclock").removeAttribute("disabled", "true");
});
I made a little typing game that reveals some random text and you have to type the same in, so that you can test your typing speed. the users has the ability to play again and again, the issue is that when the user types play again, the stopwatch does not begin as it did the first time.
Can anyone help me with making the stopwatch restart everytime the user clicks on the play again button?
[ full code is here] (https://jsfiddle.net/kisho/ncbxd9o4/#&togetherjs=qD5bT8vLiw)
js portion-
const textDisplay = document.querySelector('#text-display');
const input = document.querySelector('#input');
const btn = document.querySelector('#btn');
const textBox = document.querySelector('#text-box');
const countdown = document.querySelector('#countdown');
const stopwatch = document.querySelector('#stopwatch');
const successMessege = document.querySelector('#success-messege');
const stopwatchTime = document.querySelector('#stopwatch-time');
btn.addEventListener('click', runGame);
function runGame() {
if ((btn.innerText = 'Play again')) {
playAgain();
fetchQuote();
countownTimer();
confirmQuote();
} else {
fetchQuote();
countownTimer();
confirmQuote();
}
}
function fetchQuote() {
fetch('https://api.quotable.io/random')
.then((res) => {
return res.json();
})
.then((data) => {
textDisplay.innerText = data.content;
});
}
function countownTimer() {
if (timer !== undefined) {
clearInterval(timer);
}
var timeleft = 2;
var downloadTimer = setInterval(function() {
if (timeleft <= 0) {
clearInterval(downloadTimer);
document.getElementById('countdown').innerHTML = 'Start Typing!';
input.classList.remove('displayNone');
runningStopwatch.classList.remove('displayNone');
begin();
} else {
document.getElementById('countdown').innerHTML = timeleft + ' seconds remaining';
}
timeleft -= 1;
}, 1000);
}
function confirmQuote() {
if ((countdown.innerHTML = 'Start typing!')) {
input.addEventListener('keyup', function(event) {
if (event.keyCode === 13) {
if (textDisplay.innerText === input.value) {
btn.innerText = 'Play again';
// textBox.classList.add('displayNone');
hold();
} else successMessege.innerText = 'Missed something there, try again!!';
}
});
}
}
function playAgain() {
textBox.classList.remove('displayNone');
input.classList.add('displayNone');
input;
input.value = '';
successMessege.innerText = '';
}
let ms = 0,
s = 0,
m = 0;
let timer;
let runningStopwatch = document.querySelector('.running-stopwatch');
function begin() {
timer = setInterval(run, 10);
}
function run() {
runningStopwatch.textContent =
(m < 10 ? '0' + m : m) + ': ' + (s < 10 ? '0' + s : s) + ': ' + (ms < 10 ? '0' + ms : ms);
ms++;
if (ms == 100) {
ms = 0;
s++;
}
if (s == 60) {
s = 0;
m++;
}
}
function hold() {
clearInterval(timer);
successMessege.innerText = `Nice job! You just typed in x seconds!`;
}
function stop() {
(ms = 0), (s = 0), (m = 0);
runningStopwatch.textContent =
(m < 10 ? '0' + m : m) + ': ' + (s < 10 ? '0' + s : s) + ': ' + (ms < 10 ? '0' + ms : ms);
}
You are not handling the clearInterval correctly.
You are clearing the interval only if one ends the game successfully.
My solution would be:
When calling the countownTimer() function, the first thing you should do, is to check if the interval timer is still running.
function countownTimer() {
if (timer !== undefined) {
clearInterval(timer);
}
// [...]
}
The next thing would be, to start the interval every time begin() gets called.
function begin() {
timer = setInterval(run, 10);
}
i have this 2 codes and want change the JS file.
Currently that's how it works:
--> the animation starts only when you click in the navigation.
I want play the animation if my site is loaded but i don't finde the function to change the code.
you can find the animation here: https://tympanus.net/Development/ShapeOverlays/index3.html
Thank you so much.
html:
<div class="animation">
<svg class="shape-overlays" viewBox="0 0 100 100" preserveAspectRatio="none">
<path class="shape-overlays__path"></path>
<path class="shape-overlays__path"></path>
<path class="shape-overlays__path"></path>
</svg>
</div>
JS-File:
setTimeout(() => document.body.classList.add('render'), 60);
class ShapeOverlays {
constructor(elm) {
this.elm = elm;
this.path = elm.querySelectorAll('path');
this.numPoints = 2;
this.duration = 600;
this.delayPointsArray = [];
this.delayPointsMax = 0;
this.delayPerPath = 200;
this.timeStart = Date.now();
this.isOpened = false;
this.isAnimating = false;
}
toggle() {
this.isAnimating = true;
for (var i = 0; i < this.numPoints; i++) {
this.delayPointsArray[i] = 0;
}
if (this.isOpened === false) {
this.open();
} else {
this.close();
}
}
open() {
this.isOpened = true;
this.elm.classList.add('is-opened');
this.timeStart = Date.now();
this.renderLoop();
}
close() {
this.isOpened = false;
this.elm.classList.remove('is-opened');
this.timeStart = Date.now();
this.renderLoop();
}
*/
updatePath(time) {
const points = [];
for (var i = 0; i < this.numPoints; i++) {
const thisEase = this.isOpened ?
(i == 1) ? ease.cubicOut : ease.cubicInOut:
(i == 1) ? ease.cubicInOut : ease.cubicOut;
points[i] = thisEase(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
}
let str = '';
str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `;
for (var i = 0; i < this.numPoints - 1; i++) {
const p = (i + 1) / (this.numPoints - 1) * 100;
const cp = p - (1 / (this.numPoints - 1) * 100) / 2;
str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `;
}
str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`;
return str;
}
render() {
if (this.isOpened) {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i)));
}
} else {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1))));
}
}
}
renderLoop() {
this.render();
if (Date.now() - this.timeStart < this.duration + this.delayPerPath * (this.path.length - 1) + this.delayPointsMax) {
requestAnimationFrame(() => {
this.renderLoop();
});
}
else {
this.isAnimating = false;
}
}
}
Well, you missed last part
(function() {
const elmHamburger = document.querySelector('.hamburger');
const gNavItems = document.querySelectorAll('.global-menu__item');
const elmOverlay = document.querySelector('.shape-overlays');
const overlay = new ShapeOverlays(elmOverlay);
elmHamburger.addEventListener('click', () => {
if (overlay.isAnimating) {
return false;
}
overlay.toggle();
if (overlay.isOpened === true) {
elmHamburger.classList.add('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.add('is-opened');
}
} else {
elmHamburger.classList.remove('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.remove('is-opened');
}
}
});
}());
There is event listener click attached to button elmHamburger, That is executing anonymous arrow function. If you want to run that animation on load, you need to replace click event with load.
That is:
elmHamburger.addEventListener('click', () => {...};
with
window.document.addEventListener('load', () => {...};
If you want to start animation on load and keep button event, then
(function() {
const elmHamburger = document.querySelector('.hamburger');
const gNavItems = document.querySelectorAll('.global-menu__item');
const elmOverlay = document.querySelector('.shape-overlays');
const overlay = new ShapeOverlays(elmOverlay);
const func = () => {
if (overlay.isAnimating) {
return false;
}
overlay.toggle();
if (overlay.isOpened === true) {
elmHamburger.classList.add('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.add('is-opened');
}
} else {
elmHamburger.classList.remove('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.remove('is-opened');
}
}
}
elmHamburger.addEventListener('click', func);
window.addEventListener('load', func);
}());
I've got a image slider on my website, it seems to work fine on IE, Firefox and Opera. But it doesn't work on Chrome and Safari. (Example: http://tommy-design.nl/ari/index.php)
<script type="text/javascript">
var data = [
["fotos/DSC_0055 (Large).JPG","Duitse herder","fotos/DSC_0055 (Large).JPG"],
["fotos/DSC_0154 (Large).JPG","Duitse herder","fotos/DSC_0154 (Large).JPG"],
["fotos/DSC_0194 (Large).JPG","Duitse herder","fotos/DSC_0194 (Large).JPG"],
["fotos/SSA41896 (Large).jpg","Duitse herder","fotos/SSA41896 (Large).jpg"],
["fotos/DSC_0143 (Large).JPG","Duitse herder","fotos/DSC_0143 (Large).JPG"]
]
imgPlaces = 4
imgWidth = 230
imgHeight = 122
imgSpacer = 0
dir = 0
newWindow = 1
moz = document.getElementById &&! document.all
step = 1
timer = ""
speed = 10
nextPic = 0
initPos = new Array()
nowDivPos = new Array()
function initHIS3()
{
for (var i = 0;i < imgPlaces+1;i++)
{
newImg=document.createElement("IMG")
newImg.setAttribute("id","pic_"+i)
newImg.setAttribute("src","")
newImg.style.position = "absolute"
newImg.style.width=imgWidth + "px"
newImg.style.height=imgHeight + "px"
newImg.style.border = 0
newImg.alt =""
newImg.i = i
newImg.onclick = function()
{
his3Win(data[this.i][2])
}
document.getElementById("display").appendChild(newImg)
}
containerEL = document.getElementById("container1")
displayArea = document.getElementById("display")
pic0 = document.getElementById("pic_0")
containerBorder = (document.compatMode == "CSS1Compat"?0:parseInt(containerEL.style.borderWidth) * 2)
containerWidth = (imgPlaces * imgWidth) + ((imgPlaces - 1) * imgSpacer)
containerEL.style.width=containerWidth + (!moz?containerBorder:"") + "px"
containerEL.style.height=imgHeight + (!moz?containerBorder:"") + "px"
displayArea.style.width = containerWidth+"px"
displayArea.style.clip = "rect(0," + (containerWidth+"px") + "," + (imgHeight+"px") + ",0)"
displayArea.onmouseover = function()
{
stopHIS3()
}
displayArea.onmouseout = function()
{
scrollHIS3()
}
imgPos = - pic0.width
for (var i = 0;i < imgPlaces+1;i++)
{
currentImage = document.getElementById("pic_"+i)
if (dir === 0)
{
imgPos += pic0.width + imgSpacer
}
initPos[i] = imgPos
if (dir === 0)
{
currentImage.style.left = initPos[i]+"px"
}
if (dir === 1)
{
document.getElementById("pic_"+[(imgPlaces-i)]).style.left = initPos[i]+"px"
imgPos += pic0.width + imgSpacer
}
if (nextPic == data.length)
{
nextPic = 0
}
currentImage.src = data[nextPic][0]
currentImage.alt = data[nextPic][1]
currentImage.i = nextPic
currentImage.onclick = function()
{
his3Win(data[this.i][2])
}
nextPic++
}
scrollHIS3()
}
timer = ""
function scrollHIS3()
{
clearTimeout(timer)
for (var i = 0;i < imgPlaces+1;i++)
{
currentImage = document.getElementById("pic_"+i)
nowDivPos[i] = parseInt(currentImage.style.left)
if (dir === 0)
{
nowDivPos[i] -= step
}
if (dir === 1)
{
nowDivPos[i] += step
}
if (dir === 0 && nowDivPos[i] <= -(pic0.width + imgSpacer) || dir == 1 && nowDivPos[i] > containerWidth)
{
if (dir === 0)
{
currentImage.style.left = containerWidth + imgSpacer + "px"
}
if (dir === 1)
{
currentImage.style.left = - pic0.width - (imgSpacer * 2) + "px"
}
if (nextPic > data.length-1)
{
nextPic = 0
}
currentImage.src=data[nextPic][0]
currentImage.alt=data[nextPic][1]
currentImage.i = nextPic
currentImage.onclick = function()
{
his3Win(data[this.i][2])
}
nextPic++
}
else
{
currentImage.style.left=nowDivPos[i] + "px"
}
}
timer = setTimeout("scrollHIS3()",speed)
}
function stopHIS3()
{
clearTimeout(timer)
}
function his3Win(loc)
{
if(loc === "")
{
return
}
if(newWindow === 0)
{
location = loc
}
else
{
newin = window.open(loc,'win1','left = 430,top = 340,width = 300 ,height = 300')
newin.focus()
}
}
</script>
I'm almost 100% sure that the problem lies in the array, but I can't seem to figure out what exactly the problem is..
Thanks in advance. :)
Try to use
position:relative;
and moving the first one from left to right / right to left(the others will follow accordingly as relative will tell em to follow the first image )
. i am pretty sure that that will start working on chrome then. as relative position tells it to use different positions. while opening your slider i found some bugs in chrome console : they all have the same left: thats getting changed together.