How do smooth slides work in javascript? - javascript

For a while now i have been trying to figure out the algorithms behind smooth slides, fades etc..in javascript. Just to give you an example of what am talking about, I have seen a div with content in it that had a height of 0px and on toggled, it didn't just snap to height, it smoothly and gradually grew to height using some sort of function. What i do know is that the height of this div was being assigned its height value from either a date object that had an interval set or a loop of some sort. I've searched all over the web trying to find tutorials explaining how this works but failed. Can someone please either explain to me how to create my own smooth fades, slides or reference some links that i can read?
PS: I know i can just use jquery, but i want to know how the fades and slides actually work.

It's quite simple actually. All of these animations use a timer (see setInterval) with a short interval, say 100 milliseconds, and every time the timer fires, the property (height or whatever) is changed by a fraction of the total amount instead of all at once.
For example, if you want to slide from a height of 0px to 200px in 1 second, then you could set up a timer that fires every 100 ms and increases the height of the DIV by 20px. That way, in 1 second, the timer would have fired 10 times and the height would be 200px.
A simple example:
function slideOpen(elem, finalHeight, slideTime) {
var count = slideTime * 10; // 10 intervals per second
height = 0, // current height
delta = finalHeight / count; // change in height per interval
var timerId = setInterval(slide, 100);
function slide() {
height += delta;
elem.style.height = height + 'px';
if (--count == 0)
clearInterval(timerId);
}
}

I have never looked at the jQuery code myself, but i'm pretty sure it uses a loop/timeout to increment the top/left/bottom/right css position of the element gradually using the specified easing equation.
You might want to have a look at jQuery source code for the animate() function.

CSS3 makes it trivial.
For non-CSS3 based solution, this is the first Google result for the query "javascript smooth animation": http://www.schillmania.com/content/projects/javascript-animation-2/

I am adding some code from one of my projects to move the div right
belolw xs_tuck() will be called till finalleftpositionval reaches
This code makes the div move to right.
if(xs_endpt<finalLeftPositionVal){
xs_endpt+=5;
xs_pDiv2.style.left=xs_endpt;
setTimeout("xs_tuck();",20);
}

Related

Item positioning on scroll gives a warning about asynchronous scrolling

I'm trying to position two images by changing their top margin based on the scroll position.
The margins have a max value as well.
Everything works just fine but I have a warning on the console, saying that this solution can cause a jittery scrolling effect in browsers with asynchronous scrolling.
My first question is, should I worry about this?
Also, this is literally my first few lines of javascript and I'm not sure if this solution is good enough, so any advice is appreciated.
It just looks so simple I feel like there is a catch.
I could do it by adding classes to the images and set the margins in CSS, but it would be a lot longer code I guess.
I'm trying to do this strictly with js and CSS grid, just to learn to solve problems with limited tools.
The images are in a div, which is in a grid cell.
window.addEventListener("scroll", function () {
myMargin = 0.011 * window.scrollY;
if (myMargin < 3.4) { //max margin is 3.4% for myImg1
myImg1.style.marginTop = animMargin + "%";
myImg2.style.marginTop = animMargin / 2.7 + "%"; //myImg2 moves on a different scale
} else {
myImg1.style.marginTop = "3.4%"; //when the max value reached the margin is fixed
myImg2.style.marginTop = "1.25%";
}
});
Scrolling handlers can be intensive and put performance strain on the page as they will fire far more times than your handler actually needs. This ends up causing choppy/lag when scrolling as the browser may need to repaint in response to your handler.
A common technique is to throttle or debouce the handler.
Throttle:
only invokes func at most once per every x milliseconds.
Debouce:
delays invoking func until after x milliseconds have elapsed since the last time the debounced function was invoked.
The warning you are getting is actually fine, but you may benefit from using a throttled callback and increase the wait time to the max that is suitable for your needs - so least times it is called in order for it to work for you.
Demo using lodash throttle
// only call the handler once every 200ms
const throttledScroll = _.throttle(() => {
console.info('throttled', window.scrollY);
}, 200);
window.addEventListener('scroll', throttledScroll);
html,
body {
height: 300vh;
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

width of div flickering between previous width and current width

I have developed an audio slider (the slider down the bottom which allows you to scrub through the track) similar to SoundCloud's, and it all works perfectly, except for one thing; it flickers back and forth between the width [/ time] of the previous playing track, and the current playing track.
I have no idea as to why this is happening and have been stumped on it for quite a while.
This is my current block of JavaScript & jQuery:
function trackToSlider(wave){
// get the duration of current playing song
var waveDuration = wave.getDuration();
// check every 0.1s how far in the song is
var getWidthAndMax = setInterval(function(){
// currentWidth is the current percentage of the width of the slider from 100%
var currentWidth = (wave.getCurrentTime() / waveDuration) * 100;
makeSliderIncrease(currentWidth, waveDuration);
}, 100);
function makeSliderIncrease(currentWidth, maxWidth){
// if the current time is more than or equal to the songs duration, set the width of the slider to 100% and clear the interval
if(currentWidth >= maxWidth){
clearInterval(getWidthAndMax);
$('#inner-slider').css('width', '100%');
// otherwise set the width percentage equal to currentwidth
} else {
$('#inner-slider').css('width', currentWidth + '%');
}
}
}
Here are the relative elements inside my HTML:
<!-- play or pause track button !-->
<div onclick="trackToSlider(wave);"></div>
<!-- the audio slider which keeps on flickering !-->
<div class="audio-slider-container">
<div id="outer-slider">
<div id="inner-slider"></div>
</div>
</div>
I hope you all sort of understand where I am at currently. I have attempted to comment everything to make it easier to understand.
I feel like the problem is that because it's set a width already, before it moves onto the next track, when the new track attempts to set the new width, it's flicking between the two widths consistently, but I could be wrong.
All help or suggestions are appreciated,
Thanks. :-)
I think it's beacouse you use the same div for every track. My assumption is that your clearInterval function resets currentWidth of wave, and makes it go back to 0 invoking tracktoSlider twice. But that's all I can say based on given code. Try to add a #inner-slider to html each time you start a new track, and remove it each time when track ends

