Javascript List Item Animations - javascript

I am working on a very basic animation where classes are removed from list items once they have been loaded and appended to the document. The issue I am having is with the animation itself. I want the animation to execute in a stepped manner like the image below...
What actually though is that the loop runs completely, console.log messages get output in a stepped manner, but the classes are all removed at the same time once the loop has completed. How can I change this behavior? Why would the console.log messages be stepped but the classList.remove functionality is not executed at the same time?
Here is my code...
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
/**/
function showListItems() {
var listItems = document.querySelector('.idList');
var n = 20;
var c = 0;
var itemArray = new Array();
for (var i = 0; i < listItems.children.length; i++) {
var item = listItems.children[i];
if (item.classList && item.classList.contains('idList__item--hide')) {
console.log('Item: ', item);
itemArray[c] = item;
c++;
}
}
console.log('Item Array: ', itemArray);
itemArray.forEach(function(el, index) {
sleep(n);
el.classList.remove('idList__item--hide');
console.log("EL[" + index + "]: ", el);
});
}
I realize this code may look over complex and perhaps it is, but I have tried about everything I can think of. I have tried using promises, for loops, now the forEach method.
Thank you.

The browser doesn't update until javascript finishes running. Your script doesn't relinquished control back to the browser while sleeping so the browser can't update. This is exactly what setTimeout is for.
Change
itemArray.forEach(function(el, index) {
sleep(n);
el.classList.remove('idList__item--hide');
console.log("EL[" + index + "]: ", el);
});
to
itemArray.forEach(function(el, index) {
const ms = n * (index + 1);
setTimeout(function() {
el.classList.remove('idList__item--hide');
console.log("EL[" + index + "]: ", el);
}, ms);
});
We're scheduling all the remove calls in advance which is why we're multiplying n by index + 1.
And in case you're interested, here is the code I used to test sleep vs setTimeout.
https://codepen.io/rockysims/pen/jeJggZ

This may be a bad way but it should solve your problem.
You can use setTimeout() in forEach, and use index to change time parameter, like it:
itemArray.forEach(function(el, index) {
setTimeout(function(){
el.classList.remove('idList__item--hide')
},500*(index+1))
});

