using requestAnimationFrame - javascript

I'm using this function to set a transform property of some elements,but the animation is not so smooth in firefox and it's less smooth when window size is bigger(in any browser).I have read a lot of thing's on blogs which are saying that I can make much smoother animation using requestAnimationFrame,but I don't understand how I can implement it inside of my function.Can somebody explain me how I can use it inside of my function?
function sectionMovement(delay,section) {
setTimeout(function () {
var val = ((v.sectionIndex + 1) > v.leavingSection) ?
val = 100 :
val = 0;
document.getElementById("sec_"+section+"").style.transform = "translateY(-"+val+"%)"
}, delay);
};

Something like this:
function updateSection(selector) {
var elem = document.getElementById("sec_" + section);
return function step() {
var val = ((v.sectionIndex + 1) > v.leavingSection) ? // not sure what 'v' is?
100 :
0;
elem.style.transform = "translateY(-"+val+"%)";
requestAnimationFrame(step);
}
}
var sel = "myElementId";
requestAnimationFrame(updateSection(sel));
You will also likely want an external variable to check against to know when to stop the animation.

Related

How to create a custom loop?

I made a custom loop that delays 300ms on it's each iteration. But in this loop, the line ul.syle.height = i + 'px'; is throwing a error that TypeError: Cannot set property 'height' of undefined at main.js
But the variable ul is working fine above at the line var ul_scrollHeight = ul.scrollHeight;.
Then why it is not working inside 'setTimeout'? Here getNextSibling is another function in my code.
function fun1() {
var ul = getNextSibling(this);
var ul_scrollHeight = ul.scrollHeight;
var i = 1;
function customLoop() {
setTimeout(function () {
ul.syle.height = i + 'px'; // Not Working
if (i <= ul_scrollHeight) {
customLoop();
}
}, 300)
}
customLoop();
}
I think you just have a typo on that line:
ul.syle.height = i + 'px';
Because ul.syle is missing a t, so that returns undefined, which did not have a property height. 🙂

Delay inside for loop not working

I want to make a delay inside my for loop, but it won't really work.
I've already tried my ways that are on stackoverflow, but just none of them work for what I want.
This is what I've got right now:
var iframeTimeout;
var _length = $scope.iframes.src.length;
for (var i = 0; i < _length; i++) {
// create a closure to preserve the value of "i"
(function (i) {
$scope.iframeVideo = false;
$scope.iframes.current = $scope.iframes.src[i];
$timeout(function () {
if ((i + 1) == $scope.iframes.src.length) {
$interval.cancel(iframeInterval);
/*Change to the right animation class*/
$rootScope.classess = {
pageClass: 'nextSlide'
}
currentId++;
/*More information about resetLoop at the function itself*/
resetLoop();
} else {
i++;
$scope.iframes.current = $scope.iframes.src[i];
}
}, $scope.iframes.durationValue[i]);
}(i));
}
alert("done");
This is what I want:
First of all I got an object that holds src, duration and durationValue.
I want to play both video's that I have in my object.
I check how many video's I've got
I make iframeVideo visible (ngHide)
I insert the right <iframe> tag into my div container
It starts the $timeout with the right duration value
If that's done, do the same if there is another video. When it was the last video it should fire some code.
I hope it's all clear.
I've also tried this:
var iframeInterval;
var i = 0;
$scope.iframeVideo = false;
$scope.iframes.current = $scope.iframes.src[i];
iframeInterval = $interval(function () {
if ((i + 1) == $scope.iframes.src.length) {
$interval.cancel(iframeInterval);
/*Change to the right animation class*/
$rootScope.classess = {
pageClass: 'nextSlide'
}
currentId++;
/*More information about resetLoop at the function itself*/
resetLoop();
} else {
i++;
$scope.iframes.current = $scope.iframes.src[i];
}
}, $scope.iframes.durationValue[i])
Each $timeout returns a different promise. To properly cancel them, you need to save everyone of them.
This example schedules several subsequent actions starting at time zero.
var vm = $scope;
vm.playList = []
vm.playList.push({name:"video1", duration:1200});
vm.playList.push({name:"video2", duration:1300});
vm.playList.push({name:"video3", duration:1400});
vm.playList.push({name:"video4", duration:1500});
vm.watchingList=[];
var timeoutPromiseList = [];
vm.isPlaying = false;
vm.start = function() {
console.log("start");
//ignore if already playing
if (vm.isPlaying) return;
//otherwise
vm.isPlaying = true;
var time = 0;
for (var i = 0; i < vm.playList.length; i++) {
//IIFE closure
(function (i,time) {
console.log(time);
var item = vm.playList[i];
var p = $timeout(function(){playItem(item)}, time);
//push each promise to list
timeoutPromiseList.push(p);
})(i,time);
time += vm.playList[i].duration;
}
console.log(time);
var lastPromise = $timeout(function(){vm.stop()}, time);
//push last promise
timeoutPromiseList.push(lastPromise);
};
Then to stop, cancel all of the $timeout promises.
vm.stop = function() {
console.log("stop");
for (i=0; i<timeoutPromiseList.length; i++) {
$timeout.cancel(timeoutPromiseList[i]);
}
timeoutPromiseList = [];
vm.isPlaying = false;
};
The DEMO on PLNKR.
$timeout returns promise. You can built a recursive chain of promises like this, so every next video will play after a small amount of time.

