javascript div updating rate - javascript

I have a very simple HTML/Javascript as below
But when I run it, the label is only updated once, when it is 99999, which is not my intended behavior. I want the label to update in "real time". Is there any way I can force it to redraw. I have tried to put it into a
notice.style.display = 'none';
notice.innerHTML = i
notice.style.display = 'block';
but it still doesnt work.
Thank you very much.
<html>
<head>
</head>
<body>
<label id = "esperanto-notice"></label>
<script type="text/javascript">
var notice = document.getElementById("esperanto-notice")
for(var i =0; i<100000; i++){
notice.innerHTML = i
console.log(i)
}
console.log("done")
</script>
</body>
</html>

Javascript tries to run all its inline code before updating the DOM, because the latter is slow. Your whole loop runs before the page updates a single time.
We can force the page to update:
for(var i =0; i<100000; i++){
notice.innerHTML = i;
notice.getBoundingClientRect(); // Force DOM update to get latest size
console.log(i);
}
However, while the DOM is updating it still goes straight back to the JS to keep running the loop - this is updating faster than you can see and still appears to hang.
What you need to do is pause the JS execution so that the page has a chance to update.
We can do this with an asynchronous JS function - something that finishes the current JS block but that queues up a callback function to fire later (in this case after the user has seen it):
var notice = document.getElementById("esperanto-notice");
var i = 0;
// Function to write the next value, increment, and queue up the next timeout
var nextFunc = function() {
console.log(i);
notice.innerHTML = i++;
if (i < 100000)
setTimeout(nextFunc, 16); // 16ms is 60FPS
else
console.log('done');
}
// Start it off
nextFunc();
<label id="esperanto-notice"></label>
Now the entire JS runs and nextFunc executes once. It also queues it up to fire again after 16ms, but until then it lets the browser update the page.
Each time nextFunc fires it uses setTimeout to queue up the next execution, then the page has a frame to update (so users see it), then it fires again.
Modern browsers provide a function specifically to wait for the next frame: requestAnimationFrame:
var notice = document.getElementById("esperanto-notice");
var i = 0;
// Function to write the next value, increment, and queue up the next timeout
var nextFunc = function() {
console.log(i);
notice.innerHTML = i++;
if (i < 100000)
// Request the next visible frame to continue
requestAnimationFrame(nextFunc);
else
console.log('done');
}
// Start it off
nextFunc();
<label id="esperanto-notice"></label>
This is the best way unless you need to support old versions of IE (<=9), as requestAnimationFrame can handle any duration of frame (setTimeout can have issues if you have lots of jank).
Finally, this is where the new language keywords async and await can make your code easier. You can keep the loop and abstract the wait for the DOM to update. This next snippet only runs on modern browsers like Chrome and FX (but could use Babel or TypeScript to support IE):
(async function() {
var notice = document.getElementById("esperanto-notice");
for (var i = 0; i < 100000; i++) {
console.log(i);
notice.innerHTML = i;
// Pass back to the DOM until the next frame
await new Promise(r => requestAnimationFrame(r));
}
console.log('done');
})();
<label id="esperanto-notice"></label>

Your loop works very fast and you're not able to see changes in real time. To reach your goal you should to make some timeout before increment counter. For example:
<html>
<head>
</head>
<body>
<label id = "esperanto-notice"></label>
<script type="text/javascript">
var notice = document.getElementById("esperanto-notice")
var i = 0;
var interval = setInterval(function() {
notice.innerHTML = ++i;
if (i === 100000)
clearInterval(interval)
}, 500);
</script>
</body>
</html>

Basically update happened quite fast and you are only seeing the final update on that div,
Try changing the for-loop to following to see the changes
for(var i =0; i<100000; i++)
{
(function(i){ //wrapping the value of i in an IIFE so that it can be locked
setTimeout( function(){
notice.innerHTML = i
console.log(i)
} , i * 100); //i*100 is in milliseconds
})(i);
}

Use javascript setInterval and clearinterval.
<html>
<body>
<label id="esperanto-notice"></label>
<script type="text/javascript">
var notice = document.getElementById("esperanto-notice");
var i = 0;
var interval = setInterval(function () {
notice.innerHTML = i;
i++;
if(i >= 100000) {
clearInterval(interval);
}
}, 100);
</script>
</body>
</html>

