Parallax with Many Assets and Large One - javascript

I am trying to create a landing page that has a parallax effect. The problem is that when scrolling, the assets seem to move at less than 15 fps. In this performance, the parallax effect is not noticeable. The object inside the element bg_container is more than 10000px in height.
What is wrong with my code or is there a better implementation for this. This is the temporary site of my site: http://royvon.therookieblog.com/
Here the version 1 of my code in which the objects are moved within the window scroll event:
$(document).ready(function() {
var bg_speed = 0.7;
var tree_speed = 0.8;
var mid_speed = 0.8;
var fast_speed = 1.0;
$(window).scroll(function () {
var scrolled = $(window).scrollTop();
$('#bg_container').css('top',(0-(scrolled*bg_speed))+'px');
$('#map_1home_container').css('top',(0-(scrolled*bg_speed))+'px');
$('#map_2playGround_container').css('top',(0-(scrolled*bg_speed))+'px');
$('#map_3camp_container').css('top',(0-(scrolled*bg_speed))+'px');
//AND SOME 15 OBEJCTS HERE
});
});
Here is the version 2 of my code that uses setTimeout to move the assets:
$(document).ready(function() {
var scrollTimer = null;
$(window).scroll(function () {
if (scrollTimer) {
clearTimeout(scrollTimer); // clear any previous pending timer
}
scrollTimer = setTimeout(moveObjects, 25); // set new timer
});
});
function moveObjects() {
var bg_speed = 0.7;
var tree_speed = 0.8;
var mid_speed = 0.8;
var fast_speed = 1.0;
var scrolled = $(window).scrollTop();
$('#bg_container').stop(true, true).animate({'top':(0-(scrolled*bg_speed))+'px'}, 25);
$('#map_1home_container').stop(true, true).css({'top':(0-(scrolled*bg_speed))+'px'},25);
$('#map_2playGround_container').css('top',(0-(scrolled*bg_speed))+'px');
$('#map_3camp_container').css('top',(0-(scrolled*bg_speed))+'px');
//AND SOME other assets here
}
In version 2, I have tried changing the number in setTimeout. I also tried in version 2 changing the .css to .animate but the performance is still the same.
For version 1, Firefox and Chrome seems to display the parallax in less than 15fps but in internet explorer 9 and 10, it's very smooth.
I have tried viewing both versions in Chrome for android and the performance was catastrophic.
Is there something that can be done in this code? Or I just tell the client leave this idea?

Related

jQuery move background to follow element positioned using CSS Animations

I got an application where I'm moving an image around the page using CSS3 Animations the idea is you click a button and the next animation runs and this way the "sprite" moves around a map.
However on mobile I was asked to keep the size of the map the same as desktop but instead move the map instead of the sprite, my question is how can I make that work?
My current (really early) code looks like this:
$(document).on("boatAnimationStarted", function(event) {
window.isAnimating = true;
var boatElement = $("#boat-sprite");
var backgroundElement = $("#background");
var backgroundWidth = backgroundElement.width();
var backgroundHeight = backgroundElement.height();
var windowSize = { width: $(window).width(), height: $(window).height() };
var originalOffset = boatElement.offset();
window.animationInterval = setInterval(function() {
var boatOffset = boatElement.offset();
var working = {
top: originalOffset.top - (boatOffset.top / 2),
left: originalOffset.left - (boatOffset.left / 2),
}
$("#background").offset(working);
}, 10);
});
This does manage to move it somewhat but it doesn't seem to be exact and isn't really accounting for the offset of the #background element when it changes position.
So I'm guessing I should do everything relative to the Background image (which is around 1200w X 421h)
So to do that you would do something like this i'm guessing
var relativeOffset = {
top: boatOffset.top - backgroundElement.offset().top,
left: boatOffset.left - backgroundElement.offset().left
}
And I would in theory get the offsets of the sprite relative to the large background image as opposed to the mobile viewport. But then how would I go about moving the background?
Sorry if it's a simple question but it's the first time I've ever had to work with this kind of stuff so I'm a bit confused.

Animation (bound to scrollTop) only finishes when I stop scrolling

