"Tick" issue while using cookies to maintain a persistent countdown timer - javascript

The following question requires a look into the following external resources:
jQuery Countdown
JavaScript Cookie
No, this isn't one of the other "Cookie Timer not working" questions here on SO. ;)
I have crafted a persistent countdown timer that uses cookies to save a particular user's countdown state regardless of browser reloads or reboots. Everything is working great, except for when I use jQuery Countdown's "ticks" to create callbacks…
Actually, the callbacks do work if I let the timer run without reloading the page. But as soon as the page reloads, one of the callbacks doesn't work — and one of them does.
The callback that works regardless is the one that checks for the end of the timer. The one that doesn't work (after reload) is the one that checks for the "halfway" point.
Here's the code…
$(document).ready(function()
{
if (!Cookies.get('cdTime'))
{
var now = $.now(); // First time on page
var timerSet = 30; // Amout of time (sec)
var halfway = timerSet / 2;
Cookies.set('firstTime', now,
{
expires: 7,
path: '/'
});
Cookies.set('cdTime', timerSet,
{
expires: 7,
path: '/'
});
var runTimer = Cookies.get('cdTime');
}
else
{
var currentTime = $.now();
var usedTime = (currentTime - Cookies.get('firstTime')) / 1000; // Calculate and convert to sec
var runTimer = Cookies.get('cdTime') - usedTime;
}
$('#cd').countdown({
until: runTimer,
compact: true,
onExpiry: endCountdown,
onTick: callBacks,
layout: '{sn} seconds left...'
});
function callBacks(periods)
{
if ($.countdown.periodsToSeconds(periods) <= halfway)
{
$('#cd').addClass('halfway');
}
else if ($.countdown.periodsToSeconds(periods) === 0)
{
endCountdown();
}
}
function endCountdown()
{
$('#cd').removeClass('halfway').addClass('ended');
$('#cd').html('♥');
}
});
body {
margin: 1em;
font: 2em/1.4em 'Helvetica Neue', 'Helvetica','Arial', sans-serif;
color: #333;
}
#cd {
margin-top: 2em;
font-family: 'Source Code Pro','Andale Mono',Monaco,'Courier New',monospace;
font-size: 30px;
font-weight: 100;
}
.halfway {
color: #0000ff;
}
.ended {
color: #ff0000;
font-size: 125% !important;
line-height: 0;
}
header, footer
{
width:66%;
font-size: 18px;
line-height: 1.4em;
}
footer
{
position: absolute;
bottom: 0;
margin-bottom: 1.5em;
font-style: italic;
color: #ffa500;
}
.highlight
{
background: #FFFBCC;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-countdown/2.0.2/jquery.plugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-countdown/2.0.2/jquery.countdown.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.1.3/js.cookie.min.js"></script>
<header>This countdown timer uses jQuery Countdown, by Keith Wood, and JavaScript Cookie to work — it will continue itsa countdown regardless of browser reloads or reboots (really, try it!). <span class="highlight">Oh, and it works on mobile too</span>.</header>
<div id="cd"></div>
<footer>(Clear the “firstTime” and “cdTime" Cookies and then reload the page to start the timer over.)</footer>
A working example can be found here:
http://codepen.io/ProfessorSamoff/pen/xqXrgx
Watch it through once without reloading the page and then follow the onscreen instructions in order to start the timer again and play around with reloading.
Any ideas about why this might be happening?
Thank you!
Tim

I'm not 100%, but I think halfway is undefined. It only gets sets when the page is loaded for the first time.
Instead of if ($.countdown.periodsToSeconds(periods) <= halfway) try just if ($.countdown.periodsToSeconds(periods) <= halftime)
At the top, instead of var timerSet = 30; before the first if statement put totalTime = 30; and also halftime = Math.floor(totalTime / 2)

Related

Why does website cause most elements to be recalculated upon small change after being hosted?

I decided to make a Pac-Man game and after I did it and everything was working somewhat fine on local document I pushed my website on Github pages and decrease in fps was enormous. It turned out page was making recalculation for hundreds elements which caused 20ms+ delay.
Here's a small part of the code that still has performance difference between local and github-pages hosted website.
const gameBoard = document.getElementById("game-board");
const root = document.documentElement.style;
let elements;
let characterNode;
let position = 658;
makeLevel();
function makeLevel() {
for (let i = 0; i < 868; i++) {
const element = document.createElement("DIV");
element.style.backgroundPosition = `0 0`;
let character = document.createElement("DIV");
character.className = "yellow";
element.append(character);
gameBoard.append(element);
}
elements = Array.from(gameBoard.children);
characterNode = elements[658].children[0];
changePosition();
}
function changePosition() {
root.setProperty(`--yellow-sprite-y`, `-32px`);
characterNode.style.transform = `translateX(-20px)`;
setTimeout(() => {
characterNode.style.transform = "";
characterNode.classList.remove(`yellow-visible`);
position = position - 1;
characterNode = elements[position].children[0];
characterNode.classList.add(`yellow-visible`);
changePosition()
}, 200)
}
:root {
--yellow-sprite-y: -32px;
}
#game-board {
width: 560px;
height: 620px;
display: grid;
grid-template-columns: repeat(28, 20px);
background-color: #000000;
}
#game-board > * {
position: relative;
width: 20px;
height: 20px;
}
.yellow {
position: absolute;
top: -4px;
left: -5.5px;
width: 30px;
height: 28px;
z-index: 10;
}
.yellow-visible {
background-image: url("https://i.imgur.com/SphNpH6.png");
background-position: -32px var(--yellow-sprite-y);
transition: transform 200ms linear;
}
<div id="game-board">
</div>
The exact problem in this code is line 29 which on local document performs like this:
while after hosting it on Github performs this way:
Why is it working this way and what can I do to lessen the performance decrease on hosted page?
Amazingly everything works well and bug doesn't exist on CodePen, yet on Github it still persists.
After getting some feedback that my site works well for other users I shared it on CodePen and it also worked fine, day later somebody said there could be an extension that could do something like that and indeed Adblocker Ultimate caused the slow performance.

