I've search around and tried my best, but could not find out how to achieve the following:
Loop through an unknown amount of divs
Have some sort of animation (maybe just a simple width growth of 110%)
Each Div fades in/fades out
Delay in between the final div fading out and the first div fading in again
My Current code is as follows
JS Fiddle Link - Example
HTML
<div class="container">
<div class="popup">Popup 1</div>
<div class="popup r">Popup 2</div>
<div class="popup b">Popup 3</div>
<div class="popup g">Popup 4</div>
<div class="popup y">Popup 5</div>
</div>
CSS
.popup {
display: none;
width: 400px;
height: 80px;
background: #000;
color: #fff;
line-height: 80px;
text-align: center;
}
.r{background:red}
.b{background:blue}
.g{background:green}
.y{background:yellow}
jQuery
var popups = $('.popup');
var i = 0;
function step() {
if (i >= popups.length)
i = 0;
$(popups[i]).fadeToggle(300);
i++;
}
setInterval(step, 2000);
As you can see, my divs don't fade out until all are shown, this is not desired.
You can chain together animations with a delay between:
function next() {
if (i >= popups.length)
i = 0;
popups.eq(i).fadeIn(300).delay(2500).fadeOut(300).delay(1000).queue(function(){
next();
$(this).dequeue();
});
i++;
}
next()
(note: I have used popups.eq(i) which is the same as $(popups[i]))
Live example: http://jsfiddle.net/3ujb7k4L/7/
Something like this?
var popups = $('.popup');
var i = 0;
function fadeOutLater(popup) {
setInterval(function() {
popup.fadeOut(500);
}, 5000);
}
function step() {
var popup;
if (i >= popups.length)
i = 0;
popup = $(popups[i]);
popup.fadeIn(300, fadeOutLater(popup));
i++;
}
setInterval(step, 2000);
To create a longer pause between hiding the last element and showing the first element again you could skip one fadeIn/fadeOut cycle on resetting the counter:
var popups = $('.popup');
var i = 0;
function step() {
if (i >= popups.length) {
i = 0;
} else {
$(popups[i]).delay(300).fadeIn(300).delay(200).fadeOut(300).delay(200);
i++;
}
}
setInterval(step, 2000);
Like here: http://jsfiddle.net/r72qpher/
Related
I have a fixed div on the page which contains a logo and as the user scrolls and this logo passes over other divs I wnat to the change the colour of the logo.
I have this working over a single div but need to it work across multiple so any help appreciated.
The WIP site can be seen here... dd.mintfresh.co.uk - if you scroll down you'll (hopefully) see the logo change from black to white as it crosses an illustrated egg. I need the same to happen when it crosses other divs further down the page.
The script so far...
jQuery(window).scroll(function(){
var fixed = jQuery("logo");
var fixed_position = jQuery("#logo").offset().top;
var fixed_height = jQuery("#logo").height();
var toCross_position = jQuery("#egg").offset().top;
var toCross_height = jQuery("#egg").height();
if (fixed_position + fixed_height < toCross_position) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else if (fixed_position > toCross_position + toCross_height) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else {
jQuery("#logo img").css({filter : "invert(0%)"});
}
}
);
Any help appreciated. Thanks!
you need to fire a div scroll event. you can assign
$("div1").scroll(function(){
//change the color of the div1
}
});
$("div2").scroll(function(){
//change the color of the div2
}
});
or you can assign a class to divs which you want to change the color
$(".div").scroll(function(){
//change the color of the div which you are scrolling now
}
});
You can use like this :-
$(window).scroll(function() {
var that = $(this);
$('.section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('active')) {
$('.logo').addClass('invert');
} else {
$('.logo').removeClass('invert');
}
}
});
});
body {
padding: 0;
margin: 0;
}
div {
background: #f00;
height: 400px;
}
.logo {
position: fixed;
top: 0;
left: 0;
width: 100px;
}
.logo.invert {
filter: invert(100%);
}
div:nth-child(even) {
background: #ff0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="https://dd.mintfresh.co.uk/wp-content/uploads/2018/06/DD_logo.svg" class="logo" />
<div id="page1" class="section"></div>
<div id="page2" class="section active"></div>
<div id="page3" class="section"></div>
<div id="page4" class="section active"></div>
<div id="page5" class="section"></div>
As your site code you can do like this :
$(window).scroll(function() {
var that = $(this);
$('#content > section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('black')) {
$('#logo img').css({filter: 'invert(0%)'});
} else {
$('#logo img').css({filter: 'invert(100%)'});
}
}
});
});
I want to show and hide a series of divs based on time interval.
Show div 1 after 4 seconds, show div 2 after a further 4 seconds and so on.
The previous div being hidden, so it appears as if new information is replacing the previous and at time intervals.
I have it working to a point, it's just when I add more divs.
setInterval(function() {
$("#a").hide();
setTimeout(function() {
$("#b").fadeIn('normal');
});
}, 4000);
#b, #c {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a">1</div>
<div id="b">2</div>
<div id="c">3</div>
https://jsfiddle.net/Layt8cuy/1/
The first div needs to be there by default, and they stop with the last div with no loop back to the beginning.
Here is basic function Jsfiddle
var currentDiv = $("#a");
var nextDiv, count = 1;
var myInterval = setInterval(function() {
if (count == 5) {
clearInterval(myInterval);
} else {
count++;
currentDiv.hide();
currentDiv = currentDiv.next();
currentDiv.show();
}
}, 2000);
#b,
#c,
#d,
#e {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a">1</div>
<div id="b">2</div>
<div id="c">3</div>
<div id="d">4</div>
<div id="e">5</div>
You need a variable to track the current visible div. Also it's recommended to use a class to select all divs, otherwise you'll have to select them by tag name, which is an issue if you have other divs that shouldn't be included.
You only need setInterval() and inside it first hide all divs, then show the div with the current index, and finally increment the current index variable if it is still less that the number of divs, otherwise reset it to 0.
var current = 0;
setInterval(function() {
var divs = $(".roll").hide();
divs.eq(current).fadeIn("normal");
if (current < divs.length - 1)
current++;
else
current = 0;
}, 1000);
.roll {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a" class="roll">1</div>
<div id="b" class="roll">2</div>
<div id="c" class="roll">3</div>
To do only one loop, you need to store the ID of the setInterval() and use it in clearInterval() to stop. Here is a solution for the points in your comments:
var current = 0;
var divs = $(".roll");
var timer = setInterval(function() {
if (current < divs.length - 1) {
divs.eq(current).hide();
current++;
divs.eq(current).fadeIn("normal");
} else
clearInterval(timer);
}, 1000);
.roll {
display: none
}
#a {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a" class="roll">1</div>
<div id="b" class="roll">2</div>
<div id="c" class="roll">3</div>
a working example, with returning to first div after finish
recursive + timeout
you can use the same method for your situation:
let duration = 1000, // these are miliseconds
activeIndex = 0; // first item to activate
function activateNext() {
let boxes = $('.boxes > div');
// activate current item
boxes.addClass('hide').eq(activeIndex).removeClass('hide');
// increase activeIndex and make reset at end of collection
if (++activeIndex >= boxes.length) activeIndex = 0;
// run the function again after duration
setTimeout(function() {
activateNext(activeIndex);
}, duration)
}
// start the loop
$(window).on('load', activateNext);
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="boxes">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
Without looping back to first:
let duration = 1000, // these are miliseconds
activeIndex = 0; // first item to activate
function activateNext() {
let boxes = $('.boxes > div');
// activate current item
boxes.addClass('hide').eq(activeIndex).removeClass('hide');
// increase activeIndex and make reset at end of collection
if (++activeIndex < boxes.length) {
// run the function again after duration
setTimeout(function() {
activateNext(activeIndex);
}, duration)
}
}
// start the loop
$(window).on('load', activateNext);
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="boxes">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
You might also consider pure CSS solution:
#a, #b, #c {
position: absolute;
animation: hide 4s linear forwards;
}
#b, #c {opacity: 0}
#b {
animation-delay: 4s;
}
#c {
animation-name: last;
animation-delay: 8s;
}
#keyframes hide {
0%, 99.99% {opacity: 1}
100% {opacity: 0}
}
#keyframes last {
0%, 100% {opacity: 1}
}
<div id="a">1</div>
<div id="b">2</div>
<div id="c">3</div>
I have two parent divs: .inputs and .infoBoxes. Each of them have an equal number of children. When the user clicks into the first .input in .inputs, the first .infoBox in .infoBoxes should slideDown(). Same for second, third, etc. I'd like to do this without re-writing the same code for each pair. So far I have:
var $inputs = $('.inputs').children();
var $infoBoxes = $('.infoBoxes').children();
for(var i = 0; i < $inputs.length; i++ ) {
$($inputs[i]).find('.input').focus(function() {
$($infoBoxes[i]).slideDown();
})
$($inputs[i]).find('.input').blur(function() {
$($infoBoxes[i]).slideUp();
})
}
This isn't working but I have tried replacing i with the indexes of each div.
$($inputs[0]).find('.input').focus(function() {
$($infoBoxes[0]).slideDown();
})
$($inputs[0]).find('.input').blur(function() {
$($infoBoxes[0]).slideUp();
})
repeat...
repeat...
repeat...
This works but isn't very DRY. I'm looking for a better solution that won't have me repeating a bunch of code.
First code will not work, because you using same variable for all internal functions. You should wrap it into function, which will create local variable for index. Try following code:
var $inputs = $('.inputs').children();
var $infoBoxes = $('.infoBoxes').children();
for(var i = 0; i < $inputs.length; i++ ) {
(function(ix) {
$($inputs[ix]).find('.input').focus(function() {
$($infoBoxes[ix]).slideDown();
})
$($inputs[ix]).find('.input').blur(function() {
$($infoBoxes[ix]).slideUp();
})
})(i);
}
slideDown is used for showing elements. I am guessing you want to hide elements, since you are clicking on them and you cant click an hidden element. Use hide or slideUp to hide elements.
$(".input, .infobox").on("click", function() {
var ind = $(this).index();
$(".infobox:eq(" + ind + "), .input:eq(" + ind + ")").hide(500);
});
.input,
.infobox {
widht: 100%;
height: 50px;
text-align: center;
margin: 5px 0;
color: white;
}
.input {
background: red;
}
.infobox {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="inputs">
<div class="input">1</div>
<div class="input">2</div>
<div class="input">3</div>
<div class="input">4</div>
<div class="input">5</div>
</div>
<div class="infoboxes">
<div class="infobox">1</div>
<div class="infobox">2</div>
<div class="infobox">3</div>
<div class="infobox">4</div>
<div class="infobox">5</div>
</div>
I have and editable div that allow users to enter text. This is part of a chat widget so the design needs the box to be fixed to the bottom.
When a user types I need javascript to catch the resize and append classes to elements where needed.
I managed to get the box to resize upwards but I have had a lot of trouble scaling it back down again.
I have been stuck on this for days now, so any help now would be greatly appreciated.
I have the function and a basic UI version here JSFiddle
Its probably really simple but I am having no luck figuring this out
JSFiddle
var chatBoxSize = {
oldHeight : 0,
scrollHeight : 0,
lastClass : 1,
minClass : 1,
maxClass : 5,
min_height : 0,
last_size : 0,
getClass : function (size){
var sizes = [chatBoxSize.min_height, chatBoxSize.min_height * 2, chatBoxSize.min_height * 3, chatBoxSize.min_height * 4, chatBoxSize.min_height * 5];
switch (size){ case sizes[0] : return 1; break; case sizes[1] : return 2; break; case sizes[2] : return 3; break; case sizes[3] : return 4; break; case sizes[4] : return 5; break; };
//is not exact
var r = null;
console.log(size);
for(var x = 0; x < sizes.length; x++){
if(x < sizes.length){
if(size >= sizes[x] && size < sizes[(x + 1)]){
return (x + 1);
}
}
}
return chatBoxSize.maxClass;
}
};
$(function () {
chatBoxSize.min_height = parseInt($('#msgWriteArea').height());
chatBoxSize.max_height = chatBoxSize.min_height * 4;
chatBoxSize.last_size = chatBoxSize.min_height;
});
function updateChatSize() {
var id = '#msgWriteArea';
var element = document.querySelector(id);
var size = $(id)[0].scrollHeight;
var container = $('.container');
var toRemove = 'size_' + chatBoxSize.lastClass;
console.log(chatBoxSize.getClass(size));
chatBoxSize.lastClass = chatBoxSize.getClass(size);
console.log('Add new class', chatBoxSize.lastClass);
chatBoxSize.last_size = size;
$(id).removeClass(toRemove);
$(id).addClass('size_' + chatBoxSize.lastClass);
container.removeClass(toRemove);
container.addClass('size_' + chatBoxSize.lastClass);
$('#display').val('Removed ' + toRemove + ' Added ' + chatBoxSize.lastClass);
};
$(function (){
$('#msgWriteArea').bind('change keydown input', function () {
if(event.type == 'keydown'){
updateChatSize();
}
});
})
I have thought of just setting the heights to auto but that will not work with the rest of the ui elements.
Sorry to say but No JS needed at all
flex to the rescue, overflow-y: auto; and max-height to the editable DIV:
Heres a jsBin demo so you can play and resize the browser
*{box-sizing:border-box; -webkit-box-sizing:border-box;}
html, body{height:100%; margin:0;font:16px/1 sans-serif; color:#444;}
#chat{
display: flex;
flex-direction: column;
height:100%;
}
#messages{
flex:1;
overflow-y: auto;
}
#messages > div{
padding: 24px;
background: #eef;
margin: 4px 0;
}
#ui{
background: #eee;
}
#msgWriteArea{
padding: 24px;
overflow-y: auto;
height:100%;
background:#ddd;
max-height:100px; /* if max height is exceeded */
overflow-y: auto; /* add scrollbars */
}
<div id="chat">
<div id="messages">
<div>Message 1</div>
<div>Message 2</div>
<div>Message 3</div>
<div>Message 4</div>
<div>Message 5</div>
<div>Message 6</div>
</div>
<div id="ui">
<div id="msgWriteArea" contenteditable>Some text message</div>
</div>
</div>
Now, if you still really need to the the message area height (for some reasons) you could count the number of lines using JS.
<body>
<div id = "SiteContainer">
<div id = "NavigationButtons"></div>
<div id = "ShowReelContainer">
<div id= "NavigationBackward" name = "back" onclick="setPosition();">x</div>
<div id= "NavigationForward" name = "forward" onclick="setPosition();">y</div>
<div id = "VideoWrapper">
<div id = "SlideShowItem">
<img src="Images/A.png" alt="A"></img>
</div>
<div id = "SlideShowItem">
<img src="Images/B.png" alt="B"></img>
</div>
<div id = "SlideShowItem">
<img src="Images/C.png" alt="C" ></img>
</div>
</div>
</div>
</div>
<script>
var wrapper = document.querySelector("#VideoWrapper");
function setPosition(e)
{
if(e.target.name = "forward")
{
if!(wrapper.style.left = "-200%")
{
wrapper.style.left = wrapper.style.left - 100%;
}
}
else
{
if(e.target.name = "back")
{
if!(wrapper.style.left = "0%")
{
wrapper.style.left = wrapper.style.left + 100%;
}
}
}
}
</script>
</body>
Hi, I am very new to javascript. What I am trying to do, is change the x-position of a div when another div (NavigationForward or NavigationBackward) is clicked. However it does not appear to do anything at all. Basically if the div with name forward is clicked, I want to translate the VideoWrapper -100% from it's current position and +100% when "back". The css div itself VideoWrapper has a width of 300%. Inside this div as you can see is a SlideShowItem which is what will change. Perhaps I am adding and subtracting 100% the wrong way?
EDIT:
Thanks everyone for helping me out with this...I had just one more query, I am trying to hide the arrows based on whether the wrapper is at the first slide or the last slide. If its on the first slide, then I'd hide the left arrow div and if it's on the last, I'd hide the right arrow, otherwise display both of em. Ive tried several ways to achieve this, but none of em work, so Ive resorted to using copies of variables from the function that works. Even then it does not work. It appears that my if and else if statements always evaluate to false, so perhaps I am not retrieving the position properly?
function HideArrows()
{
var wrapper2 = document.getElementById("VideoWrapper");
var offset_x2 = wrapper2.style.left;
if(parseInt(offset_x2,10) == max_x)
{
document.getElementById("NavigationForward").display = 'none';
}
else if(parseInt(offset_x2,10) == min_x)
{
document.getElementById("NavigationBackward").display = 'none';
}
else
{
document.getElementById("NavigationForward").display = 'inline-block';
document.getElementById("NavigationBackward").display = 'inline-block';
}
}
//html is the same except that I added a mouseover = "HideArrows();"
<div id = "ShowReelContainer" onmouseover="HideArrows();">
To achieve this type o slider functionality your div VideoWrapper must have overflow:hidden style, and your SlideShowItemdivs must have a position:relative style.
Then to move the slides forward or backward you can use the style left which allows you to move the divs SlideShowItem relative to it's parent VideoWrapper.
I've tested this here on JSFiddle.
It seems to work as you described in your question, although you may need to do some adjustments, like defining the width of your slides, how many they are and so on.
For the sake of simplicity, I defined them as "constants" on the top of the code, but I think you can work from that point on.
CSS
#VideoWrapper{
position:relative; height:100px; white-space:nowrap;width:500px;
margin-left:0px; border:1px solid #000; overflow:hidden; }
.SlideShowItem{
width:500px; height:100px;display:inline-block;position:relative; }
#NavigationForward, #NavigationBackward{
cursor:pointer;float:left; background-color:silver;margin-right:5px;
margin-bottom:10px; text-align:center; padding:10px; }
HTML
<div id = "SiteContainer">
<div id = "NavigationButtons">
</div>
<div id = "ShowReelContainer">
<div id= "NavigationBackward" name = "back" onclick="setPosition('back');">prev</div>
<div id= "NavigationForward" name = "forward" onclick="setPosition('forward');">next</div>
<div style="clear:both;"></div>
<div id = "VideoWrapper">
<div class= "SlideShowItem" style="background-color:blue;">
Slide 1
</div>
<div class = "SlideShowItem" style="background-color:yellow;">
Slide 2
</div>
<div class = "SlideShowItem" style="background-color:pink;">
Slide 3
</div>
</div>
</div>
</div>
JavaScript
var unit = 'px'; var margin = 4; var itemSize = 500 + margin; var itemCount = 3; var min_x = 0; var max_x = -(itemCount-1) * itemSize;
function setPosition(e) {
var wrapper = document.getElementById("VideoWrapper");
var slides = wrapper.getElementsByTagName('div');
var offset_x = slides[0].style.left.replace(unit, '');
var curr_x = parseInt(offset_x.length == 0 ? 0 : offset_x);
if(e == "forward")
{
if(curr_x <= max_x)
return;
for(var i=0; i<slides.length; i++)
slides[i].style.left= (curr_x + -itemSize) + unit;
}
else if(e == "back")
{
if(curr_x >= min_x)
return;
for(var i=0; i<slides.length; i++)
slides[i].style.left= (curr_x + itemSize) + unit;
} }
After you analyze and test the code, I don't really know what's your purpose with this, I mean, you maybe just playing around or trying to develop something for a personal project, but if you are looking for something more professional avoid to create things like sliders on your own, as there are tons of plugins like this available and well tested out there on the web.
Consider using jQuery with NivoSlider, it works like a charm and is cross browser.
I would recommend using jQuery, this will reduce your coding by quite a bit. Can read more here: http://api.jquery.com/animate/
I've created a simple fiddle for you to take a look at. This example uses the .animate() method to reposition two div elements based on the CSS 'left' property.
CSS:
#container {
position: absolute;
left: 1em;
top: 1em;
right: 1em;
bottom: 1em;
overflow: hidden;
}
#one, #two {
position: absolute;
color: white;
}
#one {
background: pink;
width: 100%;
top:0;
bottom:0;
}
#two {
background: blue;
width: 100%;
left: 100%;
top:0;
bottom:0;
}
HTML:
<div id="container">
<div id="one">Div One</div>
<div id="two">Div Two</div>
</div>
JavaScript/jQuery:
var one, two, container;
function animateSlides(){
one.animate({
left : '-100%'
}, 1000, function(){
one.animate({
left : 0
}, 1000);
});
two.animate({
left : 0
}, 1000, function(){
two.animate({
left:'100%'
}, 1000);
});
};
$(function(){
one = $('#one');
two = $('#two');
container = $('#container');
setInterval(animateSlides, 2000);
});
JSFiddle Example: http://jsfiddle.net/adamfullen/vSSK8/3/