Controlling a Lottie Animation with ScrollMagic and TimelineMax - javascript

I'm trying to use ScrollMagic to control a TimelineMax which moves the playhead of a Lottie animation.
So, as the user scrolls, the animation plays relative to the speed and direction of the scroll. I'm so close and need a little help to bring the effect home.
First, I include my Libraries
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.5.9/lottie.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/animation.gsap.js"></script>
Then...
// init scrollmagic
var controller = new ScrollMagic.Controller();
Now, the animation setup...
// Manage Animation
var animation = bodymovin.loadAnimation({
container: document.getElementById('lottie'), // Required
path: '/static/animations/animation.json', // Required
renderer: 'svg', // Required
loop: false, // Optional
autoplay: false, // Optional
name: "Welcome to Awesomeness", // Name for future reference. Optional.
});
This is where I'm struggling:
// Setup Timeline
var lottieControl = new TimelineMax({ repeat: -1, yoyo: true }); // <-- don't loop and let the timeline go back and forth
lottieControl.to({ frame:0 }, 1, { // <-- is this right? I'm telling the timeline to start at frame 0
onUpdate:function(){
animation.goToAndStop(Math.round(this.target.frame), true) // <-- move the playback head of the animation to the target frame that has been rounded and use frames not time (true)
},
ease:Linear.easeNone
})
Finally, bring it all back together...
// Attach to scroll
var lottieScene = new ScrollMagic.Scene({
duration: '80%',
offset: 1
})
.setPin("#header-scroll")
.setTween(lottieControl)
.addTo(controller);
For the life of me, I can't see if I'm using the goToAndStop method right or not. Thanks for your time.

After hours of testing I found the answer. I was looking at the wrong thing. I needed to tie the timeslines progress to the frame to go to. In this instance, there are 300 frames, thus the multiplication by the number of frames in the animation.
Here's the revised code:
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.5.9/lottie.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/animation.gsap.js"></script>
<script>
// init scrollmagic
var controller = new ScrollMagic.Controller();
// Manage Animation
var animation = bodymovin.loadAnimation({
container: document.getElementById('lottie'), // Required
path: '/static/animations/scroll_animation.json', // Required
renderer: 'svg', // Required
loop: false, // Optional
autoplay: false, // Optional
name: "Welcome to Awesomeness",
});
// Setup Timeline
var tl = new TimelineMax();
tl.to({frame:0}, 1, {
frame: animation.totalFrames-1,
onUpdate:function(){
animation.goToAndStop((Math.round(this.progress() * 300)), true)
},
ease: Linear.easeNone
})
// Attach to scroll
var lottieScene = new ScrollMagic.Scene({
duration: '100%',
offset: 1
})
.setPin("#header-scroll")
.setTween(tl)
.addTo(controller);
</script>

Related

Animation disappears on end LottieJS

I have an animation build with LottieJS which loops like:
var lottieLogo = lottie.loadAnimation({
container: document.getElementById('icon_logo'), // the dom element that will contain the animation
renderer: 'svg',
loop: true,
autoplay: false,
path: 'path-to-json'
});
lottieLogo.play();
Then after animation is done I want to pause for 10 seconds like:
function logoAnimation() {
lottieLogo.pause();
setTimeout(
function()
{
lottieLogo.play();
}, 10000);
}
lottieLogo.addEventListener('loopComplete', logoAnimation);
It works fine but the only problem is that the animation disappears for about 0.2 seconds every time it loads again. Anyone familiar with this problem?
If you set loop to false it should give you the desired effect.

Using Bodymovin and Scrollmagic to animate as you scroll

I am using Bodymovin in combination with ScrollMagic and GSAP to animate through series of images as you scroll back and forth. Everything works great, except, when I reach the end it doesn't stay on the final image, but goes white.
Libraries that I load first:
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.5.9/lottie.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/animation.gsap.js"></script>
Then my code:
var controller = new ScrollMagic.Controller();
var animation = bodymovin.loadAnimation({
container: document.getElementById('hero-anim'),
animationData: animationframes,
renderer: 'svg',
autoplay: false,
});
var tl = new TimelineMax();
tl.to({frame:0}, 1, {
frame: animation.totalFrames-1,
onUpdate:function(){
animation.goToAndStop((Math.round(this.progress() * 60)), true)
},
ease: Linear.easeNone
})
var lottieScene = new ScrollMagic.Scene({
duration: '100%',
offset: 600
})
.setPin("#hero-anim")
.setTween(tl)
.addTo(controller);
Any ideas what could be causing that? Looking at browser's Inspect Element, it basically adds display:block to the image that is supposed to be currently visible and applies display:none to the previous image, but at the end, they all have display:none, and it doesn't stay visible
RESOLVED
As Zach pointed out, I tried Math.floor and at first it didn't help, but afterwards I tried adjusting animation.goToAndStop((Math.floor(this.progress() * 60)), true) to * 59 (one frame less than the total frame count and now it works, perfectly. Math.round with * total frame count or even * total frames - 1 didn't work, strangely.

ScrollMagic pin spacer too large