JavaScript animation very buggy

So I have a very small, insignificant site i'm working on. my website If you click on the grey-ish bar at the bottom, it will animate a sort of eased-in for me to use in the future to edit info i put together on various pictures or whatever i decide i want to put up there.
my code for the animation is: (edited to reflect changes)
function animateForm(startPosition,endPosition,firstKey,keyInterval)
{
if(currentKey != lastKey)
{
animationPointer =( .5 * Math.sin((currentKey * (Math.PI/totalKeys)) - (Math.PI/2))) + .5;
currentPosition = (animationPointer)*endPosition;
bottomForm.style.bottom = currentPosition + "px";
currentKey=currentKey+(keyInterval*1);
}
else
{
clearInterval(int);
int=0;
}
}
SOLVED! The problem was that I was multiplying the "animation pointer" (a decimal from 0 to 1 indicating the progress in the animation) by the "end position," and if the animation was aiming for an end position of "0," This set my form's position immediately to the "hide" position, and things asploded from there.
What i needed to do multiply the pointer by the maximum height the form could reach so that on its descent it could gradually return a smaller and smaller value to the "currentPosition" variable.
You're never clearing the setInterval between animations. Simply typing clearInterval; doesn't do anything. You need to store the ID that's returned from setInterval(), and then pass it to a call to clearInterval();.
Because you're not clearing, those original intervals are still running and still trying to operate on the same variables.

How do I move the background image of a DIV based on the scrollbar movement?

