If i use in showAnimateWin property offsetHeight, animation work. example
function end( ) {
var top = ( window.innerHeight - win.clientHeight ) / 2,
left = ( window.innerWidth - win.clientWidth ) / 2;
win.style.top = top + "px";
win.style.left = left + "px";
}
function showAnimateWin( ) {
win.offsetHeight ;//here
win.classList.add("modal-window-animate");
end();
};
If i removed win.offsetHeight, animation work only one times. example
function showAnimateWin( ) {
win.classList.add("modal-window-animate");
end();
};
Why won't work without win.offsetHeight ?
The reason is probably because the win.offsetHeight; causes the method to wait for a few milliseconds before the transition can start again. If you put alert(1); instead of the win.offsetHeight; it will still work. You need to wait for the transition to complete before starting another animation.
UPDATE: Fiddle Link
This should work without having any delays (check fiddle):
window.setTimeout(function() {
showAnimateWin();
}, 25);
Related
I'm currently using the following javascript as shown below.
It's working well when I place just text within the div .image_scroll_3 but as soon as I insert images the scroll glitches and won't move past the top of the image.
Any advice would be much appreciated
JS
<script>
(function($, undefined) {
$.fn.loopScroll = function(p_options) {
var options = $.extend({
direction: "upwards",
speed: 60
}, p_options);
return this.each(function() {
var obj = $(this).find(".image_scroll_2");
var text_height = obj.find(".image_scroll_3").height();
var start_y, end_y;
if (options.direction == "downwards") {
start_y = -text_height;
end_y = 0;
} else if (options.direction == "upwards") {
start_y = 0;
end_y = -text_height;
}
var animate = function() {
// setup animation of specified block "obj"
// calculate distance of animation
var distance = Math.abs(end_y - parseInt(obj.css("top")));
//alert("animate " + obj.css("top") + "-> " + end_y + " " + distance);
//duration will be distance / speed
obj.animate(
{ top: end_y }, //scroll upwards
1500 * distance / options.speed,
"linear",
function() {
// scroll to start position
obj.css("top", start_y);
animate();
}
);
};
obj.find(".image_scroll_3").clone().appendTo(obj);
$(this).on("mouseout", function() {
obj.stop();
}).on("mouseout", function() {
animate(); // resume animation
});
obj.css("top", start_y);
animate(); // start animation
});
};
}(jQuery));
$("#example4").loopScroll({ speed: 700 });
</script>
I think the problem is that your text_height is calculated before the images are actually loaded inside your .image_scroll_3 elements. So you'll need to wait for the images to load.
Put your loopScroll call inside a $(window).load like so:
$(window).load(function(){
$('#example4').loopScroll({speed:700});
});
That massive glitch should now be gone as the fix above should have helped mitigate it.
However, there is still some unwanted jank / stutter (don't want to use the word glitch again, lets keep it reserved for the initial problem) in movement of all images if you notice and I am guessing that is probably because we are animating the whole thing too fast. Passing in speed like 100 or 200 resolves that but this is not really a solution because, ideally, you should be able to put in any speed value and it should just produce smooth animations out of it.
I am working on exactly the same thing but before that, I want to know if the above fix for the glitch helps you and we are finally done with it? Let me know.
Update:
Here is my version that I spoke of earlier, for your perusal.
Because all you are trying to do is loop images in a very linear fashion, I, for one, do not see the need to rely on animate() function of jQuery. There is requestAnimationFrame API that I have leveraged instead. In fact, in my demonstration below I have completely abandoned jQuery in favour of vanilla JavaScript only because I kept finding alternatives to pretty much everything we needed to do in this demo. But of course, this is also a very subjective matter; a taste thing; so if you want to go with jQuery, then by all means.
Another fundamental change I brought is rather than updating top values, I have resorted to updating translateY values.
Take a look at this jsFiddle and let me know if it fits your needs.
JavaScript code of which is as belows:
// [http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/]
window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})();
var main=null;
var imageScroll2=null;
var imageScroll3=null;
var totalHeight=null;
var initY=null;
var destY=null;
var currY=null;
var increment=null;
var direction=null;
var UP=null;
var DOWN=null;
var isPlaying=null;
function init(){
main=document.getElementById('example4');
imageScroll2=main.getElementsByClassName('image_scroll_2')[0];
imageScroll3=main.getElementsByClassName('image_scroll_3')[0];
totalHeight=imageScroll3.clientHeight;
UP='upwards';
DOWN='downwards';
isPlaying=true;
direction=UP;
increment=10;
if(direction===DOWN){
initY= -totalHeight;
destY=0;
}else{
initY=0;
destY= -totalHeight;
}
currY=initY;
imageScroll2.appendChild(imageScroll3.cloneNode(true));
if(imageScroll2.addEventListener){
imageScroll2.addEventListener('mouseover',function(){isPlaying=false;},false);
imageScroll2.addEventListener('mouseout',function(){isPlaying=true;},false);
}else{
imageScroll2.attachEvent('onmouseover',function(){isPlaying=false;});
imageScroll2.attachEvent('onmouseout',function(){isPlaying=true;});
}
requestAnimFrame(render);
}
function render(){
if(isPlaying){
imageScroll2.style.transform='translate(0px,'+currY+'px)';
if(direction===DOWN){
currY+=increment;
if(currY>=destY){currY=initY;}
}else{
currY-=increment;
if(currY<=destY){currY=initY;}
}
}
requestAnimFrame(render);
}
//
init();
So I've created the following function to fade elements in and passed in a div that I want to fade in which in this case is an image gallery popup that I want to show when a user clicks an image thumbnail on my site. I'm also passing in a speed value (iSpeed) which the timeout uses for it's time value. In this case I'm using 25 (25ms).
I've stepped through this function whilst doing so it appears to be functioning as expected. If the current opacity is less than 1, then it is incremented and it will recall itself after the timeout until the opacity reaches 1. When it reaches one it stops fading and returns.
So after stepping through it, I take off my breakpoints and try to see it in action but for some reason my gallery instantly appears without any sense of fading.
var Effects = new function () {
this.Fading = false;
this.FadeIn = function (oElement, iSpeed) {
//set opacity to zero if we haven't started fading yet.
if (this.Fading == false) {
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
this.Fading = false;
return;
}
//otherwise, fade
else {
this.Fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
}
}
}
Here's where I'm setting up the gallery.
this.Show = function (sPage, iImagesToDisplay, oSelectedImage) {
//create and show overlay
var oOverlay = document.createElement('div');
oOverlay.id = 'divOverlay';
document.body.appendChild(oOverlay);
//create and show gallery box
var oGallery = document.createElement('div');
oGallery.id = 'divGallery';
oGallery.style.opacity = 0;
document.body.appendChild(oGallery);
//set position of gallery box
oGallery.style.top = (window.innerHeight / 2) - (oGallery.clientHeight / 2) + 'px';
oGallery.style.left = (window.innerWidth / 2) - (oGallery.clientWidth / 2) + 'px';
//call content function
ImageGallery.CreateContent(oGallery, sPage, iImagesToDisplay, oSelectedImage);
//fade in gallery
Effects.FadeIn(oGallery, 25);
}
Could anyone help me out?
Also, I'm using IE10 and I've also tried Chrome, same result.
Thanks,
Andy
This line:
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
calls Effects.FadeIn with the given arguments, and feeds its return value into setTimeout. This is exactly like foo(bar()), which calls bar immediately, and then feeds its return value into foo.
Since your FadeIn function doesn't return a function, that would be the problem.
Perhaps you meant:
setTimeout(function() {
Effects.FadeIn(oElement, iSpeed);
}, iSpeed);
...although you'd be better off creating that function once and reusing it.
For instance, I think this does what you're looking for, but without recreating functions on each loop:
var Effects = new function () {
this.FadeIn = function (oElement, iSpeed) {
var fading = false;
var timer = setInterval(function() {
//set opacity to zero if we haven't started fading yet.
if (fading == false) { // Consider `if (!this.Fading)`
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
clearInterval(timer);
}
//otherwise, fade
else {
fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
}
}, iSpeed);
};
};
Your code has a lot of problems. The one culpable for the element appearing immediately is that you call setTimeout not with a function but with the result of a function, because Effects.FadeIn will be executed immediately.
setTimeout(function(){Effects.FadeIn(oElement, iSpeed)}, iSpeed);
will probably act as you intend.
But seriously, you probably should not re-invent this wheel. jQuery will allow you to fade elements in and out easily and CSS transitions allow you to achieve element fading with as much as adding or removing a CSS class.
T.J. and MoMolog are both right about the bug: you're invoking the Effects.FadeIn function immediately before passing the result to setTimeout—which means that Effects.FadeIn calls itself synchronously again and again until the condition oElement.style.opacity >= 1 is reached.
As you may or may not know, many UI updates that all take place within one turn of the event loop will be batched together on the next repaint (or something like that) so you won't see any sort of transition.
This jsFiddle includes the suggested JS solution, as well as an alternate approach that I think you may find to be better: simply adding a CSS class with the transition property. This will result in a smoother animation. Note that if you go this route, though, you may need to also include some vendor prefixes.
I am faking fixed position for a footer on a mobile site for mobile browsers that don't support fixed-position. (iOS before iOS 5, Andriod before 2.2, etc.)
Here is the JQuery code I'm using, which works well and does what I want:
function changeFooterPosition() {
$('.not-fixed').css('top', window.innerHeight + window.scrollY - 56 + "px");
}
$(document).bind('scroll', function() {
changeFooterPosition();
});
So that works.
My question is, I want to add a slight delay to it and have the footer fade into view rather than just snap quickly after every little scroll. I've looked around and found the following methods I could use, but I"m not sure if they are the correct ones or where to add them to the js above.
.delay(1000).fadeTo('slow', 1)
I know this functionality exists in JQuery Mobile, but I don't want to use the entirety of JQuery Mobile for just this one little thing.
Thanks in advance.
Try the animate function http://api.jquery.com/animate/
This won't fade but should move smoothly instead.
function changeFooterPosition() {
$('.not-fixed').animate({'top': window.innerHeight + window.scrollY - 56 + "px"}, 2000);
}
$(document).bind('scroll', changeFooterPosition);
Change
$(document).bind('scroll', function() {
changeFooterPosition();
});
To
$(document).bind('scroll', changeFooterPosition);
Change
$('.not-fixed').css('top', window.innerHeight + window.scrollY - 56 + "px");
to
var WantedSpeed = 2000;
$('.not-fixed').delay(1000).animate({
top: window.innerHeight + window.scrollY - 56 + "px"
}, WantedSpeed, function() {
// Animation complete.
})
What you want to do is throttle your scroll callback:
(function() {
var scrollTimer = 0,
$notFixed = $('.not-fixed');
function changeFooterPosition() {
$notFixed.css('top', window.innerHeight + window.scrollY - 56 + "px").show(300);
}
$(document).bind('scroll', function() {
$notFixed.hide();
clearTimeout(scrollTimer);
setTimeout(changeFooterPosition, 50);
});
}());
I am trying to implement some code on my web page to auto-scroll after loading the page. I used a Javascript function to perform auto-scrolling, and I called my function when the page loads, but the page is still not scrolling smoothly! Is there any way to auto scroll my page smoothly?
Here is my Javascript function:
function pageScroll() {
window.scrollBy(0,50); // horizontal and vertical scroll increments
scrolldelay = setTimeout('pageScroll()',100); // scrolls every 100 milliseconds
}
It's not smooth because you've got the scroll incrementing by 50 every 100 milliseconds.
change this and the amount you are scrolling by to a smaller number to have the function run with the illusion of being much more 'smooth'.
turn down the speed amount to make this faster or slower.
function pageScroll() {
window.scrollBy(0,1);
scrolldelay = setTimeout(pageScroll,10);
}
will appear to be much smoother, try it ;)
Try to use jQuery, and this code:
$(document).ready(function(){
$('body,html').animate({scrollTop: 156}, 800);
});
156 - position scroll to (px), from top of page.
800 - scroll duration (ms)
You might want to look at the source code for the jQuery ScrollTo plug-in, which scrolls smoothly. Or maybe even just use the plug-in instead of rolling you own function.
Smoothly running animations depends on the clients machine. No matter how fairly you code, you will never be satisfied the way your animation runs on a 128 MB Ram system.
Here is how you can scroll using jQuery:
$(document).scrollTop("50");
You might also want to try out AutoScroll Plugin.
you can use jfunc function to do this.
use jFunc_ScrollPageDown and jFunc_ScrollPageUp function.
http://jfunc.com/jFunc-Functions.aspx.
Since you've tagged the question as 'jquery', why don't you try something like .animate()? This particular jquery function is designed to smoothly animate all sorts of properties, including numeric CSS properties as well as scroll position.
the numbers are hardcoded, but the idea is to move item by item (and header is 52px) and when is down, go back
let elem = document.querySelector(".spfxBirthdaysSpSearch_c7d8290b ");
let lastScrollValue = 0
let double_lastScrollValue = 0
let scrollOptions = { top: 79, left: 0, behavior: 'smooth' }
let l = console.log.bind(console)
let intScroll = window.setInterval(function() {
double_lastScrollValue = lastScrollValue //last
lastScrollValue = elem.scrollTop // after a scroll, this is current
if (double_lastScrollValue > 0 && double_lastScrollValue == lastScrollValue){
elem.scrollBy({ top: elem.scrollHeight * -1, left: 0, behavior: 'smooth' });
} else {
if (elem.scrollTop == 0){
elem.scrollBy({ top: 52, left: 0, behavior: 'smooth' });
} else {
elem.scrollBy(scrollOptions);
}
}
}, 1000);
Here's another take on this, using requestAnimationFrame. It gives you control of the scroll time, and supports easing functions. It's pretty robust, but fair warning: there's no way for the user to interrupt the scroll.
// Easing function takes an number in range [0...1]
// and returns an eased number in that same range.
// See https://easings.net/ for more.
function easeInOutSine(x) { return -(Math.cos(Math.PI * x) - 1) / 2; }
// Simply scrolls the element from the top to the bottom.
// `elem` is the element to scroll
// `time` is the time in milliseconds to take.
// `easing` is an optional easing function.
function scrollToBottom(elem, time, easing)
{
var startTime = null;
var startScroll = elem.scrollTop;
// You can change the following to scroll to a different position.
var targetScroll = elem.scrollHeight - elem.clientHeight;
var scrollDist = targetScroll - startScroll;
easing = easing || (x => x);
function scrollFunc(t)
{
if (startTime === null) startTime = t;
var frac = (t - startTime) / time;
if (frac > 1) frac = 1;
elem.scrollTop = startScroll + Math.ceil(scrollDist * easing(frac));
if (frac < 0.99999)
requestAnimationFrame(scrollFunc);
}
requestAnimationFrame(scrollFunc);
}
// Do the scroll
scrollToBottom(document.getElementById("data"), 10000, easeInOutSine);
Hi
I am using the following method to programmatically scroll a web document:
window.scrollBy(0, delta)
The current implementation of scrollBy just jumps the document to the new position. Is there a way of animating this? I am using webkit specifically, and jQuery (or any other javascript framework) is not an option.
Thanks for any help in advance.
You can just animate it by invoking an interval:
setInterval(function() {
window.scrollBy(0, 5);
}, 13);
This of course would do it over and over, so you need to put in a conditional check, when to cancel the interval. Could look like:
var timerID = setInterval(function() {
window.scrollBy(0, 5);
if( window.pageYOffset >= 500 )
clearInterval(timerID);
}, 13);
Every time this function is called, it will jump the number of pixels in window.scrollBy (0,5), regardless of where the pageYOffset is. For instance, if pageYOffset is 300px, it will jump to 305px.
but this problem can be solved by moving the if and adding an else
like so:
var timerID = setInterval(function() {
if( window.pageYOffset <= 500 )
window.scrollBy(0, 5);
else
clearInterval(timerID);
}, 1);