An issue with CSS animations and JS classList.add

I'm writing a private 'framework' of sorts in order to have some basic effects without the need of jQuery.
I've just written some code for fade-ins/outs, and basically what I do is add/remove classes, and check for animation support.
Here's the JavaScript part (please, check mainly the fadeIn, fadeOut properties):
var effs = {
checkSupport: (function() {
var init = true;
var supports = false;
return function(el) {
if (init) {
var animationstring = 'animation',
keyframeprefix = '',
domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
pfx = '';
if (el.style.animationName !== undefined) {
supports = true;
}
if (supports === false) {
for (var i = 0; i < domPrefixes.length; i++) {
if (el.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
supports = true;
break;
}
}
}
init = false;
}
return supports;
};
}()),
fadeOut: function(el) {
el.style.opacity = 1;
if (this.checkSupport(el)) {
el.classList.remove("fadeIn", "fadeOut");
//Here comes the annoying timeout!
setTimeout(function() {
el.classList.add("fadeOut");
}, 25);
} else {
el.style.opacity = 0;
}
},
fadeIn: function(el) {
el.style.opacity = 0;
if (this.checkSupport(el)) {
el.classList.remove("fadeIn", "fadeOut");
setTimeout(function() {
el.classList.add("fadeIn");
}, 25);
} else {
el.style.opacity = 1;
}
}
};
As you can see, I have had to delay the addition of the animation class, because without that timeout, the animation doesn't show the second time around in Chrome(and other Webkit browsers), when it is called on the same element. It does work in Firefox without the timeout, though.
I also tested this in Midori, and since it's also a Webkit browser, it needs the timeout as well, but with the added annoyance of the delay being even longer than 25ms, for some reason.
Why is this? Is there any other way around that you can think of? I know these methods aren't very compatible with a lot of browsers, but I don't mind the animations not showing in some of them. Thank you.

How to pass a variable after setInterval completes?

I have the following code. A fiddle I started which is an isolated version of something I am trying to do.
var height;
var count = 0;
var setHeight = setInterval(function() {
count++;
console.log('count');
if ( count > 10)
{
console.log('done');
height = 20;
clearInterval(setHeight);
}
},100);
console.log('this is the height -> ' + height);
What I would expect (or want to happen) is for the value of height = 20; to be outputted in my console.log. The end goal would be to retrieve a variable from my setInterval function after the interval has been cleared.
Right now I get .. this is the height -> undefined
FIDDLE:
http://jsfiddle.net/GNvG6/8/
What I am trying to accomplish:
So the underlying issue is this. I have a function that runs before some elements are loaded in the DOM. So what I am trying to do is keep running the function until an instance of that element exists. Once that happens I then intend to get the height of that element and hand it off to another variable. I am not sure If this will resolve my issue, but I figure if I can get this to work I can at least test it out.
var height;
var count = 0;
var setHeight = setInterval(function() {
count++;
console.log('count');
if ( count > 10)
{
console.log('done');
height = 20;
reportHeight(height);
clearInterval(setHeight);
}
},100);
function reportHeight(height){
console.log('this is the height -> ' + height);
}
console output is
(11) count
done
this is the height -> 20
FIDDLE DEMO
var height = 0; // initial value
var count = 0;
var setHeight = setInterval(function() {
count++;
console.log('count and height is still:'+ height); // height is always 0
if ( count > 10){
height = 20;
console.log('done and height is:'+ height); // height is finally 20
clearInterval(setHeight);
}
},100);
As you're using jQuery, you could also use $.Deferred.
// wait for 3 + (0..2) seconds
setTimeout(function () {
$(document.body).append($("<strong>hello</strong>"));
}, 3000 + 2000 * Math.random());
function waitFor(test, interval) {
var dfd = $.Deferred();
var count = 0;
var id = setInterval(function () {
console.log(count++);
var val = test();
if (undefined !== val) {
clearInterval(id);
dfd.resolve(val);
}
}, interval);
return dfd.promise();
}
function waitForEl(selector, interval) {
return waitFor(function () {
var els = $(selector);
return (els.length > 0) ? els : undefined;
}, interval);
}
waitForEl("strong", 100).then(function (strong) {
console.log(strong, strong.height());
});
Example in this jsfiddle.

