How to slide images in from the side using JavaScript? - javascript

I have a script that displays images sort of like a carousel. The images are placed in LIs and the left positioning is changed based on the width of each slide (all the same). Currently, the old slide just disappears then the new one appears.
I would like to make it so they slide in from the side and was wondering if someone could give me a basic example of how to do this using plain JavaScript (no jQuery!).
For example, I'm using the following code to update the left positioning of the containing UL. How can I make it so it will slide the selected image to the left or to the right (depending upon whether the next or previous button is clicked)
containingUL.style.left = '-' + (slideNumber * slideWidth) + 'px';

Here's a basic element slide function. You can play with the values of steps and timer to get the animation speed and smoothness just right.
function slideTo(el, left) {
var steps = 25;
var timer = 25;
var elLeft = parseInt(el.style.left) || 0;
var diff = left - elLeft;
var stepSize = diff / steps;
console.log(stepSize, ", ", steps);
function step() {
elLeft += stepSize;
el.style.left = elLeft + "px";
if (--steps) {
setTimeout(step, timer);
}
}
step();
}
So you could go:
slideTo(containingUL, -slideNumber * slideWidth);
Edit: Forgot to link to the JSFiddle
Edit: To slide to the left, provide a left value less than the current style.left. To slide to the right, provide a value greater than the current style.left. For you it shouldn't matter much. You should be able to plug it into your existing code. I'm guessing your current code either increments or decrements slideNumber and then sets style.left according to the slideNumber. Something like this should work:
if (nextButtonClicked) slideNumber++;
else slideNumber--;
slideTo(containingUL, -slideNumber * slideWidth);
I updated the JSFiddle with a working example of a sliding "gallery", including prev and next buttons. http://jsfiddle.net/gilly3/EuzAK/2/

Simple, non jQuery:
http://sandbox.scriptiny.com/contentslider/slider.html
http://www.webmonkey.com/2010/02/make_a_javascript_slideshow/
http://javascript.internet.com/miscellaneous/basic-slideshow.html

Related

Set div width based on scroll position

The code:
http://codepen.io/anon/pen/EjrpMM
So, i'm working on an interesting problem. I am working with a 2000px HTML document, that has a modal placed ontop of it.
The width of the div lightbox is 80%, and it's sitting positioned fixed.
The goal is, when scrolling down the page, to control the width of the div based on the scroll position. At the bottom of the page, it's only a third in size.
I've had trouble figuring out the proper equation or formula for this, and was seeking help.
Currently, I've been trying to look at the window.pageYOffset, to add 2.5% to the div while increasing, and minus 2.5% when scrolling back up, to bring it back to it's 80% width.
However, something isn't working right. I was seeing if the community had any ideas to help solve the problem.
I'm not using any frameworks for this.
Here's my javascript:
var lightBox = document.getElementById('lightBox'),
count = 80,
num = window.pageYOffset;
document.addEventListener('scroll', function(e) {
var offset = window.pageYOffset;
num >= offset ? count += 2.5 : count -= 2.5;
num = offset;
lightBox.style.width = count + '%';
});
View the code here, in this codepen
http://codepen.io/anon/pen/EjrpMM
Thank you!
You just have to change
+= 2.5 and -=2.5 to += 0.7 and -= 0.7
When I checked your code I did this and it worked.
Scroll event fired once on scroll independently on how much you've scrolled. E.g. if you've scrolled 1px scrollbar, or scrolled 100px using mousewheel scroll event will be fired once.
So if you need stable results you will need to calculate your div width depending on scroll position (window.pageYOffset).
Check this codepen fork. I've assumed that in the end of page div width should be 50%.
Core part is:
var lightBox = document.getElementById('lightBox');
var upperBound = 80;
var lowerBound = 50;
var tickValue = (upperBound - lowerBound) / window.innerHeight;
document.addEventListener('scroll', function(e) {
var offset = window.pageYOffset;
var count = upperBound - offset * tickValue;
lightBox.style.width = count + '%';
});
Important note: for crossbrowser way to get innerHeight you can check this answer
This is a simple equation. Let f : scroll |-> f(scroll) be the function that gives you the width of your div. You want f(0) = 0.8, f(2000)= 1/3.
Let's say you want the progression to be linear so f(scroll) = a*scroll + b, you can easily deduce that b = 0.8 and a = (1/3 - 0.8)/2000 = -0.000233. Now for any scroll value, you can find the width of your div.
Now you can change the values when you want, f(scroll) = (minWidth-maxWidth)/pageLength * scroll + maxWidth.

