Dynamically binding/unbinding SuperScrollorama tweens - javascript

I'm trying to bind/unbind SuperScrollorama tweens dynmaically. On unbind, I also need to reset the tweened element to its default styles. In my case, I'm the bind/unbind needs to happen, based on browser width. I thought I could do something like this:
calcSizes = function() {
controller.addTween( '#panel', TweenMax.to( $('#panel h1'), .5, {css:{top: 0 }}), 0, 50);
if ( viewport().width >= '720' ) {
controller.removeTween( '#panel' );
}
}
$(window).resize(function(){
calcSizes();
});
Of course, this isn't particularly elegant, and doesn't work.

this does work with ScrollMagic. :)
check it out. -> http://janpaepke.github.io/ScrollMagic/
regards,
J

Related

How to not re-render the whole list in Mithril

I've used react for quite some time and wanted to try out Mithril.js.
Went through the documentation and the examples and liked what I saw, so I said I should get my hands dirty and start coding!
I have a smiple API call that receives a JSON data and then outputs ul list with all the items. I've integrated GSAP TweenMax for animations and what I'm trying to achieve is very simple - I fade everything in, on onload and then onclick I want to fade to fade an element out and remove it from DOM / data.
What seems to be happening is that the element is fading out, the whole ul list is being re-rendered and that element remains in the DOM with 0 opacity:
var Item = {
list: function() {
return m.request({method: 'GET', url: '/api/items'});
}
}
var dm = {
controller: function(data) {
var items = Item.list();
return {
items: items,
remove: function(item) {
items().data.splice(items().data.indexOf(item), 1);
}
}
},
view: function(ctrl) {
return m('ul', [
ctrl.items().data.map(function(item, id){
return m('li',{
key: id,
config: fadesIn,
onclick: fadeOut(ctrl.remove.bind(this, item))
}, item.title);
})
]);
}
}
var fadesIn = function(element){
var tl = new TimelineMax();
tl.from(element, .5, {opacity: 0});
}
var fadeOut = function(callback) {
return function(e) {
m.redraw.strategy('none');
TweenMax.to(e.target, .5, {opacity: 0, onComplete: function() {
m.startComputation();
callback();
m.endComputation();
}});
}
}
m.mount(document.getElementById('test'), dm);
I'm very new.. started reading up just yesterday.
Getting animation libraries to work with Mithril can be tricky. When libraries manipulate DOM state the synchronization with Mithril state can be broken.
Fortunately that wasn't the case: What you're missing is the isInitialized parameter for the config function, which is false only on the first call. Testing for that makes the fade-in only happen once:
var fadesIn = function(element, isInit){
if(isInit) return;
var tl = new TimelineMax();
tl.from(element, .5, {opacity: 0});
}
In this simple example the redrawing can also be simplified, I've made a fiddle with a working example:
http://jsfiddle.net/ciscoheat/dkyc0ryc/
Since there are no DOM manipulations a call to m.redraw is enough to remove the div from DOM, but you're probably right in using start/endComputation when things get more complex. I would even move m.startComputation above the TweenMax.to call to make it extra safe, but if many other things are happening at the same time, that may block other redraws. You have to find a balance. :)
The call to m.redraw.strategy isn't needed in any case, I think. It's mostly used when you want nothing at all to happen (synchronously as well), but an async animation is starting so it won't have any effect.
Edit: Found another problem, the key cannot be set to the index of the map function, then it will change when an item is removed, messing up the redraw. I've updated the fiddle to use item.title as key instead.

jQuery Animation Jump