Your for loop execute in milliseconds and you only get the last value of your loop. If you want it in real time just use setInterval
var notice = document.getElementById("esperanto-notice")
var i = 0
var refreshIntervalId = setInterval(changeCounter,1000)
function changeCounter(){
i++
notice.innerHTML = i
if(i==10){
clearInterval(refreshIntervalId)
console.log("done")
}
}
<html>
<body>
<label id = "esperanto-notice"></label>
</body>
</html>

Since your code is running very fast actually in "real time" you are not able to see the numbers change on your screen. In order to do that you need the numbers to change slowly enough for you to notice. For that you can setTimeout and delay the update to the DOM.
var notice = document.getElementById("esperanto-notice")
for (var i = 0; i < 100000; i++) {
setTimeout(function(innerI) {
notice.innerHTML = innerI;
console.log(innerI);
}.bind(null, i), i * 100);
}
console.log("done")
<html>
<head>
</head>
<body>
<label id="esperanto-notice"></label>
</body>
</html>

Related

Creation of web page to show numbers with intervals

does anyone know how to make a WEB PAGE that shows numbers from, for example, 1 to 100 and that when it reaches 100 it resets to 1 again? and that you can change the time between number and number.
Using html, javascript or anything that was needed. Thx :)
Did you mean something like that?
let countArea = document.getElementById('count-area');
let speedInput = document.getElementById('speed');
let speed = Number(speedInput.value);
function setSpeed() {
speed = Number(speedInput.value)
}
function count() {
if (100 > Number(countArea.textContent)) {
countArea.textContent = Number(countArea.textContent) + 1;
} else {
countArea.textContent = 0;
};
setTimeout(count, speed)
}
count()
speedInput.addEventListener('change', setSpeed)
<!doctype html>
<html>
<head>
<title>Number counter</title>
</head>
<body>
<p id="count-area">0</p>
<input type="range" id="speed" min="50" max="1000">
</body>
</html>
I'm not sure I understand what you mean.
If you mean just a script that writes numbers from 1 to 100 multiple times this can work:
<div id='somediv'></div>
<script>
var times = 4;
for (var n=1;n<times;n++){
for (var i=1;i<101;i++){
somediv.innerHTML+='<br>'+i
}
}
</script>
To set delay between them can add timeout like here:
https://www.w3schools.com/jsref/met_win_settimeout.asp
Depending in what way you want that delay, the rest will be different.
To change how many times it will write 1-100 change the value of 'times', currently it will write it 1 time less then the number(so 3 times), can change that as well.
Edit: Aha!Ok so this can do something similar:
<div id='somediv'></div>
<script>
setInterval(displayCounter, 1000);
var i=0;
function displayCounter() {
document.getElementById("somediv").innerHTML = i;
i=i+1;
if (i==100){i=1};
}
</script>
It will cycle from 0 to 100, then start from 0 again. Currently its 1 second apart(1000 miliseconds). You can make it more or less by changing the 1000 to something else(3000 will be 3 seconds).
Edit 2:
{<br>
"number":"<span id='somediv'></span>"<br>
}
<script>
setInterval(displayCounter, 100);
var i=0;
function displayCounter() {
document.getElementById("somediv").innerHTML = i;
i=i+1;
if (i==100){i=1};
}
</script>
If you want it to start from 1 change:
var i=0;
to
var i=1;
If you want it to be to more or less then 100 change:
if (i==100)...
to 50 for example would be:
if (i==50)...
And can't think of anything more. For style can use css on #somediv.
Edit 3:
{<br>
"number":"<span id='somediv'></span>"<br>
}
<script>
setInterval(displayCounter, 1000);
var i = new Date().getSeconds();
function displayCounter() {
document.getElementById("somediv").innerHTML = i;
i=i+1;
if (i==100){i=1};
}
</script>
This will start the counter(1-100) from the current seconds of the clock. I'm not sure it will be the same for everyone, though, browser may load slower in some places or other factors.
Edit 4:
{<br>
"number":"<span id='somediv'></span>"<br>
}
<script>
setInterval(displayCounter, 1000);
var i = new Date().getSeconds();
if (i>0){somediv.innerHTML = i-1 ;} else if (i==0){somediv.innerHTML = 100}
function displayCounter() {
document.getElementById("somediv").innerHTML = i;
i=i+1;
if (i==100){i=1};
}
</script>