I used Jquery each and setTimeout functions for chaining the animations.
$( "li" ).each(function( index ) {
var listItem = $( this );
setTimeout(function() {
listItem.animate({
opacity: 1
}, 500);
}, (index + 1) * 500);
});
ul {
padding : 20px;
}
ul li {
list-style : none;
height : 50px;
background-color : lightgreen;
margin : 20px;
opacity : 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>Hello world 1</li>
<li>Hello world 2</li>
<li>Hello world 3</li>
<li>Hello world 4</li>
</ul>

Related

Javascript onLoad function

I would like to use a function that prints a string slow in sequence on a page once the page has loaded. Something like this:
"W, E, L, C, O, M, E , T, O, M, Y, P, A, G, E"
Any suggestions where i can find a guide?
Thanks in advance!
Try with SetInterval function .split the string with space the apply the array with setInterval with time delay
var a = "WELCOMETOMYPAGE";
window.onload = function() {
var arr = a.split('');
var i = 0;
var timer = setInterval(function() {
if (arr.length > i) {
document.body.innerHTML += '<span>' + a[i] + ',</span>';
}
i++;
}, 500);
}
span {
transition: all 0.5s ease;
}
You can probably achieve this with a clever use of setInterval
var welcome = "Welcome to my page";
var index = 1;
var interval = setInterval(function(){
if(index <= welcome.length) {
console.log(welcome.substr(0,index))
index++;
} else {
clearInterval(interval);
}
}, 500);
But of course instead of console.log update your page element. I'm using console.log so that you can quickly test this code.
So substitute:
console.log(welcome.substr(0,index))
With:
document.getElementById("element_id").textContent=welcome.substr(0,index)
Alternatively you could use a library like Greensock which is very good at sequencing stuff. In fact they even have a function that does exactly that:
https://greensock.com/
UPDATE:
Of course all of this has to be inside a window onload function to make sure it executes after the page has loaded:
window.onload = function() {
var welcome = "Welcome to my page";
var index = 1;
var interval = setInterval(function(){
if(index <= welcome.length) {
document.getElementById("element_id").textContent=welcome.substr(0,index)
index++;
} else {
clearInterval(interval);
}
}, 500);
}
SUMMARY:
Study
How to execute javascript code after the page has loaded
How to use setInterval in javascript
How to update dom elements using javascript (study jquery as well while you at it)

Javascript - Mouse Wheel Go to Class

Every time I use the mouse wheel (you know normal scrolling) I want the JS (jquery or whatever) to scroll to a specific class (or id doesn't matter).
I have multiple divs so code like $('body').scrollTo($nextdiv) is not an option.
I just want to make every wheel cycle to move to a next div with a specific class/id. The same for the reverse scroll. To move one div (with a specific class) up.
I found mouse wheel event and how to move to a specific div but can't manage to make it work together.
Animated scroll would be cool.
Simple question. Can I have class AND id in the same div? ex <div class="a" id="b"> ?
Quick example, this code can be improved. Better to test on jsfiddle. Point mouse over list and scroll.
Note: I didn't use class but if you understand what I did it's easy to use classes.
Note 2: I just change color but logic can be replace with anything you want.
demo
demo 2 (with classes)
var i = 0;
var list = document.getElementById("list"), length = list.children.length;
list.addEventListener("wheel", ColorLi);
function ColorLi(e) {
//reset colors
for(var j = 0; j < length; j++)
list.children[j].style.color = "black";
//calculate index
if(e.wheelDelta > 0)
i++;
else
i--;
//fix index out of range
i = i < 0 ? 0 : i;
i = i > length-1 ? length-1 : i;
//set color
list.children[i].style.color = "red";
}
<ul id="list">
<li style="color: red">A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
You could use the following plugins: jquery.mousewheel and jquery.scrollTo plugin, like:
/*!
* jQuery Mousewheel 3.1.13
*
* Copyright 2015 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
// The actual code:
$(document).ready(function () {
var targets = $('.scroll'); // List of elements to scroll to
var index = 0;
var duration = 500;
var canScroll = true;
var cache;
function limit(x, min, max) {
return Math.min(max, Math.max(min, x));
}
$(window).mousewheel(function (ev) {
if (canScroll) {
cache = index;
if (ev.deltaY < 0) {
index = index + 1; // Scrolling down, so increase index
} else {
index = index - 1; // Scrolling up, so decrease index
}
// Make sure the index is between 0 and (targets.length - 1)
index = limit(index, 0, targets.length - 1);
console.log(index);
// Make sure to scroll if and only if the value has changed
if (index !== cache) {
// Scroll to the target element:
$(window).scrollTo(targets.get(index), {
duration: duration,
easing: 'swing'
});
canScroll = false;
setTimeout(function () {
canScroll = true;
}, duration);
}
}
ev.preventDefault();
return false;
});
});
div {
content: ' ';
height: 500px;
background-color: #f2f2f2;
}
div:nth-child(even) {
background-color: #d0d0d0;
}
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//cdn.jsdelivr.net/jquery.scrollto/2.1.0/jquery.scrollTo.min.js"></script>
<div class="scroll">div1</div>
<div class="scroll">div2</div>
<div class="scroll">div3</div>
<div class="scroll">div4</div>
<div class="scroll">div5</div>
<div class="scroll">div6</div>

Need Jquery chaning My Background image in a DIV

I`m starting level in jquery , but i have the concept of my idea , i have a #SlidShow div , all i need to change the css property ( background-image ) every 3 second , i have i think 4 image , so my concept is (( Make New Array with images link )) and change the .css( background-image ) of this div with this array every 3s ..
i hope that my concept be right :) , can any one help me with that
#('SlideShow').css('background-image', (Array /* Cant handle it */));
var array = ['url(a.png)', 'url(b.png)', 'url(c.png)', 'url(d.png)'];
var i = 0;
function setBackgroundImage() {
$('#SlideShow').css('background-image', array[i]);
i = i % array.length;
}
setBackgroundImage();
setInterval(setBackgroundImage, 3000);
You already got your answer. Just wanted to add that jQuery is a bit overkill if this is all you want to do, but it's probably not.
Here is a pure javascript solution:
http://jsfiddle.net/2BQV5/2/
var arr = ['http://placekitten.com/200/300','http://placekitten.com/200/301','http://placekitten.com/200/302'];
window.onload = function ()
{
index = 0;
var c = document.getElementById('cat');
setInterval(function() {
if(index > arr.length-1) {index = 0}
c.style.backgroundImage='url(' + arr[index++] + ')';
}, 3000);
}
Have fun!
Edit
However for the second request in the comments, to have to pictures fade, jQuery is probably more suited.
Here is one way to achieve the fading effect:
http://jsfiddle.net/8jWT5/
var arr = ['http://placekitten.com/200/300','http://placekitten.com/200/301','http://placekitten.com/200/302'];
$(document).ready(function() {
var c = $('#cat');
fade = document.createElement('div');
$(fade).attr('style','position: absolute; width:' + c.width() + 'px; height:' + c.height() + 'px;').attr('id','fade').hide();
c.append(fade);
var index = 0;
setInterval(function () {
$('#fade').css('background-image', 'url(' + arr[index] + ')').fadeIn(500,function() {
c.css('background-image', 'url(' + arr[index++] + ')');
if(index > arr.length-1) {index = 0}
$(this).hide();
});
}, 3000);
});