Problems with CSS changes in JavaScript

I am trying do a CSS change via JavaScript. I have a quiz site where, when the user marks the correct option, the option will become green, and when the user marks the incorrect option, the option will become red, but I have to change the color and redirect the user for another page, but the CSS change is very slow and, at certain times, doesn't work. This is my code:
CSS:
.choice{
white-space: normal;
word-wrap: break-word;
margin: 20px;
width: calc(40% + 100px);
height: calc(10% + 10px);
border-style: solid;
border-color: rgba(0, 0, 0, 0.4);
border-radius: 7px;
background-color: rgba(255,255,255,0.6);
cursor: pointer;
font-size: 20px;
transition: 0.4s;
}
JS:
function sleep(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms);
}
function govariable(page,variable,valor,id,color) {
document.getElementById(id).style.backgroundColor = color
sleep(3000)
window.location.replace(`${page}?${variable}=${valor}`)
}
When you change something in the DOM (in this case, your background color) JavaScript won't update your screen until the event it is processing has finished.
This is because JavaScript runs in only one thread - it can't be looping around and around and re-displaying your background colour at the same time! It needs to finish looping first.
Instead of trying to implement a "sleep" function that will never work well in a single-threaded javascript world, you should try using setTimeout().
function govariable(page,variable,valor,id,color) {
document.getElementById(id).style.backgroundColor = color
setTimeout(function() {
window.location.replace(`${page}?${variable}=${valor}`)
}, 3000);
}
Instead of looping around again and again until time is up, at a very simplistic level this does something more like setting an internal "wake-up alarm" inside the JavaScript engine, that in 3000 milliseconds will go off, and tell JavaScript to run the code inside it. In this case, to call window.location.redirect.

Set delays - Javascript