I have been looking into parallax effects for vertical scrolling on my web page, and after some research, I'm not sure that what I want to do is technically a parallax effect.
From what I've seen, most parallax effects assume you want to be able to scroll indefinitely with many background images rolling by, or with huge images that repeat.
What I want to do is have the background of two DIVs be filled with a background image as the scroll bar reaches the bottom of the page. Note that I do not want the background images to stretch. I'm assuming to get the effect I want that these images would have a vertical height bigger than most people's viewport, and then their vertical position would change. When the user's scrollbar is at the top, a certain amount of the background is visible, and then it moves vertically to fill the background space as the user scrolls down.
Please see the image below for a visual explanation of the effect I hope to acheive:
The height of the veiwport will vary depending on the length of content inside the inner DIV.
My trouble is that if what I am trying to do is not exactly a parallax effect, then I don't know what else to call it, and my attempts to search by describing it keep landing me back at pages offering tutorials on parallax effects. So I've been stumped by a lack of terminology.
If someone could direct me to how I can control the vertical position of the background depending on the scrollbar position, that would be much appreciated. If this can be done with just CSS that would be great, but I'm assuming some Javascript would be required. A jQuery solution would also work for me.
Update:
After searching using the terms provided in comments, I've got the background image in the outer DIV to almost do what I want with the following code:
$(window).scroll(function () {
var yPos = $("#outerDiv").height() - ($("#outerDIV").height() * ($(window).scrollTop() / $(window).height()));
document.getElementById('outerDIV').style.backgroundPosition="0px " + yPos + "px";
});
It moves the background image in the right direction relative to the scrolling, but what it lacks is constraining that motion to within the viewport. Getting the right proportions based on the viewport and DIV sizes is proving to be just a little beyond my mathematical abilities.
For your requirement, you have to use a jquery parallax plugin to guide this activity, my best suggest it to use a Superscollorama and play with the elements as your wish...
As far as your question, Try this example,
controller.addTween(
'#examples-background',
(new TimelineLite())
.append([
TweenMax.fromTo($('#parallax-it-left'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 -54px)"}}),
TweenMax.fromTo($('#parallax-it-right'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 54px)"}})
]),
1000 // scroll duration of tween
);
You serial vice change as far as your wish...
Try practice this plugin, hope that works for you...
http://johnpolacek.github.io/superscrollorama/
Thanks...
Turns out what I want to acheive is possible with no special plugins, just some carefully thought out math. I did use a little jQuery syntax, but I don't think it's strictly necessary.
The code below has copious notes, so hopefully it's largely explanatory. In summary, you just need to find the position of the background image when the scroll would be at the top, and the position it would be if the scroll bar was at the bottom, and then you can use the percentage of the scrollbar's movement to work out where you are between those two points. It's a little tricker than just that, of course, in that you have to account for the difference between the total height of the scroll bar and where your DIV appears on the page and a few other adjustments, but the details of what I did are below.
What I've done here is just for the "outer DIV" that I described in my question. To get a background to move like the "inner DIV" I described, you'd have to modify the code, presumeably by reversing a few parameters. I haven't done that yet, but it seems like a straightforward task.
Hope others find this code useful. If anyone has suggestions on how it can be made more efficient or better, please let me know.
function moveBG(){
// imageHeight is not the total height of the image,
// it's the vertical amount you want to ensure remains visible no matter what.
var imageHeight = 300;
// Get the maximum amount within the DIV that the BG can move vertically.
var maxYPos = $("#outerDIV").height() - imageHeight;
// Get the amount of vertical distance from the top of the document to
// to the top of the DIV.
var headerHeight = document.getElementById("outerDIV").offsetTop;
// Calculate the BG Y position for when the scrollbar is at the very top.
var bgTopPos = $(window).height() - headerHeight - imageHeight;
// I don't want the image to wander outside of the DIV, so ensure it never
// goes below zero.
if (bgTopPos < 0)
{
bgTopPos = 0;
}
// Calculate the BG Y position when the scrollbar is at the very top.
var bgBottomPos = $(document).height() - $(window).height() - headerHeight;
// To prevent the BG image from getting cut off at the top, make sure
// its position never exceeds the maximum distance from the top of the DIV.
if (bgBottomPos > maxYPos)
{
bgBottomPos = maxYPos;
}
// Subtract the top position from the bottom, and you have the spread
// the BG will travel.
var totalYSpan = bgBottomPos - bgTopPos;
// Get the scrollbar position as a "percentage". Note I simply left it as a
// value between 0 and 1 instead of converting to a "true" percentage between
// 0 and 100, 'cause we don't need that in this situation.
var scrollPercent = ($(window).scrollTop() / ( $(document).height() - $(window).height()));
// The percentage of spread is added to the top position, and voila!
// You have your Y position for the BG image.
var bgYPos = bgTopPos + (Math.round(totalYSpan * scrollPercent));
// Apply it to the DIV.
document.getElementById('outerDIV').style.backgroundPosition="0px " + bgYPos + "px";
}
// Place the BG image correctly when opening the page.
$(document).ready(function() {
moveBG();
});
// Make it update when the scrollbar moves.
$(window).scroll(function () {
moveBG();
});

jQuery div autoscroll

I am looking for advice on how to create an autoscrolling effect using jQuery which would enable an entire div within a page to begin scrolling vertically upon loading at a constant slow speed. This would be a div with a large amount of content of which only a small amount was visible on the screen at any one time.
The scroll needs to be automatic, smooth and at a defined rate for example 10 pixels per second. Additionally when the scroll gets to the bottom of the page I need to be able to call a function.
I have tried a few different jQuery plugins but found nothing yet that worked reliably. Can anybody suggest an approach to take here?
Thanks
Simon
This can easily be done without jquery.
function init() {
var div = document.getElementById("myDiv");
// increase the scroll position by 10 px every 10th of a second
setInterval(function() {
// make sure it's not at the bottom
if (div.scrollTop < div.scrollHeight - div.clientHeight)
div.scrollTop += 10; // move down
}, 100); // 100 milliseconds
}
Try this technique
try this plugin : scrollTo
especially the onAfter

Categories