I have a testimonials area on my website that fades from one testimonial to another. I'm having an issue where it will fade out too slowly before the next item fades in causing both to come up making a large div making it look ugly.
I want it to fade from one testimonial to another without jumping and flashing with both.
You can see an example here: http://ledragonvert.com/index_test.php
Here is my Javascript code:
function rotate_p() {
if (p_current == p_count) {
p_current = 1;
} else {
p_current++;
}
var $container = $('#container');
$container.find('p').fadeOut();
$container.find('p:nth-child(' + p_current + ')').fadeIn();
}
var p_count;
var p_current = 0;
var p_interval;
$(document).ready(function () {
rotate_p();
p_count = $('#container').find('p').length;
p_interval = setInterval(function () {rotate_p();}, 7000);
});
Thanks you very much for taking your time out to help me.
the solution is CSS based. since the position of the "p" element is static and you call both fadeOut and fadeIn, there is an overlap, as two p elements are inevitably shown together. To get them one on top of the other you need to use absolute positioning on the p element, like so:
#container {
position:relative;
}
#container>p {
position:absolute;
//use any values you wish, to set the testimonial relative to #container:
top:10px;
left:50px;
}
Related
my question has 3 parts. Any assistance with any part of this JS problem would be greatly appreciated. I am attempting to learn and comprehend JS by trial and error.
I've created this nice looking travel landing page, https://portfolioprime.github.io/Nature%20carousel/glidejs.html with a thumbnail carousel which uses Glide.js, which is really cool and works well. The carousel moves to the left and has arrow buttons to manually control the slide.
But I've been trying to implement a vanilla JS carousel slider,but I am failing miserably. Been struggling for 2 days and the best I can achieve is getting a single carousel item moving left and right. See https://portfolioprime.github.io/Nature%20carousel/.
What I'd like is to get the carousel sliding left automatically, with arrow buttons to manually control the slider.
I'm targeting all the carousel-items with querySelectorAll('.carousel-items') and adding left:-274px to the carousel container glide__slides.
Here's my JS code.
// var & event-listener buttons
document.querySelector(".left").addEventListener("click", slideLeft);
document.querySelector(".right").addEventListener("click", slideRight);
// Function slide left
function slideLeft(left) {
document.querySelector('.glide__slides').style.left = left;
}
// Function slide left
function slideRight(right) {
document.querySelector('.glide__slides').style.left = right;
}
Secondly, I'd like to have an active carousel-item, which when active automatically changes the background Image.
Right now I have the hero.style.background = var; and I've got it changing onclick with onclick = function('01.jpg') on each carousel item.
Here's the code.
// Change Hero Img
function heroChange(hmmm) {
var hero = document.querySelector('.hero');
hero.style.background = hmmm;
}
So I guess I would add EventListeners to the carousel-items and add an active class to the carousel-item like so,
var slides = document.querySelectorAll('.carousel-items');
function changeBgImg() {
slides.forEach(s => s.classList.remove('active');
this.classList.add('active');
//change the bg image === this
//But I have no idea how to do that
}
Thirdly I've got the content, background and carousel indicators using the same functions above but it seems like really dirty code. The HTML has each .carousel-item, there are ten of them, calling 4 functions each. It looks like this:
<div class="glide hero-carousel">
<div class="glide__track" data-glide-el="track">
<ul class="glide__slides">
<li class="glide__slide carousel-item"
onclick="heroChange('url(images/02.jpg) bottom/cover no-repeat');
number('01');
h4('Destination Shire');
h1('Valley<br> of Dreams');">
<div class="carousel-text">
<p>Destination Shire</p>
<h3>Valley<br> of Dreams</h3>
</div>
</li>
<li class="glide__slide carousel-item"
onclick="heroChange('url(images/03.jpg) bottom/cover no-repeat');
number('02');
h4('Destination Westwood');
h1('Misty<br> Woodlands');">
<div class="carousel-text">
<p>Destination Westwood</p>
<h3>Misty<br> Woodlands</h3>
</div>
</li>
</ul>
</div>
</div>
So it looks pretty yucky. It works though, but I would love to find a more elegant way of achieving this by putting all of these functions into one function that does each part in sequence.
Lastly, I'd want to get transition on-click animations going but that's another kettle of fish entirely.
So that's it. Whew!
Thanks for taking the time guys, I appreciate it. Any help you can provide is going to make me a better designer. There are actually a bunch of projects I have will benefit from the answers.
If you can provide help with at least Part 2 & 3: cleaning up the code into 1 function and getting the bg-image changing on the active class that would be a big big help.
There's just so much that JS can do and I'm not finding the answers on Google and youTube.
Thank you again.
An Update:
I have edited the slider by by using margin-left as shown by this question:
vanilla javascript carousel not sliding
// var & event-listener buttons
document.querySelector(".left").addEventListener("click", slideLeft);
document.querySelector(".right").addEventListener("click", slideRight);
let marginLeft = 0;
const slides = document.querySelector('.glide__slides');
// Function slide left
function slideLeft() {
marginLeft += 264;
slides.style.marginLeft = marginLeft + 'px';
console.log(getComputedStyle(slides).marginLeft);
}
// Function slide Right
function slideRight() {
marginLeft -= 264;
slides.style.marginLeft = marginLeft + 'px';
console.log(getComputedStyle(slides).marginLeft);
}
This has now got the carousel moving manually 1 slide at a time.
Still not fully understanding why my previous code above didn't work. If anyone can explain that to me that would be great.
I'm still left with some issues:
Autosliding and looping at the end of the slides.
Having the active slider change the background automatically. At this point it only changes onclick.
Finding a way to tidy up the function calls and functions.
The question asks for various ideas on how to simplify code and how to use native JavaScript to create a slider that rolls continuously.
The code originally used glider and it may be something simpler would be sufficient to get the desired result, for example using animationend event to change the background when a slide gets to the left hand side. However, eating the elephant slowly I'll tackle the yucky code (part 3) first.
Although the HTML looks rather daunting, 4 calls on a click for every li element for example, it is currently what is required so let's investigate creating it at run time. This gives us more easily maintainable code. For example, if we want to remove a slide, or alter the order of slides or add one we can just alter the slider array defined below and JavaScript will do the rest.
Part 1 of the question asked about sliding. We slide the whole ul element using CSS animation defined something like this, where 33vw is the total width of a slide (inc. margins/padding)
#keyframes sliding0 {
0% { left: 0; }
30% { left: 0; }
100% { left: -33vw; }
}
and we add an event listener to the element to trap animationend events because when the ul has slid one slide's width we want to change the hero image, and we want to put the slide that has just disappeared onto the back of the infinie sliding will work. We then set the animation running again.
See the snippet for details on how this and other events are dealt with. It also shows how the changeHero function can work which was part 2 of the question. Note, the snippet works more or less in the SO environment, though occasionally hover action is partially ignored. Running the code on your own machine it should be fine though.
<!DOCTYPE html>
<html>
<head>
<style>
#keyframes sliding0 {
0% { left: 0; }
30% { left: 0; }
100% { left: -33vw; }
}
#keyframes sliding1 {
0% { left: 0; }
30% { left: 0; }
100% { left: -33vw; }
}
body {
background-repeat: no-repeat no-repeat;
background-size: cover;
background-position: center center;
}
div .glide_track {
position: relative;
width: 100vw;
overflow-x: hidden;
}
ul {
position:relative;
left: 0;
width: 330vw;
height:100vh;
animation-name: sliding0;
animation-duration: 3s;
animation-delay: 0s;
animation-iteration-count: 1;
animation-timing-function: linear;
margin: 0;
padding: 0;
list-style-type: none;
}
li {
position: relative;
left:0;
top:0;
float:left;
width: 32vw;
height:30vw;
display: inline-block;
margin: 0;
margin-right: 1vw;
padding: 0;
background-size: cover;
background-repeat: no-repeat no-repeat;
background-position: center center;
}
</style>
</head>
<body>
<script>
// we put the two lots of text and the image url for each slide in an array in the order they are to be shown
// this makes it easier to maintain when you want to add or remove a slide or change their order
// we only have one slider at the moment but this makes it more general
// these are the offsets in the array describing a slide. Done as indexes rather than named as easier to set up sliders array
const img = 0;
const text1 = 1;
const text2 = 2;
const sliders = [
[
['https://ahweb.org.uk/boxfordmosaic.jpg','Shire','Valley<br> of Dreams'],
['https://ahweb.org.uk/gear-in-turbine-house-reading.jpg','Westwood','Misty Woodlands'],
['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams'],
['https://ahweb.org.uk/boxfordmosaic.jpg','Shire','Valley<br> of Dreams'],
['https://ahweb.org.uk/gear-in-turbine-house-reading.jpg','Westwood','Misty Woodlands'],
['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams'],
['https://ahweb.org.uk/boxfordmosaic.jpg','Shire','Valley<br> of Dreams'],
['https://ahweb.org.uk/gear-in-turbine-house-reading.jpg','Westwood','Misty Woodlands'],
['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams'],
['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams']
]
];
// go through each slider and create its outer divs and its ul element
sliders.forEach(createSlider);
function createSlider(slider,sliderno) {
const div1 = document.createElement('DIV');
const div2 = document.createElement('DIV');
const ul = document.createElement('UL');
div1.classList.add("glide","hero-carousel");
div2.classList.add("glide_track");
div2.setAttribute("data-glide-el","track");
div1.appendChild(div2);
div2.appendChild(ul);
document.body.appendChild(div1);
ul.classList.add("glide__slides");
ul.addEventListener("animationend", animationEnd);
slider.forEach(createLi);
function createLi(slide,slideNo) {
const li = document.createElement('LI');
li.classList.add("glide__slide","carousel-item");
li.style.backgroundImage='url('+slide[img]+')';
li.addEventListener("click",slideClicked);
li.addEventListener("mouseover",slideHovered);
li.addEventListener("mouseout",slideUnhovered);
li.setAttribute('data-slideno','0' + slideNo);//! needs generalising if you have >10 slides !
ul.appendChild(li);
const div = document.createElement('DIV');
const p = document.createElement('P');
const h3 = document.createElement('H3');
p.innerHTML = slide[text1];
div.appendChild(p);
h3.innerHTML = slide[text2];
div.appendChild(h3);
li.appendChild(div);
}
}
// this is for testing, in real version use whatever required (i.e. whichever element is to have the hero image)
function ahHeroChange(backgroundImage) {
document.body.style.background = backgroundImage + " bottom/cover no-repeat";
}
function slideClicked(event) {
var slide = event.target;
var slideNo = slide.getAttribute('data-slideno');
// make the hero image the same as the slide's
ahHeroChange(slide.style.backgroundImage);
/* I don't know what these functions do - they were executed in the original on a click
number(slideno);
h4(slide.firstElementChild.querySelector('p').innerHTML);// text1 of the slide is passed to h4
h1(slide.firstElementChild.querySelector('h3').innerHTML;// text2 of the slide is passed to h1
*/
}
function slideHovered(event) {
var slide = event.target;
var slider = slide.parentElement;
slider.style.animationPlayState = 'paused';
ahHeroChange(slide.style.backgroundImage);
}
function slideUnhovered(event) {
var slide = event.target;
var slider = slide.parentElement;
//restore the hero image to the first one in the slider
ahHeroChange(slider.firstElementChild.style.backgroundImage);
//get the animation running again
slider.style.animationPlayState = 'running';
}
function animationEnd(event) {
//find the element that was clicked (it will be a ul element representing a slider)
var slider = event.target;
//take the first slide off the list and put it back at the end
slider.append(this.firstElementChild);
//change the hero image to the slide which is now the leftmost - use modified heroChange in the final version
document.body.style.backgroundImage = this.firstElementChild.style.backgroundImage;
// toggle the animationName (to an identical keyframes action) to force the animation to start again
slider.style.animationName='sliding'+(Number(event.animationName.replace('sliding',''))+1)%2;
}
</script>
</body>
</html>
I have 2 divs on my webpage. first div is "#pattern" (red one), and second on is "#projets".(blue one)
when use scrolls for the first time, the window scrolls automaticaly to the the second div "#projets". I'm using jquery scroll-To plugin.
it works nice, even if when the users scroll with a large amount of scroll there could be on offset from the "#projets" div... If someone has an idea to correct this would be nice, but that's not my main trouble...
Now i'm trying to scroll back to the top of the page ("#pattern" div) as soon as "#pattern" div reappears when scrolling, the red one. so basically it should be as soon as the offset from the top of my screen of my div "#projets" is supperior to 1.
I've tried so many solutions without results, using flags, multiple conditions... it can be the same kind of thing as on this page, but user should be abble to scroll freely inside the page, not scrolling from hash to hash :
http://www.thepetedesign.com/demos/onepage_scroll_demo.html
here is my html :
<div id="pattern"></div>
<div id="projets"></div>
my css :
#pattern {
height:300px;
width: 100%;
background-color:red
}
#projets {
height:800px;
width: 100%;
background-color:blue
}
and my jquery :
var flag=0 ;
$(window).on('scroll',function(){
var top_projets_position = $("#projets").offset().top - $(window).scrollTop();
if((flag==0) && $(window).scrollTop()>1){
$(window).scrollTo('#projets', 500);
flag=1;
}
if($(window).scrollTop()==0){
flag=0;
}
});
here is jsfiddle :
http://jsfiddle.net/jdf9q0sv/
hope someone can help me with this, I can't figure out what I'm doing wrong, maybe a wrong method ! thanks
It looks like you need to track 3 things:
The scroll direction occurs.
The area you are currently viewing.
If scroll animation is currently happening (we need to wait until it's done, or problems will occur).
http://jsfiddle.net/vx69t5Lt/
var prev_scroll = 0; // <-- to determine direction of scrolling
var current_view ="#pattern"; // <-- to determine what element we are viewing
var allowed = true; // <-- to prevent scrolling confusion during animation
var top_projets_position = $("#projets").offset().top + 1;
$(window).on('scroll',function(){
var current_scroll = $(window).scrollTop();
if(current_scroll < top_projets_position && current_view=="#projets" && current_scroll < prev_scroll){
scrollToTarget("#pattern");
}
if($(window).height() + current_scroll > top_projets_position && current_view=="#pattern" && current_scroll > prev_scroll){
scrollToTarget("#projets");
}
prev_scroll = current_scroll;
});
function scrollToTarget(selector){
if(allowed){
allowed = false;
$(window).scrollTo(selector, {
'duration':500,
'onAfter': function(){ allowed = true; current_view = selector;}
});
}
}
This is just a quick solution based on your original code. A better solution would be to do something more Object Oriented (OOP) and track values in an object. Perhaps take an array of elements on object creation, grab all the boundaries and use the boundaries in your scroll handler to determine when to scroll to the next div.
I want to create a website with background images that change over time with a fade in/fade out effect, but I don't want to use the existing jQuery fade in/fade out effect because with when one image faded out, a white background appeared before other image faded in. I found a plugin named Maximage that suits my request but it uses img tags while I want to work with background-image CSS (I have a good reason for doing this). Does anyone know how to do this?
Here's my HTML code:
<div id="wrapper">
//My contain here
</div>
Here's my JavaScript code so far:
//Auto change Background Image over time
$(window).load(function() {
var images = ['img/top/bg-1.jpg','img/top/bg-2.jpg','img/top/bg-3.jpg'];
var i = 0;
function changeBackground() {
$('#wrapper').fadeOut(500, function(){
$('#wrapper').css('background-image', function () {
if (i >= images.length) {
i = 0;
}
return 'url(' + images[i++] + ')';
});
$('#wrapper').fadeIn(500);
})
}
changeBackground();
setInterval(changeBackground, 3000);
});
Example: http://www.aaronvanderzwan.com/maximage/examples/basic.html
AHH ! Finally ! I found a nice technique ! I'm using a double wrapper.
The problem in your code is a bit logical. You can't fadeOut and fadeIn at the same time a single wrapper.
So the idea is to create two wrapper and to switch between them back and forth. We have one wrapper called: "wrapper_top" that encapsulate the second wrapper called: "wrapper_bottom". And the magic was to put beside the second wrapper: your content.
Thus having the structure ready which is the following:
<div id='wrapper_top'>
<div id='content'>YOUR CONTENT</div>
<div id='wrapper_bottom'></div>
</div>
Then a bit of JS+CSS and voilĂ ! It will be dynamic with any amount of images !!!
Here is the implementation: http://jsbin.com/wisofeqetu/1/
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function() {
var i =0;
var images = ['image2.png','image3.png','image1.png'];
var image = $('#slideit');
//Initial Background image setup
image.css('background-image', 'url(image1.png)');
//Change image at regular intervals
setInterval(function(){
image.fadeOut(1000, function () {
image.css('background-image', 'url(' + images [i++] +')');
image.fadeIn(1000);
});
if(i == images.length)
i = 0;
}, 5000);
});
</script>
</head>
<body>
<div id="slideit" style="width:700px;height:391px;">
</div>
</body>
</html>
If it doesn't have to be background-image, you can place all the images in your #wrapper, in <img>, it will work like a charm:
<div id="wrapper">
<img src="firstImage" class="imageClass"></img>
<img src="secoundImage" class="imageClass"></img>
<img src="thirdImage" class="imageClass"></img>
</div>
then some style. Every image has to be in same spot, so add position relative to #wrapper, and position absolute to .imageClass:
#wrapper{
position: relative;
}
.imageClass{
position: absolute;
top: 0;
left: 0;
display: none;
}
display: none; will hide every image.
Now some JQuery. To appear first image when window load write this:
$(window).load(function() {
$('.imageClass').eq(0).show();
});
by the .eq() "command" you can specify which one element with class '.imageClass' you want to use exactly. Starts with 0. After that just do something like that:
function changeBackground() {
var current = 0;
//tells which image is currently shown
if(current<$('.imageClass').length){
//loop that will show first image again after it will show the last one
$('.imageClass').eq(current).fadeOut(500);
current++;
$('.imageClass').eq(current).fadeIn(500);
} else {
$('.imageClass').eq(current).fadeOut(500);
current=0;
$('.imageClass').eq(current).fadeIn(500);
}
}
changeBackground();
setInterval(changeBackground, 3000);
});
That should work, hope you will like it.
You may also use jQuery plugin backstretch.
I have an image map that I want to show a new div when I hove over the hotspots. It starts with a default listing of text but once I mouseover the hotspots, I want that to change out to the corresponding div's. I'm using the following code and am getting no joy:
$(".office-default").mouseover(function () {
var elementId = "#office-" + $(this).attr("id").split("-")[1];
$(elementId).removeClass("hidden");
});
$(".office-default").mouseout(function () {
var elementId = "#office-" + $(this).attr("id").split("-")[1];
$(elementId).addClass("hidden");
});
Here's the entire code:
http://jsfiddle.net/leadbellydesign/jR6pa/1/
I've done tons of searches and have come up with nothing helpful. I don't want to change images, I just want to show div's.
You still need to fix the space below the divs, but this should work
DEMO
$("area").hover(function () {
$office = $(this).attr("href");
$(".office-default > div").addClass("hidden");
$($office).removeClass("hidden");
}, function(){
$(".office-default > div").addClass("hidden");
$("#office-1").removeClass("hidden");
});
UPDATE
To fix the spacing issue, update your .office-default CSS:
DEMO
.office-default {
background:#444;
padding:5px 15px 0;
width: 80%;
height:150px;
}
I'm working on a website for a family friend. On it they wanted to have logos from all their associates on one row, that subtly fade to get replaced with additional logos that didn't fit the first time.
To achieve this i've assigned the <img>'s classes, that represent what cycle they should appear in, depending on how many of those images will fit on the row given its current width. This happens in my assignCycleNumbers function.
Then to actually fade them in and out i have another function called cycleAssociates which recursively fades the appropriate classes in and out. Well in theory, however it doesn't seem to be working properly, which is particularly odd because i tested the function here and it works fine. The only difference between them is that now i'm trying to assign the cycle numbers dynamically.
I'm really stumped and could do with some help!
You can see the website hosted here and if you scroll down to the bottom of the content you'll see the logos at the bottom, not behaving as expected. (First cycle appears okay but then subsequent cycles get muddled, more observable if you resize to a smaller screen width).
You can inspect the code thoroughly through your browser but here's everything you need to know, again i'd really appreciate any insight.
EDIT: The whole javascript file as requested. But all the relevant stuff is below:
JS:
//single global variable to represent how many logo cycles there is
var totalCycles = 0;
...
$(window).load(function() {
...
totalCycles = assignCycleNumbers();
cycleAssociates();
});
// window is resized
$(function(){
$(window).resize(function() {
...
totalCycles = assignCycleNumbers();
});
});
...
function cycleAssociates(){
var cycle = 0;
var recursiveCycling = function(cycle, totalCycles){
var currentAssociate = ".cycle" + cycle;
//fade in all img with the current cyle class over a second,
//wait 3 seconds before fading out over a second.
$(currentAssociate).delay(100).fadeIn(1000).delay(3000).fadeOut(1000,
function(){
cycle++;
if(cycle > totalCycles){
cycle = 0;
}
recursiveCycling(cycle, totalCycles);
});
};
recursiveCycling(cycle, totalCycles);
}
function assignCycleNumbers(){
//first remove any old cycle# classes (resized window case)
$('[class*="cycle"]').removeClass( function(unusedIdx,c){
return c.match(/cycle\d+/g).join(" ");
});
//measure div width
var divSpace = $("#bodies").innerWidth();
//assign a cycle number to a number of logos until no more will fit in that div
var cycleNum = 0;
$(".associate").each(function(){
if( divSpace - $(this).width() > 0){
$(this).addClass("cycle" + cycleNum);
divSpace = divSpace - $(this).width();
}
else{ //next logo won't fit current cycle, create next cycle
cycleNum++
$(this).addClass("cycle" + cycleNum);
divSpace = $("#bodies").innerWidth() - $(this).width();
}
});
return cycleNum;
}
html:
<img class="associate" src="IMG/spare.png" alt=""/>
<img class="associate" src="IMG/bcs_professional.jpg" alt="BCS Professional Member"/>
<img class="associate" src="IMG/climate_savers.jpg" alt="Climate Savers Smart Computing"/>
<img class="associate" src="IMG/code_of_conduct.jpg" alt="Data Centres Code Of Conduct Endorser"/>
<img class="associate" src="IMG/spare.gif" alt=""/>
<img class="associate" src="IMG/enistic.gif" alt="Enistic"/>
<img class="associate" src="IMG/greentrac_authorised.png" alt="Greentrac Authorised Reseller"/>
<img class="associate" src="IMG/very_pc.jpg" alt="Very PC Approved"/>
<img class="associate" src="IMG/spare.jpg" alt=""/>
css:
#bodies img.associate{
float: left;
max-width: 120px;
max-height: 80px;
display:none;
}
The issue is that your fadeOut function's callback is being executed even before all elements in the current cycle are faded out. Here's a modified version of your function that works as expected:
function cycleAssociates(){
var cycle = 0;
var recursiveCycling = function(cycle, totalCycles){
var currentAssociate = ".cycle" + cycle;
var n = $(currentAssociate).length; //How many images in current cycle?
$(currentAssociate).each(function() {
$(this).delay(100).fadeIn(1000).delay(3000).fadeOut(1000, function() {
n --;
if(n <= 0) { //current cycle done?
cycle++;
if(cycle > totalCycles){
cycle = 0;
}
recursiveCycling(cycle, totalCycles);
}
});
});
};
recursiveCycling(cycle, totalCycles);
}
To fix the issues that come up on window resize, try replacing your current $(window).resize handler with this:
$(function(){
$(window).resize(function() {
parallelNavbar();
$(".associate").stop(); //if there are any animations, stop 'em
$(".associate").hide(); //hide all associates
totalCycles = assignCycleNumbers(); //update the assignment
cycleAssociates(); //let's get cyclin' again!
});
});
Although I think you have some issues with scrolling. This should resolve the main cycling problem, though -- so I hope that helped!