Here is the code:
function startAnimation() {
setInterval( doAnimationStep, 40) // 40 ms = 25 frames per second
this.stopAnimation= stopAnimation(){
document.getElementById("buttonStop")= setInterval(doAnimationStep, 0)
}
}
My IDE does underscore the curly braces:
I started programming last week and I'm really struggling with methods now...
You can only have methods in classes and objects. However you can create functions within functions. Therefore you could change your code to the following and have similar behavior.
function startAnimation() {
const setInterval = (doAnimationStep, 40) // 40 ms = 25 frames per second
const stopAnimation = () => {
document.getElementById("buttonStop")= setInterval(doAnimationStep, 0)
}
}
On another note: I am not sure what you're trying to accomplish with this line:
document.getElementById("buttonStop")= setInterval(doAnimationStep, 0)
setInterval() returns a non-zero number and getElementById() returns an Element and you're assigning one to the other.
Related
No, I am not talking about <h1> or something like that. I am talking about the <title> element. I created a function, that delays every .5 seconds or so, and changes titles.
The script I have developed reads the array, which includes the titles, and rotates from it. The first time I have ran it, I did not use setTimeout, and it ran instantly, I couldnt read anything.
But when I tried using the setTimeout function, it started to return undefined. What is the problem with this code?
for(var i = 0; i < titles.length ; i++){
setTimeout(function () {document.title = titles[i]}, 500)
}
You're going about this the wrong way (IMO). Using a loop you'll fire off all your timeouts at once. You'd be better off using setInterval
let i = 0, titles = ['title1', 'title2', 'title3'];
let int = setInterval(() => {
document.title = titles[i];
console.log('doc.title: ', document.title);
if (i++ >= titles.length - 1) clearInterval(int);
}, 500)
So I have a weird problem (as I can do this using dummy code, but cannot make it work in my actual code) -
The concept is simple - I need a for loop that upon hitting its max "I" number reverts "I" to 0 again and creates a loop over and over -
DUMMY CODE:
for(i=0;i<10;i++){
console.log(i);
if(i === 10){
i = 0
}
}
Now for the longer code (sorry)
function reviewF(){
// add ID to each of the objects
reviews.forEach((e, i)=>{
e.id = i
})
// get the elements to be populated on page
var name = document.querySelector('p.name');
var date = document.querySelector('p.date');
var rating = document.querySelector('.rating_stars');
var review = document.querySelector('p.review_content_text');
// reverse the array - so the newest reviews are shown first (this is due to how the reviews where downloaded)
var reviewBack = reviews.slice(0).reverse();
// start the loop - go over each array - take its details and apply it to the elements
/**
* THIS IS WHAT I WOULD LIKE TO LOOP OVER FOREVER
*
* **/
for (let i = 0; i < reviewBack.length; i++) {
(function(index) {
setTimeout(function() {
// document.getElementById('reviews').classList.remove('slideOut')
name.classList.remove('slideOut')
date.classList.remove('slideOut')
rating.classList.remove('slideOut')
review.classList.remove('slideOut')
name.classList.add('slideIn')
date.classList.add('slideIn')
rating.classList.add('slideIn')
review.classList.add('slideIn')
name.innerHTML = reviewBack[i].aditional_info_name;
date.innerHTML = reviewBack[i].Date;
rating.innerHTML = '';
review.innerHTML = reviewBack[i].aditional_info_short_testimonial;
if(reviewBack[i].aditional_info_short_testimonial === 'none'){
reviewBack.innerHTML='';
}
var numberOfStars = reviewBack[i].aditional_info_rating;
for(i=0;i<numberOfStars;i++){
var star = document.createElement('p');
star.className="stars";
rating.appendChild(star);
}
setTimeout(function(){
// document.getElementById('reviews').classList.add('slideOut')
name.classList.add('slideOut')
date.classList.add('slideOut')
rating.classList.add('slideOut')
review.classList.add('slideOut')
},9600)
}, i * 10000)
})(i);
// should create a infinite loop
}
console.log('Loop A')
}
// both functions are running as they should but the time out function for the delay of the transition is not?
reviewF();
EDITS >>>>>>>>
Ok so I have found a hack and slash way to fix the issue - but its not dry code and not good code but it works.....
this might make the desiered effect easier to understand
reviewF(); // <<< this is the init function
// this init2 function for the reviews waits until the reviews have run then
// calls it again
setTimeout(function(){
reviewF();
}, reviews.length*1000)
// this version of the innit doubles the number of reviews and calls it after that amount of time
setTimeout(function(){
reviewF();
}, (reviews.length*2)*1000)
From trying a bunch of different methods to solve this issue something I noticed was when I placed a console.log('Finished') at the end of the function and called it twice in a row (trying to stack the functions running..... yes I know a horrid and blunt way to try and solve the issue but I had gotten to that point) - it called by console.log's while the function was still running (i.e. the set time out section had not finished) - could this have something to do with it.
My apologies for the rough code.
Any help here would be really great as my own attempts to solve this have fallen short and I believe I might have missed something in how the code runs?
Warm regards,
W
Why not simply nest this for loop inside a do/while?
var looping = True
do {
for(i=0;i<10;i++){
console.log(i);
}
if (someEndCondition) {
looping = False;
}
}
while (looping);
I would think that resetting your loop would be as simple as setting "i = 0" like in the dummy code. So try putting the following into your code at the end of the for loop:
if(i === 10){
i = 0;
}
I have a class test whose background-color I want to flip between lime and green faster and faster.
For that, I'm using a for loop variable and passing it to a function containing a setTimeout(), but it's not working.
(This is not a duplicate question. The said "original" is about a simple setTimeout() whereas this question is about a setTimeout() within a for loop. I understand that the answers on that question might indirectly answer mine, but the questions themselves aren't the same)
$(document).ready(function() {
for (var i = 0; i < 20; i++) {
delay(i);
$(".test").css('background-color', 'lime');
}
});
function delay(i) {
setTimeout(function() {
$(".test").css('background-color', 'green');
}, 1000 - 50 * i);
}
.test {
width: 300px;
height: 300px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test"></div>
Try this way:
for(var i=0;i<20;i++)
{
delay(i);
}
function delay(i) {
setTimeout(function() {
if (i%2 == 0) {
$(".test").css('background-color', 'green');
} else {
$(".test").css('background-color', 'lime');
}
}, 1000 - 50 * i);
}
The problem is the loop executes faster than the timeout. setTimeout function basically says execute the given function after a certain time. The for loop you created there will continue without waiting for the code inside the setTimeout function to be executed, In other words your code producing 20 functions that will be executed in the future.
There are many way to produce the functionality you need.
To keep it simple and solve it you should create two functions instead:
$(document).ready(function() {
for (var i = 0; i < 20; i++) {
delay_lime(i);
delay_green(i+1);
}
});
function delay_green(i) {
setTimeout(function() {
$(".test").css('background-color', 'green');
}, 1000 - 50 * i);
}
function delay_lime(i) {
setTimeout(function() {
$(".test").css('background-color', 'lime');
}, 1000 - 50 * i);
}
try this: here is a example example
$(document).ready(function() {
delay();
var start = 0;
delay(start);
function delay(start) {
setTimeout(function() {
if(start == 0 ){
$(".test").css('background-color', 'green');
start = 1;
}else{
$(".test").css('background-color', 'red');
start = 0;
}
delay(start);
}, 100);
}
});
If you want to use a for loop, you should turn its containing function into an async function and await promises that resolve at the desired time:
const delay = (i) => new Promise(resolve => {
setTimeout(resolve, 1000 - 50 * i);
});
function changeToGreen() {
$(".test").css('background-color', 'green');
}
function changeToLime() {
$(".test").css('background-color', 'lime');
}
(async () => {
for (var i = 0; i < 20; i++) {
await delay(i);
changeToLime();
await delay(i);
changeToGreen();
}
})();
Your loop doesn't wait for any of the timeouts to occur, it runs through and queues up the events which will fire at the relevant intervals.
However, whilst doing so it sets the background color to lime a number of times.
After the loop has finished, the queued intervals start firing, and they set the background color to green a number of times.
But the colours do not alternate as the code execution is not in the order you expect.
Also, the multiple calls to setInterval queue the events to be fired after the specified delay. The code does not wait for the allotted time and then fire the next one. So your could of 1000 - 50 * i actually queues the latest event first, and so on until it queues the event that will actually fire first. Does that make sense? It will be more intuitive for you to set these in the order that they will fire. You could achieve the reducing delay by incrementing the timeout by a variable which reduces, e.g.
time = 1000;
delay = 1000;
setTimeout (blah, time);
time += delay;
delay -= 50;
setTimeout (blah, time);
// etc.
You could achieve an alternating effect by setting alternate intervals to be green and lime. For that a simple toggle variable would help.
color = 1;
color = 1 - color; // toggles between 0 and 1
useColor = ["lime", "green"][color];
I shan't rewrite your entire program for you, but I can assist more if you have specific questions. The best way to learn is to do.
There is a slight misunderstanding about the way timeouts work in the example code. Timeouts are asynchronous, meaning that they execute out of the normal order of execution. As a result, the lime green is shown immediately, and then at various times later the background is repeatedly changed to green; although, the only time the change is noticed is the first time as changing from green to green has no effect.
setTimeout creates a task, JavaScript in a browser is single threaded and will execute tasks through a task scheduler.
Using 1000 - 50 * i from 0 to 19 in the approach shown in the question will result in timeouts being scheduled for execution. First at 1000, then at 950, etc. However, they are all scheduled at the exact same time. So there is no difference scheduling them in forward or reverse order as the only relevant metric used is the time. Essentially the result is that every 50 milliseconds, the background color is set to green in this example.
Unfortunately, tasks that get executed in the browser are not executed exactly on time, and using this will aim at 50 milliseconds per call, but due to Operating System scheduling and depending on the system in use the result could be wildly different.
This could have been done with an interval just as easily, where the interval used was 50 milliseconds (although it would still suffer from the aforementioned OS issue). That said, there is no acceleration being used there. A better approach here, since we are dealing with animation (the colors flashing) would be to instead use requestAnimationFrame MDN.
requestAnimationFrame will attempt to run your code at 60 frames per second, or roughly 16.6 milliseconds per frame (1000 milliseconds / 60 frames).
Given that the goal was acceleration, a rate could be put in place to ramp the flashing.
// Cache the constructed jQuery object for element with class "test"
var testCache = $('.test');
// Create a set of colors to use in the flashing
var colors = ['lime','green'];
// Use a variable for a switch between the two colors
var colorSwitch = 0;
// Keep track of how many times the color has flashed
var i = 0;
// Used for tracking the start of an animation sequence
var start;
// In order to facilitate acceleration, use a function for
// determining the time between flashes,
// used an offset x^2 line at (20,16) with a 2x width
// y = 1/2(x-19)^2 - 19x + 16
var ft = t => 0.5*(t-19)*(t-19) - (t-19) + 16;
// This function will be called every 16.6 milliseconds
// by requestAnimationFrame, the timestamp is automatically injected
(function flashAccel(timestamp){
// Loop control to ensure only 20 flashes occur
if(i >= 20) return;
// Track the start of the timing for the animation sequence
start = start || timestamp;
// This is the milliseconds since the last sequence was updated
var elapsed = timestamp - start;
// Check to see if enough time has elapsed based on the acceleration
// function's value and the current value, if it has then update the view
if( elapsed > ft(i) ){
// Swaps between 0 and 1
colorSwitch = 1 - colorSwitch;
// Selects 0 or 1 indexed color
var color = colors[colorSwitch];
testCache.css('background-color',color);
// Update metrics
i++;
start = timestamp;
}
// Request the function to be called again in roughly 16.6 milliseconds
window.requestAnimationFrame(flashAccel);
})()
.test {
width: 300px;
height: 300px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test"></div>
I'm trying to simplify the introduction of loops to children in JS and p5.js with writing some helper functions to ease difficult things. What I'm aiming for is something like repeat(5){ //code to be executed 5 times }
something similar can be achieved with a higher order function, but it's not quite as simple/transparent as I hope it could be.
for example:
function repeat(n = 1) {
let i = 0;
return fn => {
while(n--) {
i++;
fn(i)
}
}
}
// example usage:
repeat(10)(i => {
console.log('floop boop', i)
})
but the usage and curly/parens will confuse children. I'm aware that a while loop is one direction to go, but It's sort of goes in an inverse direction of what a repeat loop might do. It's the direction to push them, but maybe not ideal for day 1 of coding.
ultimately We could eventually use it something like:
let i = 0;
repeat(10){
i++
console.log('we are repeating and we're on iteration number ', i)
}
If you are teaching JavaScript you won't be able to avoid first class functions. I would start by creating a method called repeat, it takes in a number of times to repeat and the function with the behaviour you want repeated.
function repeat(times, fn) {
var i = 0;
while(times--) {
i++;
fn(i);
}
}
repeat(10, function(i) {
console.log('we are repeating and we\'re on iteration number ', i);
});
I agree that a higher order function may be confusing. In both cases you don't need functions to teach loops.
I'm using Coffescript and p5.
for i in range 10
rect 20*i,20,10,10
Range has same defintion as in underscore.
Python indentation without colon
P5dojo.com is my site.
im having a problem with my code, i have to make a loop, that each it loops, have to change add a class/change the color of something for just a while. i tried with a for and it didnt work, then i tried something like a loop using setinterval and it works better but still have something that is not working, it just adds the class/or toggle in that case first 1 element, and then maybe 2, then 3,etc and not 1 by 1 thanks
function runp(patron){
var x = 0;
var intervalID = setInterval(function () {
$("#container"+patron[x]).toggle(1).delay(1000).toggle(1).delay(1000);
if (++x === 20) {
window.clearInterval(intervalID);
}
}, 2000);
}
this is what i have: https://jsfiddle.net/dt8kxebg/
and this is what im trying to replicate: https://jsfiddle.net/jf0opams/
I think your problem is that you execute the runp() several times, because it is inside of a for loop. You should rather invoke the function just once after the loop, when your patron[] array is filled with random numbers (1-4).
The problem happens, because the for loop is super fast (few millisecs) filling your array with 20 random numbers. So you have invoked the animation/toggling function 20 times. This on/off behaviour takes 2 seconds and happens 20 times almost at the same time. You can see in my code in the browser console what the console.log() output to understand the behaviour better.
function start(patron, patronl){
while (patron.length<20){
patron.push(rand(1,4));
console.log('start: '+patron.length);
//runp(patron, patron.length);//old place
//readp(patron,//
}
runp(patron);//new place
}
function runp(patron, iteration){
var x = 0;
var intervalID = setInterval(function () {
$("#container"+patron[x]).toggle(1).delay(1000).toggle(1).delay(1000);
//see how 20 outputs come at once, if runp() is inside for loop
console.log('togglewait: '+x, 'start: '+iteration);
if (++x === 20) {
window.clearInterval(intervalID);
}
}, 2000);
}