I'm new to ScrollMagic so not sure if there's something obvious that I'm overlooking.
I've set up a codepen which illustrates what I'm trying to achieve, and an alternative version that almost does what I want, except there's a huge gap that I can't seem to get rid of.
Essentially looking to have 3 slides that are stacked on top of each other. When the user scrolls, the slides one-by-one transition up to reveal the one underneath.
When scrolling past the final slide, the remaining content on the page should scroll up as if it's attached to the bottom of the final slide, and should from then on function like a normal page.
Currently, the container with all the slides in it transparently overlaps the rest of the body content until the final slide has disappeared off the top of the viewport, and it's ScrollMagic that is doing this.
The pink bar in the codepen is intended to show where the bottom of the slide container finishes.
Here's the relevant code:
function initController() {
controller = new ScrollMagic.Controller({
globalSceneOptions: {
triggerHook: "onLeave"
}
});
controller.scrollTo(function(pos) {
TweenMax.to(window, 1, {
scrollTo: {
y: pos,
autoKill: true
}
});
});
}
function initAnimation() {
wipeAnimation = new TimelineMax();
$.each(ui.slides, function(i, slide) {
wipeAnimation
.add(TweenMax.to(slide, 2000, {y: '0'}))
.add(TweenMax.fromTo(slide, 5000, {y: '0'}, {
y: '-100%',
onComplete: function() {
if (i < ui.slideCount - 1) { // don't run on last slide
updateActiveSlide(ui.slides[i + 1]); // activate next slide
}
},
onReverseComplete: function() {
updateActiveSlide(slide);
}
}));
});
}
function initScene() {
scene = new ScrollMagic.Scene({
triggerElement: ui.el,
duration: '100%'
})
.setTween(wipeAnimation)
.setPin(ui.el, {
pushFollowers: false
})
.addTo(controller);
}
This is designed by default to stop the pinned elements overlapping the following elements in the document.
You need set the 'pushFollowers' property to false:
function initScene() {
scene = new ScrollMagic.Scene({
triggerElement: ui.el,
duration: '100%'
})
.setTween(wipeAnimation)
.setPin(ui.el, {
pushFollowers: false
})
.addTo(controller);
}
See documentation: http://janpaepke.github.io/ScrollMagic/docs/ScrollMagic.Scene.html#setPin
// pin element and push all following elements down by the amount of the pin duration.
scene.setPin("#pin");
// pin element and keeping all following elements in their place. The pinned element will move past them.
scene.setPin("#pin", {pushFollowers: false});
Working example: https://codepen.io/alexgill/pen/MyOMKP (forked from your codepen)

Make Slide in Animation JavaScript and HTML

How would one make a slide and fade in animation like in seen in the green and pink boxes on sharethis.com? In particular I like the one in the blue box with the arrows. Are there a set of JavaScript codes or CSS effects?
The easiest would probably be to use a library like this:
http://janpaepke.github.io/ScrollMagic/
I see that for the arrows effect the css-height property is animated when you scroll. This is done in javascript. But you can also achieve this effect through CSS3-transitions.
Update: Slide and wipe effects from the demo page:
// ani
var pinani = new TimelineMax()
// wipe
.add(TweenMax.to("#wipe", 1, {
width: "100%"
}))
// slide
.add(TweenMax.to("#slide", 1, {
top: "0%",
ease: Bounce.easeOut,
delay: 0.2
}));
// pin
new ScrollScene({
triggerElement: "section#pin",
duration: 1100
})
.on("progress", function () {
// keep centered even though width changes
$("#wipe h3").width($("#pin>h3").width());
})
.setTween(pinani)
.setPin("section#pin")
.addTo(controller);

How to stop Spin.js from other js file

i need help
Actually in my work i need to implement spin.js and block UI in a jqgrid. This is ok when i put the code in the same file and function, but i want to call a method from other JS file, and hear is where my problem. The spin.js and block UI start, then block UI stop with unblock but the spin.js still running.
Here is my code:
In BeforeRequest() in jqgrid i call one method
$.pui.common.loaderAnimationON("pane-content");
this method have this code
loaderAnimationON: function (div) {
var opts = {
lines: 13, // The number of lines to draw
length: 20, // The length of each line
width: 10, // The line thickness
radius: 30, // The radius of the inner circle
corners: 1, // Corner roundness (0..1)
rotate: 0, // The rotation offset
direction: 1, // 1: clockwise, -1: counterclockwise
color: '#000', // #rgb or #rrggbb or array of colors
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false, // Whether to use hardware acceleration
className: 'spinner', // The CSS class to assign to the spinner
zIndex: 2e9, // The z-index (defaults to 2000000000)
top: '50%', // Top position relative to parent in px
left: '50%' // Left position relative to parent in px
};
var target = document.getElementById(div);
var spinner = new Spinner(opts).spin(target);
$.blockUI({
blockMsgClass: "gridProjectsLoader",
message: null
});
return spinner;
},
in gridComplete() i call other method
$.pui.common.loaderAnimationOFF("pane-content");
this method have this code
loaderAnimationOFF: function (div) {
var target = document.getElementById(div);
var spinner = $.pui.common.loaderAnimationON();
spinner.stop(target);
$.unblockUI();
}
Anyone can help me?
Thanks guys
You should use the same object to start and stop it. You can use global variables anywhere (just another .js)
Check this jsFiddle. It's stop spinner after 3 secs.
http://jsfiddle.net/YX7dy/8/
spinner=loaderAnimationON('Spin');
setInterval(function(){spinner.stop();},3000);

Categories