The header to my tumblr page seems a bit jumpy when I attempted to animate its growth and shrinkage when it is no longer on the top of the page.
The webpage is Tobacco Endeavors and is a tumblr blog.
<script type="text/javascript">
$(window).scroll(function(){
if ($(this).scrollTop() > 1) {
$("#abracadabra").fadeOut(500, function(){
$("#header").animate({padding:"1.5em 0"}, 500);
});
} else {
$("#abracadabra").fadeIn(500, function(){
$("#header").animate({padding:"1em 0"}, 500);
});
}
});
</script>
Thanks a bunch guys.
The scroll event could fire many times, you need to control concurrency with a flag, like so:
<script type="text/javascript">
window.flag = true;
$(window).scroll(function(){
if ($(this).scrollTop() > 1) {
if (window.flag) {
window.flag = false;
$("#abracadabra").fadeOut(500, function(){
$("#header").animate({padding:"1.5em 0"}, 500, function() {window.flag = true;});
});
}
} else {
if (window.flag) {
window.flag = false;
$("#abracadabra").fadeIn(500, function(){
$("#header").animate({padding:"1em 0"}, 500, function(){window.flag = true;});
});
}
}
});
</script>
UPDATE:
Updated a typo in code. Try new version above.
stop() and fadeTo() can fix some strange issues sometimes :)
jsBin demo
$(window).scroll(function(){
if ($(this).scrollTop() > 1) {
$("#abracadabra").stop().fadeTo(500,0, function(){
$("#header").stop().animate({padding:"1.5em 0"}, 500);
});
} else {
$("#abracadabra").stop().fadeTo(500,1, function(){
$("#header").stop().animate({padding:"1em 0"}, 500);
});
}
});
about your issue:
from the DOCS:
The .fadeOut() method animates the opacity of the matched elements. Once the opacity reaches 0, the display style property is set to none, so the element no longer affects the layout of the page.
causing jumpy result. On the other hand fadeTo() method
With duration set to 0, this method just changes the opacity CSS property, so .fadeTo(0, opacity) is the same as .css('opacity', opacity).
and as you can see affecting nicely the layout of the page.
See jQuery animate, not smooth
..Just set the easing parameter of the animation to linear.
There are also plugins people have made as alternatives if you feel inclined.
jQuery/JavaScript animations can be jumpy at times, and can also depend on an individuals personal hardware setup. What I like to do for animations is make a css class that has a transition, and the add the class. Additionally, make another css class that has the opposite transition, and add that one to animate out. This works pretty well, and if i'm not mistaken, provides increased browser compatibility.

Help with adding CSS to jquery

I am really new to jquery and I dont really have time to see how it works (I work with PHP a lot) I want to make a jquery slideshow but I dont know how to add z-index to the images here: http://www.albavid.com/new/index.html
I can see that jquery adds some css elements like opacity, width.. etc.
I tried to add a bigger z-index to the current image and lower z-index to the right images and left images.
Can anyone tell me how to add css with jquery so the current image(the biggest) to be on the top and then the others behind it.
Replace your javascript on the page with this:
I added in $(el).css('z-index', 5) and $(el).css('z-index', 0) in currentCss, beforeCss, and afterCss.
jQuery( document ).ready( function(){
jQuery( '#flip' ).jcoverflip({
current: 2,
beforeCss: function( el, container, offset ){
$(el).css('z-index', 0);
return [
$.jcoverflip.animationElement( el, { left: ( container.width( )/2 - 210 - 110*offset + 20*offset )+'px', bottom: '20px' }, { } ),
$.jcoverflip.animationElement( el.find( 'img' ), { width: Math.max(10,200-10*offset*offset) + 'px' }, {} )
];
},
afterCss: function( el, container, offset ){
$(el).css('z-index', 0);
return [
$.jcoverflip.animationElement( el, { left: ( container.width( )/2 + 110 + 110*offset )+'px', bottom: '10px' }, { } ),
$.jcoverflip.animationElement( el.find( 'img' ), { width: Math.max(10,200-10*offset*offset) + 'px' }, {} )
];
},
currentCss: function( el, container ){
$(el).css('z-index', 5);
return [
$.jcoverflip.animationElement( el, { left: ( container.width( )/2 - 200 )+'px', bottom: 0 }, { } ),
$.jcoverflip.animationElement( el.find( 'img' ), { width: '400px' }, { } )
];
},
change: function(event, ui){
jQuery('#scrollbar').slider('value', ui.to*25);
}
});
jQuery('#scrollbar').slider({
value: 50,
stop: function(event, ui) {
if(event.originalEvent) {
var newVal = Math.round(ui.value/25);
jQuery( '#flip' ).jcoverflip( 'current', newVal );
jQuery('#scrollbar').slider('value', newVal*25);
}
}
});
});
you can also get it working by using different classes the use addclass() - removeClass() to toggle the effect works well if you're already familiar with CSS overrides
Try setting the position property of the elements to relative, otherwise they will be treated as static and ignore all settings to z-index.
It looks like the z-index in question should be applied to the <li>, not the <img>.
You can alter the z-index of an element by using the .css() function.
$("#elem").css('z-index','1000');
However, two better options would be to either define CSS classes for the elements you want to style and toggle between them, or use some nice jQuery slideshow plugins.
You can alter the inline CSS by selecting the element and using the css method
Suppose an element has no z-index, or a different one, and you want to change it to 5
$("#elementId").css('z-index', 5);
Another option is to set up classes with certain CSS styles before hand and change the class of certain elements ie (currentShown, nextUp, etc)
rather then waste your time reinventing the wheel why not just use a jquery slideshow plugin?
Z-index'ing the <li> instead of the <img> is the right solution to fix the overlap. However, because the <li>s are dynamic and flip before and after each other, an applied z-index to all in a sequential order from left-to-right will not solve his issue.
Solving the issue will need a few more actions to invoke within jquery but not too much extra work. What needs to happen is for jQuery to apply a z-index to the current <li> higher than the rest of the batch for each event on the slider.
Since I don't have access to your code, you basically want to apply the following logic:
Whatever <li> is in front it should have a z-index:1 and all other <li>s should have z-index:0. This should happen on every change in the slider.
#mcgrailm: Give him a break man, you can't learn how to swim unless you jump into the pool.

