I'm creating a slider with jquery. I've looked on line if I could use any of the already made plugins, but none could do what I need to.
On a site I'm working on, I have a 1260px container where the content is.
The slider is fullwidth, and in the center is the active slide, and on the sides are previous and next slides that should serve as a previous and next click.
I plan to expand on that slider so that I have thumbnails beneath it, but for now I need to make the slider working.
HTML is (the images are 1260x520px)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Fullwidth Slider</title>
<link rel="stylesheet" href="style.css" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="init.js"></script>
</head>
<body>
<div class="slider clearfix" data-autoplay="0" data-items="1" data-easing="linear" data-duration="750" data-height="520">
<div class=" single_slide" style="height: 520px; background-image: url('image.jpg'); background-size: cover; background-position: 0% 0%; background-repeat: no-repeat;">
<div class="slider_text">
</div>
</div>
<div class="single_slide active" style="height: 520px; background-image: url('image.jpg'); background-size: cover; background-position: 0% 0%; background-repeat: no-repeat;">
<div class="slider_text">
</div>
</div>
<div class=" single_slide" style="height: 520px; background-image: url('image.jpg'); background-size: cover; background-position: 0% 0%; background-repeat: no-repeat;">
<div class="slider_text">
</div>
</div>
<div class=" single_slide" style="height: 520px; background-image: url('image.jpg'); background-size: cover; background-position: 0% 0%; background-repeat: no-repeat;">
<div class="slider_text">
</div>
</div>
<div class=" single_slide" style="height: 520px; background-image: url('image.jpg'); background-size: cover; background-position: 0% 0%; background-repeat: no-repeat;">
<div class="slider_text">
</div>
</div>
</div>
</body>
</html>
Style css is:
/***************** Image Slider ****************/
.slider{
list-style: none;
display: block;
width: 100%;
overflow: hidden;
position: relative;
}
.slider .single_slide{
float: left;
display: block;
margin: 0;
padding: 0;
border-radius: 0px;
overflow: hidden;
opacity: 0.15;
width: 1260px;
cursor: pointer;
-webkit-transition: opacity 800ms ease-in-out;
transition: opacity 800ms ease-in-out;
}
.slider .single_slide.active{
opacity: 1;
cursor: default;
-webkit-transition: opacity 800ms ease-in-out;
transition: opacity 800ms ease-in-out;
}
jQuery code:
jQuery(document).ready(function($) {
$('.slider').each(function () {
var $slider = $(this);
var autoplay = $slider.data("autoplay");
var items = $slider.data("items");
var easing = $slider.data("easing");
var duration = $slider.data("duration");
var $single_slide = $slider.find('.single_slide');
var slider_height = $single_slide.css('height', $slider.data('height')+'px');
var left_offset = ($(window).width()-1260)/2;
$slider.css({'width' : $single_slide.length*1260+'px', 'left':- 1260+left_offset + 'px'});
$single_slide.eq(1).addClass('active');
var $prev = $('.active').prev();
var $next = $('.active').next();
function moveLeft() {
var $a = $('.active');
$a.removeClass('active').prev().addClass('active');
$slider.animate({
left: parseInt($slider.css('left'), 10) + $single_slide.outerWidth(true),
easing: easing,
step: items,
}, duration, function () {
$('.single_slide:first').before($('single_slide:last'));
});
}
function moveRight() {
var $a = $('.active');
$a.removeClass('active').next().addClass('active');
$slider.animate({
left: parseInt($slider.css('left'), 10) - $single_slide.outerWidth(true),
easing: easing,
step: items,
}, duration, function () {
$('.single_slide:last').after($('single_slide:first'));
});
}
$prev.click(function () {
moveLeft();
});
$next.click(function () {
moveRight();
});
if (autoplay == 1) {
setInterval(function () {
moveRight();
}, duration);
}
});
});
I've created a git repository as well, so you can download the html files.
I'm originally doing this for wordpress, but the workings is the same.
The problem is that it doesn't seem like the appending of the images once you click previous or next images works. Switching of the classes works, but the next and previous images are not changing when you click on them (I've done something similar but the prev/next buttons were fixed elements, so I could just target them all the time, but here they are changing)-
I think I got to the root of the issue with the previous and next selectors. They got cached once as a variable but were never updated when the active class changes to another slide - so the event listeners would stick to the elements that were initially set as siblings of the active slide :
var $prev = $('.active').prev();
var $next = $('.active').next();
Unfortunately this doesn't seem to work :
$('.active').prev().click(function() { ... });
But this almost does the trick :
$('.slider').find($('.single_slide').eq($('.active').index()+2)).click(function() {
moveLeft();
});
$('.slider').find($('.single_slide').eq($('.active').index()-1)).click(function() {
moveRight();
});
Update - made functional and infinite with the .detach() method and a delegated event listener :
http://codepen.io/anon/pen/aOoPgZ?editors=001
$('.slider').each(function() {
var slider = $(this);
var autoplay = slider.data('autoplay');
var items = slider.data('items');
var easing = slider.data('easing');
var duration = slider.data('duration');
var single_slide = slider.find('.single_slide');
var slider_height = single_slide.css('height', slider.data('height'));
var offset = ($(window).width()-1260)/2-1260;
$.each(single_slide, function(index) {
if (index == 0) $(this).addClass('img' + single_slide.length);
else $(this).addClass('img' + index);
});
slider.css({'width': single_slide.length*1260, 'left': offset});
single_slide
.eq(0).addClass('prev').end()
.eq(1).addClass('active').end()
.eq(2).addClass('next');
function moveLeft() {
$('.active').removeClass('active').prev().addClass('active');
slider.animate({
left: slider.position().left+single_slide.outerWidth(true),
easing: easing,
step: items
}, duration, function() {
$('.single_slide:last').detach().prependTo(slider);
slider.css('left', offset);
newNav();
});
}
function moveRight() {
$('.active').removeClass('active').next().addClass('active');
slider.animate({
left: slider.position().left-single_slide.outerWidth(true),
easing: easing,
step: items
}, duration, function() {
$('.single_slide:first').detach().appendTo(slider);
slider.css('left', offset);
newNav();
});
}
function newNav() {
$('.prev').removeClass('prev');
$('.next').removeClass('next');
$('.single_slide')
.eq(0).addClass('prev').end()
.eq(2).addClass('next');
}
$(document).on('click', '.prev', function() {
moveLeft();
});
$(document).on('click', '.next', function() {
moveRight();
});
if (autoplay == 1) {
setInterval(function() {
moveRight();
}, duration);
}
});
I'm sure there's room for some optimisation but it seems to do the trick. Has a feature to keep track of the images that may not be needed (but it's handy for debugging).
Now for some swipe support. :-D
Related
i'm trying to convert the background-image (css) into an object to change it's value but I couldn't find a solution.
At the moment there are 2 images in the script the first one is a circle loader script and the second one is a script that based of the value of the range it shows or hides part of the picture.
What i'm trying to do is to make load the picture inside the circle loader script.
For instance if the circle loader is 30/100 it should show only display 30% of the picture inside the circle vertically.
Here's the code:
Live version:
var bar = new ProgressBar.Circle(container, {
color: '#aaa',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 1,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: { color: '#aaa', width: 1 },
to: { color: '#333', width: 4 },
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value);
}
}
});
bar.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
bar.text.style.fontSize = '2rem';
bar.animate(1.0); // Number from 0.0 to 1.0
var sldH = document.getElementById('slider-h');
var sldV = document.getElementById('slider-v');
var img = document.getElementById("image");
// attach change handlers to the sliders
sldH.addEventListener('change', changeHandler);
sldV.addEventListener('change', changeHandler);
function changeHandler(e) {
var isHorizontal = e.srcElement.id == 'slider-h';
// get the sliders values
var valH = sldH.value;
var valV = sldV.value;
// calculate the percentage to pass an absolute length value
// to the clip property and determine the static value
var leftVal = calcPerc(img.width, valH);
var topVal = -1 * calcPerc(img.height, valV);
var clipVal = getClipVal(topVal, leftVal);
// set the images' right offset clip accordingly
img.style.clip = clipVal;
}
function calcPerc(range, val) {
return range / 100 * val;
}
function getClipVal(top, left) {
return 'rect(' + top + 'px, auto, auto, ' + left + 'px)';
}
#container {
margin: 20px;
top: 80px;
width: 200px;
height: 200px;
position: relative;
background-image: url("http://pngimg.com/uploads/bitcoin/bitcoin_PNG47.png");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.btc{
background-image: url("http://pngimg.com/uploads/bitcoin/bitcoin_PNG47.png");
background-repeat: no-repeat;
background-size: 100% 100%;
}
#slider-h,
#slider-v,
#image,
#underlay {
/* absolute positioning is mandatory for clipped elements (#image) */
position: absolute;
}
#slider-h,
#image,
#underlay {
width: 192px;
left: 100px;
}
#slider-h {
top: 50px;
left: 350px;
}
#slider-v {
top: 192px;
left: 200px;;
width: 207px;
-moz-transform: rotate(270deg);
-webkit-transform: rotate(270deg);
-o-transform: rotate(270deg);
-ms-transform: rotate(270deg);
transform: rotate(270deg);
}
#image,
#underlay {
top: 100px;
left: 350px;
height: 207px;
}
#image {
/* initial clip state */
}
#underlay {
/*background-color: #4C76A5;*/
}
<script src="https://rawgit.com/kimmobrunfeldt/progressbar.js/1.0.0/dist/progressbar.js"></script>
<link href="https://fonts.googleapis.com/css?family=Raleway:400,300,600,800,900" rel="stylesheet" type="text/css">
<div id="container" >
</div>
<input type="range" min="0" max="100" id="slider-h" value="0" />
<input type="range" min="-100" max="0" id="slider-v" value="0" />
<div id="underlay"></div>
<img src="http://pngimg.com/uploads/bitcoin/bitcoin_PNG47.png" id="image" />
I hope somebody can help! Thanks
I have a website, where I want to change between images in the background very smoothly. This is my actual javaScript-code for it:
var bg=[
'images/best.jpg',
'images/61182.jpg',
'images/bg.jpg'
];
$('._container-1').css('background-image','url('+bg[2]+')');
window.setInterval(
function(){
img=bg.shift();bg.push(img);
document.getElementsByClassName('_container-1')[0].style.backgroundImage='url('+img+')';
},
10000
);
Now, I want to change the images very slowly. I have tried a lot with jQuery-fadeIn/fadeOut-methods like this:
window.setInterval(
function(){
img=bg.shift();
bg.push(img);
$('._container-1').fadeOut(600, function() {
$('._container-1').css('background-image','url('+img+')');
$('._container-1').fadeIn(600);
});
},
17000
);
The problem is, that there are buttons and text in the container and they changes with the images. I want that the text and buttons are in the front all the time, only the background should fadeIn/fadeOut. My english is not perfect, I hope you understand my problem.
Can somebody help me please?
nina_berlini
I have uses 2 elements as background to achieve the effect. Also check demo on https://jsfiddle.net/n380u3cy/1/
HTML:
<div class="container">
<div class="background"></div>
<div class="background"></div>
<button>
Test button
</button>
</div>
CSS:
.container { position: relative; line-height: 100px; }
.container > .background,
.container > .background { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background-size: contain; z-index: 0; }
.container > *:not(.background) { position: relative; z-index: 1; }
Javascript:
var bg=[
'images/best.jpg',
'images/61182.jpg',
'images/bg.jpg'
];
var Transition = 1000;
$('.background').css('background-image','url('+bg[bg.length - 1]+')');
window.setInterval(
function() {
img=bg.shift();
bg.push(img);
var $Backgrounds = $('.background');
$Backgrounds.eq(1).hide(0).css({
'background-image': 'url('+img+')'
}).fadeIn(Transition * .9);
$Backgrounds.eq(0).show(0).fadeOut(Transition, function(){
$(this).show(0).css({
'background-image': 'url('+img+')'
});
$Backgrounds.eq(1).hide(0);
});
}, 2000
);
Make a wrapper and include both the background div and button div inside it with position absolute and the following CSS styles. This way you can control and animate the background separately from the buttons.
var bg = [
'https://placehold.it/1001x201',
'https://placehold.it/1002x202',
'https://placehold.it/1003x203'
];
$('._container-1').css('background-image', 'url(' + bg[2] + ')');
window.setInterval(
function() {
img = bg.shift();
bg.push(img);
document.getElementsByClassName('_container-1')[0].style.backgroundImage = 'url(' + img + ')';
},
10000
);
window.setInterval(
function() {
img = bg.shift();
bg.push(img);
$('._container-1').fadeOut(600, function() {
$('._container-1').css('background-image', 'url(' + img + ')');
$('._container-1').fadeIn(600);
});
},
17000
);
.wrapper {
position: relative;
width: 100%;
height: 200px;
}
._container-1 {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-size: cover;
background-position: top center;
}
.buttons {
position: absolute;
width: 100%;
text-align: center;
bottom: 0;
left: 0;
}
button {
background: red;
padding: 5px 10px;
border: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="_container-1"></div>
<div class="buttons">
<button type="button">
Button 1
</button>
<button type="button">
Button 2
</button>
</div>
</div>
thank you for your great solution. I am not well familiar with jQuery and have a question about your code:
$Backgrounds.eq(1).hide(0).css({
'background-image': 'url('+img+')'
}).fadeIn(Transition * .9);
means it that the second "background-div" first hides, then get a new background-image and after that it ist fadeIn? And means hide(0) that it immediately hides?
nina_berlini
Each of these 3 divs travels 500px over 6000ms. After 4000ms, I want:
the red div to fade out over its last 2000ms
the green dive to fade in over 2000ms
the green div to start its journey of 500px
all simultaneously.
Then, after 8000ms, when the green div is 4000ms into its journey, I want:
the green div to fade out over its last 2000ms
the yellow dive to fade in over 2000ms
the yellow div to start its journey of 500px
all simultaneously.
Then, at 12000ms, when the yellow div is 4000ms into its journey, I want it to fade out over its last 2000ms of its journey.
It's about having total control with overlapping animations. I tried queue() and dequeue(), queue: false, setTimeout... I can't make heads or tails of it. How do I do this?
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<style>
div {
width:50px;
height:50px;
position:absolute;
left:0;
}
#div1 {background:red;top:0;}
#div2 {background:green;top:55px;}
#div3 {background:yellow;top:110px;}
</style>
</head>
<body>
<script>
$(document).ready(function(){
$("#div1").animate({left: "500px"}, 6000);
$("#div2").delay(4000).animate({left: "500px"}, 6000);
$("#div3").delay(8000).animate({left: "500px"}, 6000);
});
</script>
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
</body>
</html>
You can use css transition and start , step options of .animate()
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<style>
div {
width: 50px;
height: 50px;
position: absolute;
left: 0;
transition: opacity 2.5s ease;
}
#div1 {
background: red;
top: 0;
}
#div2 {
background: green;
top: 55px;
opacity:0;
}
#div3 {
background: yellow;
top: 110px;
opacity:0;
}
</style>
</head>
<body>
<script>
$(document).ready(function() {
function step(now, fx) {
var n = Math.round(now)
if (n === 250 || n === 251) {
$(this).css("opacity", 0)
}
}
function start() {
$(this).css("opacity", 1)
}
$("#div1").animate({
left: "500px"
}, {
duration: 6000,
step:step
});
$("#div2").delay(4000).animate({
left: "500px"
}, {
duration: 6000,
start:start,
step:step
});
$("#div3").delay(8000).animate({
left: "500px"
}, {
duration: 6000,
start:start,
step:step
});
});
</script>
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
</body>
</html>
Is this what you are trying to implement?
idArray = ['div1', 'div2', 'div3', 'div4'];
div = {};
//Create a flag for every item in list.
$(idArray).each(function(i, val) {
div['Action' + i] = false;
});
duration = 6000; //duration of each animation
overlap = 4000; //the time when overlap happens
fadeAt = 2000; //speed at which element appear/disappear
iLikeToMoveIt(0); //initialize animation
function iLikeToMoveIt(i) {
$now = $("#" + idArray[i]); //animation element
$next = $("#" + idArray[++i]); //next element
$now.fadeIn(fadeAt).animate({
left: "500px"
}, {
duration: 6000,
queue: false,
progress: function(animation, progress, remainingMs) {
//check if flag is not set
if (!div['Action' + i] && remainingMs < fadeAt) {
//set the flag
div['Action' + i] = true;
$(this).fadeOut(fadeAt);
if ($next.length) {
//call function for next div
iLikeToMoveIt(i);
}
}
}
});
}
div {
width: 50px;
height: 50px;
position: absolute;
left: 0;
}
.hide {
display: none;
}
#div1 {
background: red;
top: 0;
}
#div2 {
background: green;
top: 55px;
}
#div3 {
background: yellow;
top: 110px;
}
#div4 {
background: blue;
top: 165px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="div1"></div>
<div id="div2" class="hide"></div>
<div id="div3" class="hide"></div>
<div id="div4" class="hide"></div>
Can anyone explain why this 3D works OK when you visit the page but disintegrates when you switch to another tab and then revert to the page?
But then...
... it disappears into the screen!
HTML:
<html>
<head>
<link href="styles/styles.css" rel="stylesheet" />
</head>
<body style='background-color: white; width: 900px;'>
<div style='margin: 50px auto;'>
<div id="img" style="background-image: url('img1.jpg'); width: 850px; height: 520px" />
</div>
<script src="js/libs/jquery/jquery-1.6.4.js" type="text/javascript"></script>
<script src="js/libs/jquery/jquery-slide-show-filter.js" type="text/javascript"></script>
</body>
</html>
CSS:
#container{
-webkit-perspective: 800;
width: 850px;
height: 520px;
}
#img, #s1 {
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
background-repeat: no-repeat;
}
#cube{
-webkit-transform-style: preserve-3d;
-webkit-transform: translateZ(-425px);
-webkit-backface-visibility: hidden;
width: 850px;
height: 520px;
}
#cube.enable
{
-webkit-animation: flash 0.75s ease-in-out;
-moz-animation: flash 0.75s ease-in-out;
-ms-animation: flash 0.75s ease-in-out;
-o-animation: flash 0.75s ease-in-out;
animation: flash 0.75s ease-in-out;
}
#-webkit-keyframes flash {
100% { -webkit-transform: translateZ(-425px) rotateY(90deg); }
}
Script:
var getImage = function(){
var images = ["img1.jpg", "img2.jpg", "img3.jpg"];
$.each(images, function( index, value ) {
$('<img />').attr('src', value);
});
index = 0;
return function(){
if (++index == images.length){
index = 0;
}
return images[index];
};
}();
setInterval(function(){
transform($('#img'), getImage());
}, 1000);
function transform(img, newImg){
img
.wrap('<div id="container"><div id="cube"></div>')
.css('-webkit-transform', 'translateZ(425px)');
img
.clone()
.attr('id', 's1')
.insertBefore(img)
.css('background-image', 'url("' + newImg + '")')
.css('position', 'absolute')
.css('-webkit-transform', 'rotateY(-90deg) translateZ(425px)');
PrefixedEvent($('#cube')[0], "AnimationEnd", function () {
img.unwrap().unwrap();
img.remove();
$('#s1')
.attr('id', 'img')
.css('-webkit-transform', '');
});
$('#cube').addClass('enable');
}
function PrefixedEvent(element, type, callback) {
var pfx = ["webkit", "moz", "MS", "o", ""];
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) type = type.toLowerCase();
element.addEventListener(pfx[p]+type, callback, false);
}
}
You can fix the issue by calling transform only while the window has focus:
(function() {
var inTab= false;
$(window).blur(function() {
inTab= false;
});
$(window).focus(function() {
inTab= true;
});
setInterval(function() {
if(inTab) {
transform($('#img'), getImage());
}
}, 1000);
})();
Fiddle
Click the image to simulate the window being focused. You can then switch between tabs, and the animation will no longer break.
I think its because if you switch tab the AnimationEnd event doesn't fire so there's no clean up.
Here's what I have currently:
HTML:
<div class="slides">
<div class="slide1-img">
</div>
</div>
jQuery:
$(function doAnimation(){
$('.slide1-img').delay(1000).fadeOut(500, function(){
for(n=1; n<=3; n++){
$(this).addClass('slide' + n + '-img').fadeIn(500).delay(1000).fadeOut(500)
};
});
});
CSS:
.slides {
width: 100%;
height: 300px;
overflow: hidden;
}
.slide1-img {
background: url(http://us.123rf.com/400wm/400/400/konradbak/konradbak1103/konradbak110300502/9188750-beautiful-lady-with-long-brown-hair.jpg) 0 0 no-repeat;
width: 100%;
height: 100%;
background-size: cover;
}
.slide2-img {
background: url(http://us.123rf.com/450wm/itrifonov/itrifonov1210/itrifonov121000202/15752531-closeup-portrait-of-a-beautiful-young-woman-with-elegant-long-shiny-hair--concept-hairstyle.jpg) 0 0 no-repeat;
width: 100%;
height: 100%;
background-size: cover;
}
.slide3-img {
background: url(http://us.123rf.com/450wm/subbotina/subbotina1307/subbotina130700109/20793602-beauty-woman-touching-her-long-and-healthy-brown-hair.jpg) 0 0 no-repeat;
width: 100%;
height: 100%;
background-size: cover;
}
It currently seems to add the slide2-img and slide3-img classes at the same time, rather than running through each one at a time. I want each of these to run one at a time (so each of the 3 images should fade in and out before the next one shows).
Also, I want this to loop infinitely, so the same 3 pictures will be in rotation.
You're probably trying to do something more like this
$(function() {
var i = 1;
(function doAnimation(){
$('.slide'+i+'-img').delay(1000).fadeOut(500, function(){
$(this).attr('class', 'slide' + (i = i==3 ? 1 : i+1) + '-img').fadeIn(500, doAnimation);
});
})();
});
FIDDLE
just iterating the class with a variable inside a recurring function.
You can do this with setInterval:
var i = 1;
var theImage = $(".slide1-img");
setInterval(function () {
console.log(theImage[0].className);
theImage.fadeOut(500, function () {
$(this).removeClass().addClass('slide' + i + '-img').fadeIn(500);
});
i++;
if (i === 4) {
i = 1;
}
}, 2000);
Fiddle