Scrolling content in a div when it's passed

Trying to accomplish something like on this website:
http://www.strangelove.nl/cases/kpmg-meijburg
The part where the responsive design is showcased, the image inside the devices start to scroll when a visitor scrolls past that point. I've tried to replicate it and I see a .js in the footer which is probably contributing. For now I have the css and html working on my test page.
Any help is gladly appreciated.
Strangelove is using their own Kubrick-js, which is available here: Kubrick-js
If you just want to have the 'images scrolling inside of frame while scrolling by'-effect, you can do it like this:
$(window).scroll(function() {
var animStart = 0, // the point where the animation starts
animEnd = 500, // the point, where the animation ends
scrollStartPos = 0, // the position your inside scrolling element starts
scrollEndPos = -300, // the position your inside scrolling element should end
winPosY = window.pageYOffset, // the scroll distance from top of document
scrollElement = $('.picture'); // the element to scroll
if(winPosY > animStart && winPosY < animEnd) {
// how far through the animation are we?
var howFar = (winPosY - animStart) / (animEnd - animStart),
scrollPos = Math.round(scrollStartPos + howFar * (scrollEndPos - scrollStartPos));
scrollElement.css('top', scrollPos + 'px');
$('.show-stats').html('How far: ' + howFar + '<br>scroll Position: ' + scrollPos);
}
});
Here is a fiddle for it: Fiddle
hope that helps.

Using a jquery slider for text instead of images?

