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.
Related
I want a Scroll-Based Animation with image sequences like this:
https://www.wayoutintl.com/
when visit above link ,see section-3 when we scroll down, beach image move from day to night. This animation seems scroll smoothly. my animation scroll smoothly on local and when i put same code on server,sequences images choppy on scroll. not smoothly work on scroll. So what should i do now ? Please help me ..... thanks in advance.... below is my code....
// define images
var images = [
"imgs/0001/0001-compress2.jpg",
"imgs/0001/0002-compress2.jpg",
"imgs/0001/0003-compress2.jpg",
"imgs/0001/0004-compress2.jpg",
"imgs/0001/0005-compress2.jpg",
"imgs/0001/0006-compress2.jpg",
"imgs/0001/0007-compress2.jpg",
"imgs/0001/0008-compress2.jpg",
"imgs/0001/0009-compress2.jpg",
"imgs/0001/0010-compress2.jpg",
"imgs/0001/0011-compress2.jpg",
"imgs/0001/0012-compress2.jpg",
"imgs/0001/0013-compress2.jpg",
"imgs/0001/0014-compress2.jpg",
"imgs/0001/0015-compress2.jpg",
"imgs/0001/0016-compress2.jpg",
"imgs/0001/0017-compress2.jpg",
"imgs/0001/0018-compress2.jpg",
"imgs/0001/0019-compress2.jpg",
"imgs/0001/0020-compress2.jpg",
"imgs/0001/0021-compress2.jpg",
"imgs/0001/0022-compress2.jpg",
"imgs/0001/0023-compress2.jpg",
"imgs/0001/0024-compress2.jpg",
"imgs/0001/0025-compress2.jpg",
"imgs/0001/0026-compress2.jpg",
"imgs/0001/0027-compress3.jpg",
"imgs/0001/0028-compress3.jpg",
"imgs/0001/0029-compress3.jpg",
"imgs/0001/0030-compress3.jpg",
"imgs/0001/0031-compress3.jpg",
"imgs/0001/0032-compress3.jpg",
"imgs/0001/0033-compress3.jpg",
"imgs/0001/0034-compress3.jpg",
"imgs/0001/0035-compress3.jpg",
"imgs/0001/0036-compress3.jpg",
"imgs/0001/0037-compress3.jpg",
"imgs/0001/0038-compress3.jpg",
"imgs/0001/0039-compress3.jpg",
"imgs/0001/0040-compress3.jpg",
"imgs/0001/0041-compress3.jpg",
"imgs/0001/0042-compress3.jpg",
"imgs/0001/0043-compress3.jpg",
"imgs/0001/0044-compress3.jpg",
"imgs/0001/0045-compress3.jpg",
"imgs/0001/0046-compress3.jpg",
"imgs/0001/0047-compress3.jpg",
"imgs/0001/0048-compress3.jpg",
"imgs/0001/0049-compress3.jpg",
"imgs/0001/0050-compress3.jpg",
"imgs/0001/0051-compress3.jpg",
"imgs/0001/0052-compress3.jpg",
"imgs/0001/0053-compress3.jpg",
"imgs/0001/0054-compress3.jpg",
"imgs/0001/0055-compress3.jpg",
"imgs/0001/0056-compress3.jpg",
"imgs/0001/0057-compress3.jpg",
"imgs/0001/0058-compress3.jpg",
"imgs/0001/0059-compress3.jpg",
"imgs/0001/0060-compress3.jpg",
"imgs/0001/0061-compress3.jpg",
"imgs/0001/0062-compress3.jpg",
"imgs/0001/0063-compress3.jpg",
"imgs/0001/0064-compress3.jpg",
"imgs/0001/0065-compress3.jpg",
"imgs/0001/0066-compress3.jpg",
"imgs/0001/0067-compress3.jpg",
"imgs/0001/0068-compress3.jpg",
"imgs/0001/0069-compress2.jpg",
"imgs/0001/0070-compress3.jpg",
"imgs/0001/0071-compress3.jpg",
"imgs/0001/0072-compress2.jpg",
"imgs/0001/0073-compress3.jpg",
"imgs/0001/0074-compress3.jpg",
"imgs/0001/0075-compress3.jpg",
"imgs/0001/0076-compress2.jpg",
"imgs/0001/0077-compress2.jpg",
"imgs/0001/0078-compress2.jpg",
"imgs/0001/0079-compress3.jpg",
"imgs/0001/0080-compress3.jpg"
];
// TweenMax can tween any property of any object. We use this object to cycle through the array
var obj = {curImg: 0};
// create tween
var tween = TweenMax.to(obj, 0.5,
{
curImg: images.length - 1, // animate propery curImg to number of images
roundProps: "curImg", // only integers so it can be used as an array index
repeat: 0, // repeat 3 times
immediateRender: true, // load first image automatically
ease: Linear.easeNone, // show every image the same amount of time
onUpdate: function () {
$("#myimg").attr("src", images[obj.curImg]); // set the image source
}
}
);
// init controller
var controller = new ScrollMagic.Controller();
// build scene
var scene = new ScrollMagic.Scene({triggerElement: "#trigger", duration: 800})
.setTween(tween)
.addTo(controller);
<div class="image-seq">
<section class="demo">
<div class="spacer s0" id="trigger"></div>
<div id="imagesequence">
<img id="myimg" class="lazy"/><br>
</div>
</section>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.16.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/ScrollMagic.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.min.js"></script>
<script type="text/javascript" src="js/as.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.7/jquery.lazyload.js"></script>
</body>
When you scroll, you are queuing up the images (maybe many) to be loaded on the next requestAnimationFrame which is why it works ok on local, but not when on a server.
Some of the images are fairly large (the stadium ones are around 150kB each, and you seem to have over 300 of them). The total page size is around 65MB.
Things to try:
Preload the images before initializing the scroller.
Reduce the amount of images and maybe their size.
Try using webP images to reduce their size.
Use vanilla JS to set the image source instead of jQuery.
Use the browser dev tools (network and performance tabs) to check where you bottlenecks are. It might be helpful to set the throttling to 3g so you can test performance on your local version.
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>
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)
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);
I have my Index.cshtml view, and for some reason, the JQuery is having a hard time firing the jqFancyTransitions method (it's acting as if the jqFancyTransitions library isn't included). The JavaScript IS firing though. For testing, I even put $('#rotatingImages').html('blah'); to see if it would find my ID and replace it's HTML contents, but it didn't.
I do get a JS error in my Firebug console: TypeError: $(...).jqFancyTransitions is not a function. Yet, I get jqFancyTransitions intellisense after I type a dot at the end of the parenthesis.
EDIT:
The jqFancyTransitions.js library IS in fact being loaded into the browser according to Firebug. To test it out, I removed the reference to it, and then I didn't see the library was loaded. I added it back in to my view, and I see it.
Here's the code on Index.cshtml:
<script src="~/Scripts/jqFancyTransitions.1.8.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#rotatingImages').jqFancyTransitions({
effect: 'wave', // wave, zipper, curtain
width: 959, // width of panel
height: 300, // height of panel
strips: 20, // number of strips
delay: 4000, // delay between images in ms
stripDelay: 50, // delay beetwen strips in ms
titleOpacity: 0.7, // opacity of title
titleSpeed: 1000, // speed of title appereance in ms
position: 'alternate', // top, bottom, alternate, curtain
direction: 'fountainAlternate', // left, right, alternate, random, fountain, fountainAlternate
navigation: false, // prev and next navigation buttons
links: false // show images as links
});
// $('#rotatingImages').html('blah'); // just for testing
});
</script>
<div id="rotatingImages">
<img src="Images/Background/bg1.jpg" />
<img src="Images/Background/bg2.jpg" />
<img src="Images/Background/bg3.jpg" />
<img src="Images/Background/bg4.jpg" />
</div>
Any ideas what's going on?
I believe your JavaScript reference needs to be changed to
<script src="#Url.Content("~/Scripts/jqFancyTransitions.1.8.js")"></script>
for Razor ViewEngine, or
<script src="<%=Url.Content("~/Scripts/jqFancyTransitions.1.8.js")%>"></script>
for WebForms ViewEngine.
Real simple. All I had to do was include my scripts in a "scripts" section inside the view I was working in, which was Index.cshtml, as follows:
#section scripts
{
#Scripts.Render("~/bundles/fancyTransitions")
<script type="text/javascript">
$(document).ready(function () {
$('#rotatingImages').jqFancyTransitions({
effect: 'wave', // wave, zipper, curtain
width: 959, // width of panel
height: 300, // height of panel
strips: 20, // number of strips
delay: 4000, // delay between images in ms
stripDelay: 50, // delay beetwen strips in ms
titleOpacity: 0.7, // opacity of title
titleSpeed: 1000, // speed of title appereance in ms
position: 'alternate', // top, bottom, alternate, curtain
direction: 'fountainAlternate', // left, right, alternate, random, fountain, fountainAlternate
navigation: false, // prev and next navigation buttons
links: false // show images as links
});
});
</script>
}
I thing u forgot to link jQuery library on the top. before
<script src="~/Scripts/jqFancyTransitions.1.8.js"> </script>