Javascript Smooth Glide?

I want to be able to move my element, El1, from (30,40) to (30,30) in 1000 milliseconds in a smooth animation. Is it even possible?
If you are not familiar to jQuery and if you don't want to use it and increase your page size by about 50kb just for some movements, I suggest you to use one of my functions:
function smooth(x, max){
return Math.floor((Math.sin((x/max*Math.PI)-(Math.PI/2))+1)*max/2);
}
and You need a code to move that element, something like this:
function process(LI){
LI = LI || Config.From;
LI++;
Left = smooth(LI, Config.To)
Config.Element.style.left = Left + 'px'
if (LI < Config.To)
setTimeout ("process("+LI+")", 10);
}
Config = {
Element: document.getElementById('El1'),
From: 0,
To: 400
};
process();
Try looking at the jquery libraries the animate function is exactly what you are looking for, and easy to implement.
Jquery is at http://jquery.com/
and the animate function specifically is at http://api.jquery.com/animate/
your code will look something like this
$('El1').animate({top: "-10px"}), 1000);
$("#moveme").animate({
top: "30px"
}, 1000);
Make sure there's an element with id="moveme" and css position: absolute

Is there any way to make two jQuery animations run (properly) simultaneously?

I have an event listener that calls two animation actions. Unfortunately their starts are staggered by a small amount (e.g. the first in the function starts first).
Does anyone know a way to properly sync them up?
Here's my code:
$("#nav ul li a").hover(
function(){
$(lastBlock).children("div").animate({width: "0px"}, { queue:false, duration:400, easing:"swing" });
$(this).children("div").animate({width: maxWidth+"px"}, { queue:false, duration:400, easing:"swing"});
lastBlock = this;
}
);
Because the first animation runs slightly before the second, it causes the overall width to become momentarily unequal, which looks a bit funky.
There was a recent disussion about this exact topic on the jQuery dev list. They created a few test cases you might wanna look at. Specially the Johns test.
Here's the discussion topic btw.
The trick is to have a single interval/callback in which all elements are updated.
You can find an example in my post here:
Can I implement a callback with each animation step in jQuery?
What you end up is basically:
var el1 = $("#element1");
var el2 = $("#element2");
var animation = new AnimationTimeline( {
easing: "swing"
, onstep: function( stepValue, animprops )
{
// This is called for every animation frame. Set the elements:
el1.css( { left: ..., top: ... } );
el2.css( { left: ..., top: ... } );
}
});
// And start it.
animation.start();

Categories

Resources