Jquery + HTML Thumbnail scroll

I want to create a list of thumbnails with a button previous and another next, showing 10 thumbnails at a time and hiding the rest, and when you reach the 10th tumbnail and click the next button, the 1st disappear and appear the 11th.
I've tried with:
Javascript
jQuery(document).ready(function() {
var count = 0;
var images = 11;
var page = 1;
var current = 1;
jQuery('.ice-navigator li').each(function(index) {
count++;
jQuery(this).attr('id', 'menu-item-' + count);
jQuery(this).attr('class', 'menu-page-' + page);
if(count >= (page * images)) {
page++;
}
jQuery(this).hide();
})
jQuery('.ice-navigator li.menu-page-1').show();
jQuery('.ice-next').click(function() {
if(current >= count) {
current = 1;
} else {
current++;
}
item = jQuery('.ice-navigator li#menu-item-' + current);
if(jQuery(item).hasClass('active')) {
jQuery(item).removeClass('active');
page = jQuery('.ice-navigator li#menu-item-' + current).attr('class');
jQuery(item).addClass('active');
} else {
page = jQuery('.ice-navigator li#menu-item-' + current).attr('class');
}
jQuery('.ice-navigator li').hide();
jQuery('.ice-navigator li.' + page).show();
})
jQuery('.ice-previous').click(function() {
current--;
if(current <= 0) {
current = count;
}
item = jQuery('.ice-navigator li#menu-item-' + current);
if(jQuery(item).hasClass('active')) {
jQuery(item).removeClass('active');
page = jQuery('.ice-navigator li#menu-item-' + current).attr('class');
jQuery(item).addClass('active');
} else {
page = jQuery('.ice-navigator li#menu-item-' + current).attr('class');
}
})
jQuery('.ice-navigator li').click(function() {
current = jQuery(this).attr('id').replace('menu-item-', '');
})
})
HTML
<div class="ice-previous">Previous</div>
<div class="ice-navigator-wrapper clearfix">
<div class="ice-navigator-outer">
<ul class="ice-navigator">
<li>THUMBNAIL 1</li>
<li>THUMBNAIL 2</li>
[...]
<li>THUMBNAIL 11</li>
<li>THUMBNAIL 12</li>
</ul>
</div>
</div>
<div class="ice-next">Next</div>
Thanks!
Edit: I now understand it is like a circular ref. I have made some changes accordingly.
See my updated DEMO here
Below is for regular nav which stops when you reach the end.
Check my old DEMO here.
I used 2 pointers to manage the start and end position. Implemented adjustNav function to show/hide div based on start and end position.
This looks like a job for jCarousel:
http://sorgalla.com/jcarousel/
There are other plugins that provide this functionality. I just used jCarousel on another project and it was the first thing I thought of.
EDIT
I didn't realize you don't want to use a plugin. You could do this with hand-coded jQuery, but you're going to be writing a lot of code.

Long task in Javascript

Why in the following code I see the whole page at once ? Thanks !
HTML:
<div></div>
CSS:
div {
width: 100px;
height: 300px;
border: 1px solid black;
text-align: center;
}
Javascript:
$(function() {
for (var i=0; i<15; i++) {
sleep(100);
$("div").append("<span>--- " + i + " ---<br /></span>");
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
});
Because Javascript on web browsers is single-threaded (although that's changing; see below) and virtually no browser updates its UI while the (main) Javascript thread is busy. All your sleep function does is block everything for 100ms, it doesn't let the browser do anything else like update its UI (e.g., doesn't "yield").
There are a couple of ways to do what you're trying to do:
Use the new web workers stuff; but note that it's not widely-supported yet.
Make your loop a function that calls itself via setTimeout. That way, your code is yielding to the browser and letting it update its UI.
Here's a simple example of how you might apply #2 above to your code:
$(function() {
var i;
doOne();
function doOne() {
$("div").append("<span>--- " + i + " ---<br /></span>");
if (i++ < 15) {
setTimeout(doOne, 0); // <== Won't really be zero, browsers clamp it at ~10
}
}
});
If you have a lot of loop iterations (e.g., a couple of hundred instead of 15), it may well be worth doing a chunk of them on each iteration rather than yielding on each iteration; the yield takes a measureable time (typically ~10-15ms).
You need to hand over some processing time to the UI since javascript is single threaded, like this:
$(function() {
function appendDiv(i) {
$("div").append("<span>--- " + i + " ---<br /></span>");
if(i < 14)
setTimeout(function() { appendDiv(i+1); }, 100);
}
appendDiv(0);
});​
You can see a demo here
You could also use an interval for what you want, like this:
$(function() {
var i = 0;
var interval = setInterval(function() {
$("div").append("<span>--- " + i++ + " ---<br /></span>");
if(i == 15) clearInterval(interval);
}, 100);
});​

Categories

Resources