Extend Zepto.js with a jQuery method? scrollTop()

I'm using Zepto.js on a current project. Zepto doesn't support the scrollTop() method that jQuery has in it.
Is it possible to kind of extend Zepto to work with scrollTop() too?
Update: All I want is to create my own small and simple "animated scroll" function like I have used before with jQuery. See the working example here. However I have no idea how to make the same function work without the scrollTop() function available in Zepto.js.
scrollTop isn't animatable using Zepto's .animate method, as it uses CSS transitions.
Try something like this: http://jsfiddle.net/DVDLM/5/
function scroll(scrollTo, time) {
var scrollFrom = parseInt(document.body.scrollTop),
i = 0,
runEvery = 5; // run every 5ms
scrollTo = parseInt(scrollTo);
time /= runEvery;
var interval = setInterval(function () {
i++;
document.body.scrollTop = (scrollTo - scrollFrom) / time * i + scrollFrom;
if (i >= time) {
clearInterval(interval);
}
}, runEvery);
}
$('#trigger').click(function () {
scroll('600px', 500);
});
EDIT: I added a runEvery variable, which specifies how often the interval should be ran. The lower this is, the smoother the animation is, but it could affect performance.
EDIT2: I think I misread the question. Here is the answer to the new question:
$.zepto.scrollTop = function (pixels) {
this[0].scrollTop = pixels;
};
dont want to steel nobody work so here is the short answer
Porting from jQuery to Zepto
Use the DOM native scrollTop property:
$('#el')[0].scrollTop = 0;
(function ($) {
['width', 'height'].forEach(function(dimension) {
var offset, Dimension = dimension.replace(/./, function(m) { return m[0].toUpperCase() });
$.fn['outer' + Dimension] = function(margin) {
var elem = this;
if (elem) {
var size = elem[dimension]();
var sides = {'width': ['left', 'right'], 'height': ['top', 'bottom']};
sides[dimension].forEach(function(side) {
if (margin) size += parseInt(elem.css('margin-' + side), 10);
});
return size;
}
else {
return null;
}
};
});
["Left", "Top"].forEach(function(name, i) {
var method = "scroll" + name;
function isWindow( obj ) {
return obj && typeof obj === "object" && "setInterval" in obj;
}
function getWindow( elem ) {
return isWindow( elem ) ? elem : elem.nodeType === 9 ? elem.defaultView || elem.parentWindow : false;
}
$.fn[method] = function( val ) {
var elem, win;
if (val === undefined) {
elem = this[0];
if (!elem) {
return null;
}
win = getWindow(elem);
// Return the scroll offset
return win ? ("pageXOffset" in win) ? win[i ? "pageYOffset" : "pageXOffset"] :
win.document.documentElement[method] ||
win.document.body[method] :
elem[method];
}
// Set the scroll offset
this.each(function() {
win = getWindow(this);
if (win) {
var xCoord = !i ? val : $(win).scrollLeft();
var yCoord = i ? val : $(win).scrollTop();
win.scrollTo(xCoord, yCoord);
}
else {
this[method] = val;
}
});
}
});
})(Zepto);
The answer is simple, Zepto dose not use timeout style animation, it uses css3, so here is a basic implementation for a scroll function:
HTML:
Animated Scroll
Hello You
​
CSS:
#page { height:5000px; position:relative; }
#element { position:absolute; top:600px }
JS:
function scroll(selector, animate, viewOffset) {
$('body').scrollToBottom (600, '800');
}
$('#trigger').click(function(e) {
e.preventDefault();
scroll( $('#element'), true, 30 );
});
$.fn.scrollToBottom = function(scrollHeight ,duration) {
var $el = this;
var el = $el[0];
var startPosition = el.scrollTop;
var delta = scrollHeight - startPosition;
var startTime = Date.now();
function scroll() {
var fraction = Math.min(1, (Date.now() - startTime) / duration);
el.scrollTop = delta * fraction + startPosition;
if(fraction < 1) {
setTimeout(scroll, 10);
}
}
scroll();
};
​
Note that version 1.0 of Zeptos now supports scrollTop(). See Documentation:
http://zeptojs.com/#scrollTop

Categories