My animation event nearly pauses or lets say gets significantly slower at completing when scroll reaches more than 15 percent. Why is that? If should animate to the left but instead it does so only when I stop scrolling.
$(window).scroll(function ()
{
var content_height = $(document).height();
var content_scroll_pos = $(window).scrollTop();
var percentage_value = content_scroll_pos * 100 / content_height;
if(percentage_value > 15)
{
TweenMax.to(".bar", 3, {right:"0", ease:Bounce.easeOut})
}
else
{
TweenMax.to(".bar", 2, {right:"-125%", ease:Power2.easeOut})
}
});
Here a Demo of the solution with explaining comments:
// This gets called _every time_, you scroll a little bit ("every time" as in "every frame").
// So we introduce a new variable that acts as a filter and only lets the function trigger, once the status changes.
// 0 = not changed (it is, where it was on page loading)
// 1 = out of the screen
// 2 = back in the screen
var status = 0;
$(window).scroll(function ()
{
var content_height = $(document).height();
var content_scroll_pos = $(window).scrollTop();
var percentage_value = content_scroll_pos * 100 / content_height;
var newStatus = percentage_value > 15 ? 2 : 1;
if(newStatus == status)
return;
switch(newStatus) {
case 1:
TweenMax.to(".bar", 2, {right:"-125%", ease:Power2.easeOut});
break;
case 2:
// because this function got called all the time, the animation started all over again, each frame.
// And becase the animation starts slowly it stayed slow as long as the user scrolled.
TweenMax.to(".bar", 3, {right:"0", ease:Bounce.easeOut});
break;
}
status = newStatus;
});
.foo {
height: 2000px;
}
.bar {
background-color: red;
height: 50px;
width: 50px;
position: fixed;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="foo">
Test<br />
Test
<div class="bar">
</div>
</div>
By the way:
Because of the nasty per-frame thing, you can improve your performance significantly, if you do not calculate the value of $(document), $(document).height() and $(window) inside that function. I would suggest, scoping all of this code in a wrap like
(function() {
var jDocument = $(document),
content_height = jDocument.height(),
jWindow = $(window),
status = 0;
// [CODE HERE, using jWindow instead of $(window)]
})();
Which also solves the problem, that status would either need a long and complicated name otherwise or would be in danger of getting overwritten by the code of anybody else.
PS: I have to admit, that I don't like your animation in the current state. It bounces too much for me - even that much too much, that I can not see it bouncing at all. To me it seemed like it appeared and disappeared, the first time, I saw it.

Decrease image size automatically over a certain amount of time

I am looking for a script but I'm not sure what to look for.
I have a webpage that has the body tag with a background image.
body {
background: url(eye.gif)repeat;
background-size:91px 91px;
}
What I am hoping to achieve is when the page loads it shows the background image as 991px then slowly decrease by 10px over a set time until the original size of 91px.
I'm not sure if there is away to do this, or even another way that when the page is loaded it is zoomed in and then zooms out automatically over time.
Basically when the page is loaded you will see the image twice and then over time you will see more and more.
Can anyone point me in the right direction.
if you use background-size your using css3 and so you can use keyframes
no javascript needed.
#-webkit-keyframes bganimation{
0%{background-size:991px 991px;}
100%{background-size:91px 91px;}
}
body{
background: url(eye.gif)repeat;
background-size:91px 91px;
-webkit-animation:bganimation 20s linear; // 20s = 20 seconds
}
for more support you need to add the other specific prefixes (-moz,-ms..)
Here is a sample using JQuery:
http://jsfiddle.net/frUvf/16/
$(document).ready(function(){
$('body').animate({'background-size':'10000px'}, 50000);
})
Using vanilla JS:
var lowerBound = 250,
step = 10,
duration = 1000,
image = document.getElementById('image');
(function resizer () {
if (image.clientWidth > lowerBound) {
image.style.width = image.clientWidth - step + 'px';
var timer = setTimeout(resizer, duration);
} else {
clearTimeout(timer);
}
}());
Just change the lowerBound/step/duration variables to whatever you need them to be.
Fiddle
with jquery:
var body = $('body');
var zoom = 2;
var interval_zoom = 0.5;
var time_interval = 90000;
setInterval(function(){
body.css("zoom", zoom);
zoom = zoom - interval_zoom;
if(zoom<=1)
clearTimeout(this);
}, time_interval )
Zoom and interval must be calculated
You could use Javascript for the animation or could take a look at CSS3 Transformations: http://web.archive.org/web/20180414114433/http://www.pepe-juergens.de/2013/02/css3-transform/

Fixing Jank on Movement locked to Scroll on Android