How to make a typing animation, that can restart half way through

So I was making a simple text animation and decided to make it so once its done, you can restart it. Problem being, im not sure of a way to force it to restart onclick once done. The way im doing it, it can and will restart in the middle if you click the screen, which is fine, but it continues to print some text from before. Anyway heres my code
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1 id=typing-style></h1>
<script>
var i=0,text="Mitchell";
setInterval(()=>{
document.getElementById("typing-style").innerHTML += text.charAt(i);
i++;
},300)
function rerun() {
document.getElementById("typing-style").innerHTML = " ";
var i=0,text="Mitchell";
setInterval(()=>{
document.getElementById("typing-style").innerHTML += text.charAt(i);
i++;
},300)
}
</script>
<canvas id="screen" onclick="rerun()" width=1000% height=1000%></canvas>
</body>
</html>
So what I've been trying to do is get it to be able to restart when you click the screen, but stop the current process. Hope someone can figure it out.
This code never calls clearInterval, so both timers will run at the same time, cross-talking each other's text manipulations. The code is repeated unnecessarily--it's easier to write it once in a function, then call the function each time you need to run the logic.
For this sort of thing, I'd create a closure that encapsulates the data needed to create a timer: an interval and index. You can return a timer start function that handles resetting timer state and can be invoked in an event listener (preferred to onclick because it keeps behavior out of the markup; read more).
Lastly, prefer textContent or innerText to innerHTML. They're faster, safer and more semantically appropriate if the content is purely text-based.
const makeTextTyper = (el, text, speed) => {
let i;
let interval;
return () => {
clearInterval(interval);
el.innerText = "";
i = 0;
interval = setInterval(() => {
if (i < text.length) {
el.innerText += text[i++];
}
else {
clearInterval(interval);
}
}, speed)
};
};
const buttonEl = document.querySelector("button");
const typerEl = document.querySelector("h3");
const runTyper = makeTextTyper(typerEl, "Mitchell", 300);
buttonEl.addEventListener("click", runTyper);
runTyper();
<button>restart</button>
<h3></h3>
When the rerun function is invoked the existing interval needs to be cancelled, this can be achieved using the clearInterval method.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1 id="typing-style"></h1>
<script>
var i = 0, text = "Mitchell";
var interval;
interval = setInterval(()=>{
document.getElementById("typing-style").innerHTML += text.charAt(i);
i++;
},300)
function rerun() {
clearInterval(interval);
document.getElementById("typing-style").innerHTML = " ";
var i=0,text="Mitchell";
interval = setInterval(()=>{
document.getElementById("typing-style").innerHTML += text.charAt(i);
i++;
},300)
}
</script>
<canvas height="1000%" id="screen" onclick="rerun()" width="1000%"></canvas>
</body>
</html>
I would write a if statement inside the rerun function to determine whether the animation is done or not. You can determine whether the text is done by using the .length method.
var typingText = document.getElementById("typing-style")
if(typingText.length === 8) //length of Mitchell {
document.getElementById("typing-style").innerHTML = " ";
var i=0,text="Mitchell";
setInterval(()=>{
document.getElementById("typing-style").innerHTML += text.charAt(i);
i++;
}
},300)
} ```

JavaScript Countdown with argument passing in

You are given an integer called start_num. Write a code that will countdown from start_num to 1, and when the countdown is finished, will print out "Liftoff!".
I am unsure how to do this and keep getting stuck.
This is the code I am provided with at the beginning of the problem:
function liftoff_countdown(start_num) {
// My code goes here!
}
And then they want me to pass in a value such as the 5:
liftoff_countdown(5);
And then this will be my output:
6
5
4
3
2
1
"Liftoff!"
Thanks!
Look at this maybe help you to create your own code
make two file in a same folder (script.js and index.html)
index.html
<!doctype html>
<head>
<title>Countdown</title>
</head>
<body>
<div id="container">
<div id="inputArea">
</div>
<h1 id="time">0</h1>
</div>
<script src="script.js"></script>
</body>
</html>
script.js
var valueRemaining;
var intervalHandle;
function resetPage() {
document.getElementById("inputArea").style.display = "block";
}
function tick() {
var valueDisplay = document.getElementById("time");
valueDisplay.innerHTML = valueRemaining;
if (valueRemaining === 0) {
valueDisplay.innerHTML = "Liftoff!";
clearInterval(intervalHandle);
resetPage();
}
valueRemaining--;
}
function startCountdown() {
var count = document.getElementById("count").value;
if (isNaN(count)) {
alert("Please enter a number!");
return;
}
valueRemaining = count;
intervalHandle = setInterval(tick, 1000);
document.getElementById("inputArea").style.display = "none";
}
// as soon as the page is loaded...
window.onload = function () {
var inputValue = document.createElement("input");
inputValue.setAttribute("id", "count");
inputValue.setAttribute("type", "text");
// create a button
var startButton = document.createElement("input");
startButton.setAttribute("type", "button");
startButton.setAttribute("value", "Start Countdown");
startButton.onclick = function () {
startCountdown();
};
// add to the DOM, to the div called "inputArea"
document.getElementById("inputArea").appendChild(inputValue);
document.getElementById("inputArea").appendChild(startButton);
};
in this example you have many things to understand how javascript works behind scenes.
How about this...
function liftoff_countdown()
{
var span=document.getElementById('num');
var i=document.getElementById('num').innerText;
i=i-1;
span.innerText=i;
if (i==0){
span.innerText='Liftoff!';
clearInterval(count_down)
}
}
var count_down=setInterval(liftoff_countdown,1000);
<span id="num">5</span>
You can achieve this with a simple recursive function and the use of setTimeout to recursively call the function after a time lapse of 1 second.
function lift_off(seconds) {
if(seconds == 0) {
console.log('liftoff');
} else {
console.log(seconds--);
setTimeout(function(){lift_off(seconds);},1000);
}
}
lift_off(10);
Here is a working JSFiddle
Preface
A lot of these answers seem to be focused on doing things with timers and recursion. I do not believe that is your intent. If your only goal is to print those values to the console, you could simply do the following (see the comments for an explanation).
The Answer
function liftoff_countdown(start_num) {
// Loops through all values between 0 and start_num
for(int i = 0; i < start_num; i++) {
// Prints the appropriate value by subtracting from start_num
console.log( start_num - i );
}
// Upon exiting the loop, prints "Liftoff!"
console.log("Liftoff!");
}
Additional Thoughts
You could just as easily loop backwards through the numbers instead of forward like so:
for(int i = start_num; i > 0; i--){
console.log( i );
}
I tend to lean towards iterating forwards just because it's more common, and it's often easy to confuse readers of your code if they gloss over the loop initialization.
Additionally, I am working with the assumption that when you say "print" you mean "console.log()". If this is untrue, you could of course use any other function in its place (e.g. alert( "Liftoff!" );).

setTimeout not working, other methods of queuing in a for loop?

Code below (the divs are shaded in my real example, I want to sequentially decrease their opacity to 0 so each disappears, in order.
I tried to doing this without using setTimeout, but all of the divs disappeared simultaneously - its good to know that the part of the code that changes the opacity works, but I cant seem to get them to work sequentially.
When I try to use setTimeout (which I presume I am implementing incorrectly),nothing happens!
Any help would be really appreciated with this, I'm fairly new to JavaScript and haven't touched it in a while and tutorials haven't been able to help me.
<body>
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
<div id="div4"></div>
<script type="text/javascript">
// the divs that we want to cycle through are named here.
var divs = ["#div1", "#div2", "#div3", "#div4"];
var divsLength = divs.length;
for (var i = 0; i < divsLength; i++) {
setTimeout(function(){
$(divs[i]).fadeTo(1000, 0, function() {
});
},1500);
};
</script>
</body>
Here's a way you should be able to do this without setTimeout:
function doFade(items, index) {
$(items[index]).fadeTo(1000, 0, function() {
doFade(items, index + 1);
});
}
doFade(divs, 0);
If you're targetting browsers that support ES5 (most modern versions do), then you can further simplify doFade:
function doFade(items, index) {
$(items[index]).fadeTo(1000, 0, doFade.bind(this, items, index + 1));
}
working jsfiddle
You can use a recursive function to do that kind of thing, something like that :
function seqFade($el){
$el.first().fadeOut(500, function(){ //Take the first element and fade it out
seqFade($el.slice(1)); //Recall the function when complete with the same set of element minus the first one.
})
}
seqFade($('div')); //Call the function
http://jsfiddle.net/L2fvdfy2/
In your code, it could look like that :
function seqFade($el){
$el.first().fadeOut(500, function(){
seqFade($el.slice(1));
})
}
seqFade($('#div1, #div2, #div3, #div4'));
It's because when the timeout finally fires the variable "i" only has the last index value. Also the loop will start all the timeouts at almost the same time.
There are other ways to accomplish it but this might work with minimal changes to your code.
Try this:
<script type="text/javascript">
var divs = ["#div1", "#div2", "#div3", "#div4"];
var divsLength = divs.length;
for (var i = 0; i < divsLength; i++) {
setTimeout((function(index) {
return function(){
$(divs[index]).fadeTo(1000, 0, function() { });
}
)(i)),1500 + (i * 1500));
};
</script>
</body>
This will create an instance of the function with it's own copy of the index when it was called. Also increasing the timeout of each timeout will have them execute sequentially.
try this:
// the divs that we want to cycle through are named here.
var divs = ["#div1", "#div2", "#div3", "#div4"];
(function fade(i) {
$(divs[i]).fadeTo(1000, 0, function() {
setTimeout(function() {fade(++i);}, 500);
});
})(0);
for (var i = 1; i <= divsLength; i++) {
setTimeout(function(){
$(divs[i]).fadeTo(1000, 0, function() {
});
},1000*i);
lets try this

How can I continue to play my GIF during JavaScript processing (as it freezes)?

My GIF image freezes after 5 seconds while my JavaScript code is doing some work. It unfreezes when procesing is finished.
Is there a solution to animate my GIF while the code is executing?
Here's my JavaScript code:
var play = function() {
var image = document.getElementById('img');
image.style.display="block";
window.setTimeout(function(){
for ( var i =0; i < 2000000000; i++ )
{
//Do nothing, in example
}
}, 5000);
};
var stop = function() {
var image = document.getElementById('img');
image.style.display="none";
};
HTML code:
<img id="img" src="loader.gif" style="display: none;"/>
<button id="Start" onclick="play()">Play</button>
<button id="Stop" onclick="stop()">Stop</button>
I think that in this case you should use webworker elements. They allow you to do some asynchronous operation in the background of the UI elements.
One example
<p>Value passed by the worker: <output id="result"></output></p>
<script>
var worker = new Worker('worker.js');
worker.onmessage = function (event) {
document.getElementById('result').textContent = event.data;
};
</script>
In a separate file (worker.js):
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// Found a prime!
postMessage(n);
}
Every time that you call postMessage you send some data from the background (that fires onmessage event of the worker element ) to the main thread.
Have a look at Using jQuery UI progress bar with MVVM, Knockout and web workers for your case:
In this post I would like to explore:
How to use the jQuery UI progress bar with KnockoutJS and MVVM pattern, as a simple example of reusing existing JavaScript UI components.
How to use web workers to execute long running task asynchronously and notify view model about the results and progress.
Use yield as in this working example with minor mod's to your own code...
var play = function() {
//'-----------------------------------Insert Handler..
var obj = myfuncGen.next(); //'start it
if (obj.done == false) {
setTimeout(play, 150); //'adjust for the amount of time you wish to yield (depends how much screen drawing is required or etc)
}
}
var myfuncGen = myfuncSurrogate(); //'creates a "Generator" out of next.
function* myfuncSurrogate() { //'This the original function repackaged! Note asterisk.
//'-------------------------------------End Insert
var image = document.getElementById('img');
image.style.display="block";
//window.setTimeout(function(){
console.log("start");
for ( var i =0; i < 20000000; i++ )
{
if ((i % 1000000) == 0) { //a yield set to go off every 1,000,000 loops (if the yield is called too often it will needlessly slowe down yor loop)
console.log("yielding ", i / 1000000);
yield;
}
}
console.log("done");
//}, 500);
};
play()
<img id='img' src='http://bestanimations.com/Earth&Space/Earth/earth-spinning-rotating-animation-52.gif' />
..I had to edit out window.setTimeout() as it created a detached function which causes an error with Yield. To restore your original intent, I would call play() from such a timeout.
If the link becomes broken to the random gif I chose, I am sure you could substitute another :-).

Categories

Resources