Currently I have a simple fire animation. It just show two flames tongues in same place and show hide within 0.3s. Right now I want set delays. After few milliseconds, stop the loop and start again like that. I tried with javascript setInterval but it's continuously running.
var $wrapper = $('.wrapper');
setInterval(function() {
$wrapper.toggleClass("alt");
}, 300);
.wrapper {
text-align: center;
position: relative;
}
.flames,
.wrapper-img,
.show-1,
.show-2 {
position: absolute;
}
.flames {
display: none;
}
.flame-1 {
left: 38px;
top: 32px;
}
.flame-2 {
left: 67px;
top: 40px;
}
.flame-2 img {
top: 220px;
}
.wrapper-img {
top: 220px;
}
.wrapper .flame-1 {
display: block;
}
.wrapper .flame-2 {
display: none;
}
.wrapper.alt .flame-1 {
display: none;
}
.wrapper.alt .flame-2 {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="flame-1 flames">
<img src="https://i.imgur.com/0Pfsrdh.png" alt="">
</div>
<div class="flame-2 flames">
<img src="https://i.imgur.com/EypytyC.png" alt="">
</div>
<div class="wrapper-img">
<img src="https://i.imgur.com/moNtPwG.png" class="wrap-img" alt="">
</div>
</div>
Any solution? Jsfiddle
As far as I see you need soething like this
var $wrapper = $('.wrapper');
function flamebaby(){
$wrapper.toggleClass("alt");
setTimeout(function() {
$wrapper.toggleClass("alt");
setTimeout(function() {
flamebaby();
},600)
}, 200);
}
flamebaby();
https://jsfiddle.net/uy43w5qq/7/
You are probably looking for CSS keyframe animations which will let you run keyframe based transitions/animations without the need of JavaScript. This will also ensure that the browser can do optimizations for your animations, they will probably run smoother.
JS based answers are already provided so I'm not going in there except for a small sidenote on setInterval.
Using setInterval() is not recommended since the body function theoretically may take longer than the interval causing a stackoverflow. A better way is to use setTimeout to call a function, which at the end of executions schedules a new timeout for itself.
const foo = () => {
console.log('bar');
setTimeout(foo, 300);
}
setTimeout(foo, 300);
Also, when animating is may be useful to first use pen and paper to write down how the animations should behave, this may help when writing the code to implement them.
I'm not sure, if i understand correctly, but what you want is this ?
var $wrapper = $('.wrapper');
function startAnimation () {
var animationCount = 4
var iterationCount = 0
var intervalValues = {
animation: 300,
loops: 900
}
function toggleAlt () {
$wrapper.toggleClass("alt");
iterationCount++
if (iterationCount > 0 && iterationCount % animationCount === 0) {
setTimeout(toggleAlt, intervalValues.loops)
} else {
setTimeout(toggleAlt, intervalValues.animation)
}
}
toggleAlt();
}
startAnimation()
i've tried to keep simple, Fiddle: https://jsfiddle.net/50gemkrk/
Toggle class few times with interval of few ms.
Wait for few ms.
Repeat first step: Toggle class few times with interval of few ms
IMHO,
I might be wrong, but setIntervals is not recommended in most of cases, it's easy to lose control
Also, i agree with Sven's answer, CSS3 Animation is cool, i recomend it !

Jquery Traversing to the Array

take a time To look at this website http://www.thejewelrysource.net/ and stay for like 7 seconds in the bottom left corner there is a small pop up that will appear and disappear again I want to do something like that using Jquery.
I know I could use Slideup and SlideDown Method but the problem I am facing is that How could traverse to the Given data in an Array so that I will Pop up the Data One at a Time. I am using only Static Data. Thank you for your Help in Advance! may someone help me! Thank You So Much
I couldn't understand much from your description. By any chance is this what are you looking are?
I have used setTimeout and setInterval to simulate this and a closure variable to keep track of the next item to display.
$(document).ready(function() {
var $popup = $(".popup"),
aMessages = ["Hello", "This is alert", "Is this what are you look for?"],
counter = 0;
$(".popup").hide();
var interval = setInterval(showMessage, 3000);
function showMessage() {
var iMessageId = counter % aMessages.length;
$popup.text(aMessages[iMessageId]);
$popup.show();
counter++
setTimeout(hideMessage, 1000);
}
function hideMessage() {
$(".popup").fadeOut(100);
}
setTimeout(function() {
clearInterval(interval);
}, 10000);
});
.popup {
width: 200px;
height: 100px;
background-color: yellow;
border-radius: 50px;
padding: 20px;
position: fixed;
left: 10px;
bottom: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="popup"></div>

Unfold animation on DIV with Oridomi (JS)

I'm using the Oridomi (oridomi.com) Javascript plugin to achieve a paper folding animation. Specifically, I would like to have a div unfold on page load (picture a book opening).
However I am having difficulty getting the unfold() method to work, despite being a method which can be called on with the plugin.
You can see from this example, that I can only get the div to fold back, rather than unfold from a folded state (in effect, I would like the animation to be reversed).
My javascript function -
(function(){ function init(){
var $domi = $('.unfold').oriDomi({ vPanels: 2, hPanels: 1, speed: 500, shading: false });
setTimeout(function(){
$domi.oriDomi('reveal', -90);
}, 600);}
document.addEventListener('DOMContentLoaded', init, false);
})();
And CSS -
.unfold {
font-family: "Abril Fatface", "Hoefler Text", Constantia, Palatino, Georgia, serif;
font-size: 4.5rem;
width: 25rem;
height: 10rem;
text-align: center;
line-height: 1;
color: #ff676d;
background-color: #6ac1ff;
padding: 2.5rem 0;
}
The documentation on http://oridomi.com is not very clear on how this can be implemented. Any help would be very much appreciated. Thanks
If the Oridomi does not supports reverse you have 2 options. One would be to know the END stare and domi.oriDomi('reveal', 0);. The other would be to reverse it first on a speed of 0 and then reveal at 0deg to unfold. Here is a fiddle with this:
http://jsfiddle.net/Av6cD/2/
(function fold() {
var $domi = $('.unfold').oriDomi({
vPanels: 2,
hPanels: 1,
speed: 500,
shading: false
});
$domi.oriDomi('reveal', -90);
setTimeout(function () {
$domi.oriDomi('reveal', 0);
}, 1000);
})();
Please note that even if this is a nice effect, oriDomi is making a really mess to your DOM. CSS shaders would be the way to go once they get proper support.

Categories