I am creating a header that acts like the Chrome for Android Address bar. The effect is that the header is a pseudo sticky header that scrolls out of view as you scroll down and then you you begin to scroll back up the header scrolls back into view.
Right now it works fine on the desktop (around 60fps) but on Chrome for Android (on Nexus 7 2013) it is full of jank.
Demo: jsFiddle
Both the header and content area are moved with transform translateY which are more performant than pos:top
I am also using requestAnimationFrame to debounce scrolling and only change properties when it is most convenient for the browser.
The header is position: fixed; top: 0; and then scrolled in and out of view with transform: translateY(...);. Also instead of using margin-top to get the content out from underneath the header, I am using transform: translateY(...);
The basic structure of my js looks like:
var latestScrollTop = 0;
var lastReactedScrollTop = 0;
var ticking = false;
function DoScroll()
{
var builtUpScrollTop = latestScrollTop - lastReactedScrollTop;
// Fold the top bar while we are scrolling (lock it to scrolling)
$('header.main-header').css('transform', 'translateY(' ... 'px)');
HeaderHeightChange();
lastReactedScrollTop = latestScrollTop;
ticking = false;
}
function HeaderHeightChange()
{
// We need to update the margin-top for the content so we don't overlap it
$('main.content-area').css('transform', 'translateY(' ... 'px)');
}
function requestTick() {
if(!ticking) {
requestAnimationFrame(function(){
DoScroll();
});
}
ticking = true;
}
$(window).on('scroll', function(e) {
latestScrollTop = $(window).scrollTop();
requestTick();
});
The effect is not complete as it needs to resolve the fold after you finish scrolling (and is coded) but I do not want to complicate the issue when just the scroll movement lock to header is causing jank. I see paint rectangles when scrolling up and down even though I am changing transform which I assume the gpu is handling and shouldn't be painting.
Edit: It seems when debugging with ADB that there is a a bunch of clear grey outlined time in each frame.
Turns out that even though I was using transform: translateY() that you still need to add translateZ(0) to see the benefit of layers and having it gpu accelerated.
But I did also update my code to use a object literal code style and got rid of the forced synchronous layout warning in the timeline by reading then writing. This is coupled along with requestAnimationFrame.
Demo: jsFiddle
var myUtils = {
clamp: function(min, max, value) {
return Math.min(Math.max(value, min), max);
},
getTranslateYFromTransform: function(rawTransform) {
return parseFloat(rawTransform.match(/^matrix\((([+-]?[0-9]*\.?[0-9]*),\s*?){5}([+-]?[0-9]*\.?[0-9]*)\)$/)[3])
}
};
var scrollHeader = {
latestScrollTop: 0,
lastReactedScrollTop: 0,
headerHeight: 0,
headerTransformTranslateY: 0,
ticking: false,
requestTick: function() {
if(!scrollHeader.ticking) {
requestAnimationFrame(function(){
scrollHeader.doHeaderFold();
});
}
scrollHeader.ticking = true;
},
doHeaderFold: function() {
var header = $('header.main-header');
var builtUpScrollTop = scrollHeader.latestScrollTop - scrollHeader.lastReactedScrollTop;
scrollHeader.headerHeight = header.outerHeight();
scrollHeader.headerTransformTranslateY = myUtils.clamp(-parseInt(scrollHeader.headerHeight), 0, (myUtils.getTranslateYFromTransform(header.css('transform')) - builtUpScrollTop));
// Fold the top bar while we are scrolling (lock it to scrolling)
header.css('transform', 'translateY(' + scrollHeader.headerTransformTranslateY + 'px) translateZ(0)');
scrollHeader.headerHeightChange();
scrollHeader.lastReactedScrollTop = scrollHeader.latestScrollTop;
scrollHeader.ticking = false;
},
headerHeightChange: function() {
// We need to update the margin-top for the content so we don't overlap it
$('main.content-area').css('transform', 'translateY(' + (scrollHeader.headerHeight + scrollHeader.headerTransformTranslateY) + 'px) translateZ(0)');
}
};
$(window).on('scroll', function(e) {
//console.log(e);
scrollHeader.latestScrollTop = $(window).scrollTop();
scrollHeader.requestTick();
});
This makes the timeline debugging on ADB (Nexus 7 2013) look like(very smooth):
Also to get rid of a small jump when first scrolling add transform: translateZ(0) to your element before animating it.

smooth auto scroll by using javascript

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);

Categories

Resources