This may be a little too specific, but I have a jquery slider that I am using <p> classes instead of images to cycle through customer quotes. Basically the problem I am running into right now is when it is static and non moving (JS code is commeneted out) they are aligned how I want them to be. As soon as the JS is un commented, they stretch out of view and you just see a white box?
Any ideas?
How I want each panel to look like:
jsfiddle
So I sort of made this my Friday project. I've changed a whole lot of your code, and added a vertical-align to the quotes and authors.
Here's the fiddle http://jsfiddle.net/qLca2fz4/49/
I added a whole lot of variables to the top of the script so you could less typing throughout.
$(document).ready(function () {
//rotation speed and timer
var speed = 5000;
var run = setInterval(rotate, speed);
var slides = $('.slide');
var container = $('#slides ul');
var elm = container.find(':first-child').prop("tagName");
var item_width = container.width();
var previous = 'prev'; //id of previous button
var next = 'next'; //id of next button
Since you used a % based width I'm setting the pixel widths of the elements in case the screen is reszed
slides.width(item_width); //set the slides to the correct pixel width
container.parent().width(item_width);
container.width(slides.length * item_width); //set the slides container to the correct total width
As you had, I'm rearranging the slides in the event the back button is pressed
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
I combined the prev and next click events into a single function. It checks for the ID of the element targeted in the click event, then runs the proper previous or next functions. If you reset the setInterval after the click event your browser has trouble stopping it on hover.
//if user clicked on prev button
$('#buttons a').click(function (e) {
//slide the item
if (container.is(':animated')) {
return false;
}
if (e.target.id == previous) {
container.stop().animate({
'left': 0
}, 1500, function () {
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
});
}
if (e.target.id == next) {
container.stop().animate({
'left': item_width * -2
}, 1500, function () {
container.find(elm + ':last').after(container.find(elm + ':first'));
resetSlides();
});
}
//cancel the link behavior
return false;
});
I've found mouseenter and mouseleave to be a little more reliable than hover.
//if mouse hover, pause the auto rotation, otherwise rotate it
container.parent().mouseenter(function () {
clearInterval(run);
}).mouseleave(function () {
run = setInterval(rotate, speed);
});
I broke this in to its own function because it gets called in a number of different places.
function resetSlides() {
//and adjust the container so current is in the frame
container.css({
'left': -1 * item_width
});
}
});
//a simple function to click next link
//a timer will call this function, and the rotation will begin :)
And here's your rotation timer.
function rotate() {
$('#next').click();
}
It took me a little bit, but I think I figured out a few things.
http://jsfiddle.net/qLca2fz4/28/
First off, your console was throwing a few errors: first, that rotate wasn't defined and that an arrow gif didn't exist. Arrow gif was probably something you have stored locally, but I changed the 'rotate' error by changing the strings in the code here to your actual variables.
So, from:
run = setInterval('rotate()', speed);
We get:
run = setInterval(rotate, speed);
(No () based on the examples here: http://www.w3schools.com/jsref/met_win_setinterval.asp)
But I think a more important question is why your text wasn't showing up at all. It's because of the logic found here:
$('#slides ul').css({'left' : left_value});
You even say that this is setting the default placement for the code. But it isn't..."left_vaule" is the amount that you've calculated to push left during a slide. So if you inspect the element, you can see how the whole UL is basically shifted one slide's worth too far left, unable to be seen. So we get rid of 'left_value', and replace it with 0.
$('#slides ul').css({'left' : 0});
Now, there's nothing really handling how the pictures slide in, so that part's still rough, but this should be enough to start on.
Let me know if I misunderstood anything, or if you have any questions.
So, a few things:
1) I believe you are trying to get all of the lis to be side-by-side, not arranged up and down. There are a few ways to do this. I'd just make the ul have a width of 300%, and then make the lis each take up a third of that:
#slides ul {
....
width: 300%;
}
#slides li {
width: calc(100% / 3);
height:250px;
float:left;
}
2) You got this right, but JSFiddle automatically wraps all your JS inside a $(document).ready() handler, and your function, rotate needs to be outside, in the normal DOM. Just change that JSFiddle setting from 'onload' to 'no wrap - in head'
3) Grabbing the CSS value of an element doesn't always work, especially when you're dealing with animating elements. You already know the width of the li elements with your item_width variable. I'd just use that and change your code:
var left_indent = parseInt($('#slides ul').css('left')) - item_width;
$('#slides ul').animate({'left' : left_indent}, 1500, function () {
to:
$('#slides ul').stop().animate({'left' : -item_width * 2}, 1500, function () {
4) Throw in the .stop() as seen in the above line. This prevents your animations from overlapping. An alternative, and perhaps cleaner way to do this, would be to simply return false at the beginning of your 'next' and 'prev' functions if #slides ul is being animated, like so:
if ($('#slides ul').is(':animated')) return false;
And I think that's everything. Here's the JSFiddle. Cheers!
EDIT:
Oh, and you may also want to clearInterval at the beginning of the next and prev functions and then reset it in the animation callback functions:
$('#prev').click(function() {
if ($('#slides ul').is(':animated')) return false;
clearInterval(run);
$('#slides ul').stop().animate({'left' : 0}, 1500,function(){
....
run = setInterval('rotate()', speed);
});
});

Image Rotation using pure Javascript

PLEASE DO NOT RECOMMEND JQUERY - I AM DOING THIS EXERCISE FOR LEARNING PURPOSES.
I have implemented a JavaScript, which rotates images (_elementSlideChange) on a timer, using a set interval of 10 seconds. Also I have added a slide functionality to this, which is 7 milliseconds (_slideImage).
The image rotates automatically every 10 seconds on page load, and I have also provided next and previous buttons, which allow the user to change the images manually.
_elementSlideChange: function () {
var myString;
var myText;
for (var i = 0; i < this._imgArray.length; i++) {
var imageArr = "url(" + this._imgArray[i].src + ")";
var imageBg = this._imageHolder.style.background + "";
if (imageArr == imageBg) {
if (i == (this._imgArray.length - 1)) {
myString = "url(" + this._imgArray[0].src + ")";
myText = this._infoArray[0];
} else {
myString = "url(" + this._imgArray[(i + 1)].src + ")";
myText = this._infoArray[i + 1];
}
}
}
this._imageNextSlide.style.background = myString;
this._imageNextSlide.style.background);
this._infoElement.innerHTML = myText;
this._myTimer = setInterval(MyProject.Utils.createDelegate(this._slideImage, this), 7);
},
_slideImage: function () {
if (parseInt(this._imageHolder.style.width) >= 0 && parseInt(this._imageNextSlide.style.width) <= 450) {
this._imageHolder.style.backgroundPosition = "right";
this._imageHolder.style.width = (parseInt(this._imageHolder.style.width) - 1) + 'px';
console.log(this._imageNextSlide.style.background);
this._imageNextSlide.style.width = (parseInt(this._imageNextSlide.style.width) + 1) + 'px';
} else {
console.log("reached 0px");
if (parseInt(this._imageHolder.style.width) == 0) {
this._imageHolder.style.background = this._imageNextSlide.style.background;
this._imageHolder.style.width = 450 + 'px';
this._imageHolder === this._imageNextSlide;
this._imageHolder.className = "orginalImage";
this._imageNextSlide.style.width = 0 + "px";
this._imageNextSlide = this._dummyImageNextSlide;
this._imagesElement.appendChild(this._imageHolder);
this._imagesElement.appendChild(this._imageNextSlide);
clearInterval(this._myTimer);
}
clearInterval(this._myTimer);
clearInterval(this._elementSlideChange);
}
}
So when the user clicks on the Next arrow button, the event listener for "click" is triggered. This creates a div for the current image on display, and creates a new div, which will contain the next image. The image slide and rotation works correctly (whether it's onLoad or onClick). The issue I have is if I click the Next button, while the new div image is sliding into position, it causes it to run into an infinite loop, so the same div with the image to be displayed keeps sliding in, and the more you click the Next button, the faster the image starts to rotate.
I have tried putting a clear interval for the image rotation and slider, but I do understand my code is wrong, which causes the infinite loop of the sliding image. And I know I am close to finishing the functionality.
Can anyone please advise where I could be going wrong? Or should I try to implement the sliding DIV in another way?
Once again please don't recommend jQuery.
And thank you for your help in advance.
Kush
To solve the issue, I did re-write the entire code, where I had a next and previous button event listener.
myProject.Utils.addHandler(this._nextImageElement, "click", myProject.Utils.createDelegate(this._changeImage, this));
Both the buttons will call the same function :
_changeImage: function (e)
In this function I check to see if the function is Transition (changing images),
I declare a boolean var forward = e.target == this._nextImageElement;
Then check to see the current index if forward ? Add 1 else minus 1
this._currentImageIndex += forward ? 1 : -1;
If its at the end of the Array and forward is true, assign the this._currentImageIndex to reset to 0 or Array.length – 1 if it’s in reverse
Then call another function which gives the ‘div’ a sliding effect. In this case call it this._transitionImage(forward);
In this function, set the this._inTranstion to true. (Because the div’s are sliding in this case).
The following code solved the issue i was having.
this._slideImageElement.style.backgroundImage = "url(\"" + this._imgArray[this._currentImageIndex].src + "\")";
this._slideImageElement.style.backgroundPosition = forward ? "left" : "right";
this._slideImageElement.style.left = forward ? "auto" : "0px";
this._slideImageElement.style.right = forward ? "0px" : "auto";
The above code is very important as the object is to place the “sliding in div” Left or Right of the current Visible “div” to the user, and this is mainly dependent on if the forward variable is true or false.
var i = 0;
Then start the transition by
setInterval( function() {
this._currentImageElement.style.backgroundPosition = (forward ? -1 : 1) * (i + 1) + "px";
this._slideImageElement.style.width = (i + 1) + "px";
Notice the forward will determine if the bgPosition will go to the left if its forward as we multiple by -1 or +1,
So for example
If the user clicks NEXT BUTTON,
Forward = true
So the first thing we do is set the
this._slideImageElement.style.backgroundPosition = "left"
Then
this._slideImageElement.style.left = "auto"
this._slideImageElement.style.right = "0px"
This means when the sliding image moves in its background position is LEFT but the div is placed on the RIGHT to 0px;
then this._currentImageElement.style.backgroundPosition = -1 * (i + 1)
Which moves the position of the currentImageElement to the left by 1px,
Increase the width of the slideImage which in this case is right of the current div,
and as the current div moves to the left the sliding image starts to appear from the right. (By default set the width of slideImageElement to 0px so the div exists but isn’t visible to the user). This gives it the slide effect of moving forward new image coming from the right.
this._slideImageElement.style.width = (i + 1) + "px";
then declare it to stop when it it’s the image width. In this case it will be 500px.
if ((i = i + 2) == 500) {
In this if statement reset the currentImageElement background and the background position “right” or “left” don’t really matter as long it has been reset.
Clear the interval
Set the transition to false again
Then call a setTimeout for the function changeImage, which will continue until the slide is completed.
The following shows the reset code as this is very important to prevent repeating the same image (This solved my entire issue)
// set the current image to the "new" current image and reset it's background position
this._currentImageElement.style.backgroundImage = "url(\"" + this._imgArray[this._currentImageIndex].src + "\")";
this._currentImageElement.style.backgroundPosition = "right";
// reset the slide image width
this._slideImageElement.style.width = "0px";
// clear the transition interval and mark as not in transition
clearInterval(this._transitionInterval);
this._inTransition = false;
// setup the next image timer
this._nextImageTimeout = setTimeout(myProject.Utils.createDelegate(this._changeImage, this), 2500);
}
I have provided a thorough detail because then it easier to understand the logic of the problem, and even if your not having the same issue, this may help you fingure out any problem.
I couldn't provide a JSfiddle, as i have created my CSS using Javascript, there are different ways of doing this, but i wanted to understand the logic behind the forward and reverse, and having a timer which continuously goes forward.
It seems like you want to cancel the animation on the slide (perhaps have it fade out while the next slide animates in, cancel its animation abruptly or let it finish and ignore the button click)
What I usually do, personally, is check for the animated state (yes, I use jquery, but you should be able to test the CSS or positioning values you are using to animate in the same way) you could even add an "active" class or data type during animation to make testing easier. Global flags work, too. If there is animation, ignore the button. (For my work... Depends on your intention)
Like I said, the problem may be with button behaviour not with the animation routine. It would be useful to see how you are calling this from the button click, and what your intended results are going to be.
How about CSS3 transitions?
transition: all 1s ease 0.5s;
Simple example on JS Fiddle.
This takes care of the animation, so you just need to set the intended destination using JavaScript, i.e.
this.style.left = '100px';
Or
this.style.top = '30px';
And CSS3 transitions will smoothly slide the element.
Cross Browser Note!
The transition property may need a vendor prefix for some browsers, I am using the latest production Firefox and you don't need -moz for that. Same goes for Opera, no '-o' required. Internet Exporer 10 needs no prefix. You may need to use -webkit for Safari / Chrome, but test without first.

How to make an image slider in javascript

I am implementing an image slider in javascript/jquery.
The demo should work like this.
http://londatiga.net/tutorials/scrollable/
Anyway I don't won't to rely on jquery.tools.min.js because this lib is out of date (the last update is about 8 months ago ).
I decide to make the js code by me.
When clicking on next or prev button I would like to shift the images on the list of one item/image.
The script shifts the items but the display is quite crappy, because the next items is not displayed.
The list is made of 4 images. At the beginning only the first two images are displayed, then when clicking on the next button I would like to display the second and the third image.
Actually the script shows just the first and the second image even if I click on the next button.
Here is the demo: http://jsfiddle.net/xRQBS/5/
Here is the code (1)
Any hints how should I fix it?
thanks
(1)
/*global jQuery */
(function ($) {
var imgs = [
'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSsarNmO4Vdo5QwHfznbyxPmOyiYQ-KmBKUFsgEirvjW6Kbm7tj8w',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRfIAfLXj3oK1lso1_0iQploSKsogfJFey3NnR0nSD9AfpWjU7egA',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR1dO4FVDDitdS85aLOCsOpQyHHTysDhD4kHQ749bMtNxaj5GMKnA',
'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcRAPO77sVu-Xk80S_txagySoTq8gKHgeiS63a9TYtKbPpGYVI5X'
];
var $list = $('.list-images');
var $slider = $('.slider');
var slideImage = function (direction) {
var unit = 150;
var left = parseInt($slider.attr('left'), 10) || 0;
left = (direction === 'prev') ? left - 150 : left + 150;
$slider.css('left', left + 'px');
};
$(function () {
$.each(imgs, function (i, img) {
$list.append($('<li>').append($('<img>').attr('src', img)));
});
$('body').on('click', '.direction', function () {
slideImage($(this).attr('data-tid'));
});
});
}(jQuery));
​
With the animate function:
$slider.animate({'left': left + 'px'}, 1000);
http://jsfiddle.net/xRQBS/6/
I'm assuming that you want the shift to be more of an animation. If so, take a look at jQuery's animate. Something like this:
$slider.animate({left: left + 'px'});
That will give it a sliding effect, which what I'm assuming you want :)

Categories

Resources