Smooth translation on mouse move - javascript

I'm trying to make 3D layer effect like on this page:
Example Page:
http://cloudraiders.com/
I did almost everything, but have one big problem that can't handle:
$("#mainView").mousemove(function( event ) {
//getting mouse dimentions
var pageX = event.pageX;
var pageY = event.pageY;
var mainWidth = $(this).width();
var mainHeight = $(this).height();
//
//console.log(pageX);
("#mainView").find("li").each(function( index ) {
var depth = $(this).attr("dataDepth");
var scalable = $(this).attr("scalable");
var x = pageX*depth;
var y = pageY*depth;
var z = 0;
var thisScale = mainWidth / mainHeight * 1;
//setting accelerated webkit transform
$(this).css("-webkit-transform", "translate3d("+x+"%,"+y+"%,"+z+"px"+")");
});
});
The problem is, that translate3d is not smooth like in example page. It is jumping.
When I'm moving mouse out of the window, and then enter in different place it is just jumping.
I'v found some solution in forum already, but didn't work to good with mouse move.
Any help will be a lot appreciated.
Regards!
EDIT:
I'v used Jquery animate function:
$(this).animate({ whyNotToUseANonExistingProperty: 100 }, {
step: function(now,fx) {
$(this).css('-webkit-transform',"translate3d("+x+"%,"+y+"%,"+z+"px"+")");
},
duration:100
},'linear');
It works almost good, but the problem is, that Jquery is stacking queries. And if I will move mouse alot, animations goes on like for minute.

When dealing with css animation/transformation, there is some performance trickt bear in mind. one of them is to set a default transform value (set to 0) in order to enable the rendering those element by default.
Try addind those rule as default in your css to your animated element ("li" in your case):
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
Also, note that the website linked in your answer use the jquery parallax plugin, which take care of those accelerations issues for you.
And here some ressource about css transform/animation acceleration:
Increase Your Site’s Performance with Hardware-Accelerated CSS
DOM, HTML5, & CSS3 Performance
Related stackoverflow question

If you expect soft transition you should tell it somewhere to the browser. Just add this style and customize it. Do it in the style-sheet not inside your evented JavaScript. Handle all the prefixes.
#mainView{
transition:all 0.5s ease-in;
}

Related

repeatable marquee that's optional based on text width

I've spent most of my morning trying to resolve how to create a scrolling marquee on an Angular app; my goal is when the dynamic text is longer than its viewport, it will scroll (repeating, meaning you don't have to wait for the entire title to scroll off the page before you see it again) but when it's short enough to display without being cut off in the viewport width, it does not scroll.
I like examples I'm seeing but need to combine them somehow and I am very beginner when it comes to adding any kind of javascript.
One is using jQuery and marquee:
$('.marquee').marquee({
duplicated: true
});
This one is great because it repeats the text and continues without it having to completely leave the screen to start again. But, my trouble comes when trying to figure out a way to add in javascript to figure out how wide that text will be; either to have it be static or scroll.
For some reason, I am unable to understand how to link to codepen or jsfiddle of the examples I've found that hit close to home. Hoping my inquiry above is enough information. I know commenters can be a bit rough—please be patient with me.
You could use text-shadow(to clone text) and animation if it is only about text.
JS will be necessary to get the width(from text lenght) of the piece to scroll and to update/insert css rule's values.
example inspired from your jsfiddle
function isElementOverflowing(element) {
var overflowX = element.offsetWidth < element.scrollWidth,
overflowY = element.offsetHeight < element.scrollHeight;
return (overflowX || overflowY);
}
// below css updated and injected . can be shorten and nicely rewritten
var element = document.getElementById('ov1');
if (isElementOverflowing(element)) {
var toscroll = element.scrollWidth;
element.style.textShadow = toscroll + 'px 0 ';
element.style.animation = 'marqueeme 5s infinite linear';
var csstyle = document.createElement('style');
csstyle.innerText = '#keyframes marqueeme {100%{ text-indent:-' + toscroll + 'px;}}';
element.appendChild(csstyle)
}
#marquee {
max-width: 15em;
overflow: hidden;
}
#ov1 {
white-space: nowrap;
margin: 0;
}
<div id="marquee">
<p id="ov1">
Yadda yadda overflowing text this line is too long oh noes!
</p>
</div>
example here is using text-indent within the animation, but negative margin-left or translateX will do the same visual.
Another example with
a text-shadow of different color
transform to see it working instead text-indent.
It also sets speed according to text length
# https://codepen.io/gc-nomade/pen/owPNZg

Css3 transition queue

I am trying to queue css transition with same properties. Basically I want to translate an element to certain position (so transition duration 0) before I make another translate.
This is a mockup, click on move (box should move 100px right, before translate 100px left)
this doesnt work because second transition overwrites first?
https://jsfiddle.net/aqwaypoh/3/
This works (I needed transition duration non zero (0.01) otherwise transitionend doesnt fire).
https://jsfiddle.net/dpv3xzth/5/
There is another problem that transition end fires 2 times on chrome, but I could fix that, I was just wondering is there a better way to write this?
I would prefer if I could write this without end event or timer if possible?
<div class="box"></div>
move</a>
Update:
You can use CSS3 animation property with #keyframes.
.box.animate {
animation: move 2s;
}
#keyframes move {
0% {
transform: translate(100px);
}
100% {
transform: translate(0px);
}
}
And to make the box move you can add class animate to your element. Or you can set animation property yourself in javascript, it's up to you.
box.addClass('animate')
jsfiddle: https://jsfiddle.net/aqwaypoh/7/
Adding a timeout on the second condition gives you what you want I believe.
var box = $('.box'),
move = $('.move').click(function() {
box.css({
"transform": "translate(100px)",
'transition-duration': '0s'
});
setTimeout(function(){
box.css({
"transform": "translate(0px)",
'transition-duration': '0.5s'
});
}, 1);
})

How to get the core part - that does the trick - of parallax work?

I tried to experiment with parallax and started from scratch to understand the core parts of this magic. To give you an example that I like to use as inspiration, you can see it at this link here at the "Photos" section.
Latest code is down the page with related information. To get an overall look of the question see the rest of the details.
Core parts I already know are the scrollTop() of the $window and the offsetTop of the element are important to apply the parallax effect on a DOM element as well as a factor for how sensitive the effect should be respond to the scroll speed. The end result should be some formule that will calculate the translateY or translate3d coordinates in pixels or percentage.
I read on the internet that the CSS property translate is faster than, for example, top from position: absolute, and my preference would be also to use translate in combination with TweenMax GSAP. So the movement of the parallax will be very smooth. But if only the css property translate is enough that's fine too. I saw some examples that where using TweenMax, so that's why I use it for now.
JS
I have code the basic things:
var win = $(window);
var el = $('#daily .entry').find('figure');
win.scroll(function() {
var scrollTop = win.scrollTop();
var parallaxFactor = 5;
el.each(function() {
var image = $(this).find('img');
var offsetTop = $(this).offset().top;
// This is the part where I am talking about.
// Here should be the magic happen...
});
});
So I've code above code, but it doesn't do anything, of course. See CodePen from above code here. It will only console log scrollTop and offsetTop. As mentioned before, I only know the core parts like scrollTop and offsetTop to apply the parallax effect. Then there should be some area created where the parallax effect will be triggered and happen, so calculations will be only done for elements within the viewport in order to keep the performance good. After that there should be some math done, but doesn't know exactly what or how to achieve this. Only after I have a final number, I could use it within for example TweenMax from Greensock like so:
TweenMax
TweenMax.to(image, 0.1, {
yPercent: offsetPercent + '%',
ease: Linear.easeNone
});
Parallax formula
If I look around to get the formula down I came to something like this (founded on the internet):
var viewportOffset = scrollTop - offsetTop + win.height();
var offsetPercent = ((viewportOffset / win.height() * 100) - 100) / parallaxFactor;
if (viewportOffset >= 0 && viewportOffset <= win.height() * 2) {
TweenMax.to(image, 0.1, {
yPercent: offsetPercent + '%',
ease: Linear.easeNone
});
}
But if I am honest, I doesn't know what this does exactly, or why it should/could be this way. I would like to know this, so I can understand the whole process of making parallax happen. The functions of scrollTop(), offsetTop and $(window).height() are clear for me, but what the trick behind the formula is, is the part that I doesn't understand.
Updates
Update 1
#Scott has notified that the inspiration site uses a plugin called scrollmagic.io, but I am very curious about how I can create a parallax by myself without the use of a plugin. How it works and how to achieve it. With emphasis on the formula, why I should it do this or that way and what exactly will be calculated, because I don't understand it and really wanna know this, so that I can use this knowledge in the future when applying a parallax effect.
Update 2
I tried to figure out what the following code snippet exactly does. I talking about this one:
var viewportOffset = scrollTop - offsetTop + win.height();
After some good debug sessions I think that I've the clue. So scrollTop is the amount of pixels that you've scrolled down the page and that are hidden from the view. offsetTop is the start position of the element within the DOM and $(window).height is the viewport height - the part that is visible in the browser -.
This is what I think that this formula does:
Set the zero point to the point where the element starts. For example, when scrollTop is equal to 0 and the element starts at 240px from the top, then the formula is: 0 minus 240 is -240. So the current scroll position is below zero point. After scrolling 240px down, the formula will output 0 because of course 240 minus 240 is 0 (zero). Am I right?
But the part that I doesn't understand yet is why + win.height.
If we go back to above formula (at Update 2) and scrollTop is zero then the $(window).height is the space from 240px till the bottom of the viewport. When scrolling down, the amount of pixel will grow on scroll, that makes no sense to me. If someone can explain what could have been the purpose of this would be fine. 'm very curious. The second part of the formula to calculate the parallax offsetPercent I still don't understand. In general the calculation of the parallax strength on scroll.
Update 3 / 4
Advised by #Edisoni, I walked the last few days by the videos of Travis Neilson and I have become a lot wiser on the basic functionalities of parallax. A must for everyone who wants to dig in parallax. I've used the new knowledge about parallax to get my above script work:
var root = this;
var win = $(window);
var offset = 0;
var elements = $('#daily .entry figure');
if (win.width() >= 768) {
win.scroll(function() {
// Get current scroll position
var scrollPos = win.scrollTop();
console.log(scrollPos);
elements.each(function(i) {
var elem = $(this);
var triggerElement = elem.offset().top;
var elemHeight = elem.height();
var animElem = elem.find('img');
if (scrollPos > triggerElement - (elemHeight / 2) && scrollPos < triggerElement + elemHeight + (elemHeight / 2)) {
// Do the magic
TweenMax.to(animElem, 0.1, {
yPercent: -(scrollPos - elemHeight / 2) / 100,
ease: Linear.easeNone
});
} else {
return false;
}
});
});
}
However, the script works only for a certain part of the elements. The problem is that it only works for the first two elements. I have a suspicion that the "error" is located in particularly after the AND && sign in the if statement, but can't get the error solved. http://codepen.io/anon/pen/XKwBAB
When the elements, that work on the trigger are animated, they will be jumping some pixels to the bottom, don't know how to fix this to.
The jumping to: 1.135%, after the trigger is fired. So it doesn't start at 0%. I already checked if I should add the CSS property translate to the CSS and set the type of number to %, but this doesn't work for me.
-webkit-transform: translateY(0%);
-moz-transform: translateY(0%);
-o-transform: translateY(0%);
transform: translateY(0%);
Should I use the TweenMax .fromTo() function instead of using the .to() function so I can set the start position as well or is my thought about this wrong and has a different cause?
Something like this:
TweenMax.fromTo(animElem, 0.1, {
yPercent: triggerElement,
z: 1
}, {
yPercent: -(scrollPos - elemHeight / 2) / 100,
ease: Linear.easeNone
});
Beside that I trying to recreate the effect of the site that I would like to use as inspiration source without the use of the scrollMagic plugin, but I don't really know how this works, with the use of two different objects that are animated.
At last, if someone thinks the code can be better formatted, don't hesitate, I would like to hear your suggestions
My actual questions are for update 2 and 3/4:
How to calculate the parallax y coordinates to get "the magic" done?
Am I right about update 2, that the zero point will be reset to offsetTop of each element?
Why my code only works for the first two elements and why they jumping some pixels down if the inline style of translate will be added to the animated element? See update 3/4 for all info.
Parallax is actually quite simple in principle. Just make the parallax element scroll slower than the rest of the content. That being said, a parallax implementation can be as simple as dividing the scroll distance by a factor:
var parallaxFactor = 3;
window.addEventListener("scroll", function(e){
el.style.top = (document.body.scrollTop / parallaxFactor) + "px";
// This is the magic. This positions the element's y-cord based off of the page scroll
}, false);
CODEPEN
This is an extremely simple demonstration of the parallax effect. Other more thorough implementations may handle values as percentages, or attempt to smooth the animation with TweenMax. This however, is the magic you're looking for.
Live long and prosper.
Update:
This example only works for elements at the top of a screen. If this were for a more general purpose, you would want to store the default y-position of the element, then something along the lines of defaultYCord + (document.body.scrollTop / parallaxFactor).
Update 2:
A very good visualization for parallax comes from Keith Clark who made a pure css parallax scroller: http://keithclark.co.uk/articles/pure-css-parallax-websites/demo3/. If you click debug in the upper left, it gives you a nice 3d-view of the magic.
This is not an answer how to build a parallax in JS. But it shows some basics, which will often be forgotten, if your too much into the code.
Basics:
Order your graphical objects in z-layers. As higher z is, as nearer
it is to observer in front of the screen.
As higher your object is in the z-axis as faster it should move on something that appears, f.e. your scrolling
Now you get a 3-D-Effect where objects nearer to you move faster to your actions as objects more far away.
Your question
How to calculate the parallax y coordinates to get "the magic" done?
The y-position depends on your z-index. If it is far away a.k.a the z-index is low, delta-y is small. If it is near too you, delta-y is big.
Please consider the z-index is not necessarily used as Style-property, it's more like it looks like.
I would add an attribute like data-z to every parallaxing layer.
function parallaxingY(el){
//el is a parallaxing element with attribute data-z
return $(el).data('z')*window.scrollTop;
}
the suggested CSS-Solution is nice and should be preferred. There the "magic" - the "z-index" - is made by the css-style "scale".

JavaScript: An efficient way to handle events (Firefox-specific)

I'm running a scroll event that triggers TweenMax animations, and I'm noticing that, while it looks good on Chrome, there is a considerable amount of lag on Firefox. Does anyone have a suggestion about how to handle this scroll event as efficiently as possible? Also, is there something about Firefox's rendering that I'm not aware of that might be causing this? Any leads would be appreciated!
The gist is that I'm looking for containers on my page called "customers", which each contain three individual "customer" elements. When a div that matches "customers" scrolls into view, trigger a TweenMax animation, and add a class called "animated", which prevents the element from re-animating subsequently.
Here is a fiddle with the basic demonstration:
http://jsfiddle.net/epp37jsq/
EDIT
To clarify, the fiddle only demonstrates the behavior of my animation function. The lag does not occur there because the file size is quite small. On the actual site, I have 11 groups of 3 "customers." The image is the same, but pulled in 33 times. In the future, the images will be unique. In essence, the animation is being called for each of these 11 groups. I'm looking for suggestions on how to improve the speed of my page.
And my code:
var scrollTimer = null;
$(window).scroll(function () {
if (scrollTimer) {
clearTimeout(scrollTimer); // clear any previous pending timer
}
scrollTimer = setTimeout(handleScroll, 500); // set new timer
console.log("fired!");
});
function handleScroll() {
scrollTimer = null;
$('.customers').each(function() {
if (!$(this).hasClass('animated')) {
if ($(this).isOnScreen(0.45, 0.45)) {
TweenMax.staggerFromTo($(this).find('.customer'), 0.3, {
y: 50,
opacity: 0
}, {
y: 0,
opacity: 1,
ease: Power2.easeOut
}, 0.15);
$(this).addClass('animated');
}
}
});
}
Usually with Firefox, translating on the x or y axis can cause some jank. Sometimes adding a slight rotation:0.001 to your tween can help make your tween more smooth in Firefox.
http://jsfiddle.net/pwkja058/
Also using the GSAP special property autoAlpha instead of opacity can help increase performance
TweenMax.staggerFromTo($(this).find('.customer'), 0.3, {
y: 200,
rotation:0.01, /* add a slight rotation */
autoAlpha: 0 /* use instead of opacity */
}, {
y: 0,
rotation:0.01, /* add a slight rotation */
autoAlpha: 1, /* use instead of opacity */
ease: Power2.easeOut
}, 0.15);
autoAlpha is part of the GSAP CSSPlugin:
http://greensock.com/docs/#/HTML5/GSAP/Plugins/CSSPlugin/
autoAlpha - Identical to opacity except that when the value hits 0 the visibility property will be set to "hidden" in order to improve browser rendering performance and prevent clicks/interactivity on the target. When the value is anything other than 0, visibility will be set to "inherit". It is not set to "visible" in order to honor inheritance (imagine the parent element is hidden - setting the child to visible explicitly would cause it to appear when that's probably not what was intended). And for convenience, if the element's visibility is initially set to "hidden" and opacity is 1, it will assume opacity should also start at 0. This makes it simple to start things out on your page as invisible (set your css visibility:hidden) and then fade them in whenever you want.

Script to rotate an image and switch image halfway through animation

I am writing a script to rotate an image in the Y direction on hover, and switch the image to a different one at the 90 degrees point (the intended effect is that when the image is hovered, it flips round to show the "back" side).
My javascript is as follows:
$('.designthumb').on('mouseover', function(e) {
var x = this;
var img = $(this).attr('src');
var path1 = img.split('.png');
$(x).css('-webkit-transform','rotateY(90deg)');
$(x).css('transform','rotateY(90deg)');
$(x).on('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd',
function(e) {
if (path1[0].substr(path1[0].length - 4) == 'back') {var newpath = path1[0]+'.png';}
else {var newpath = path1[0]+'back.png';}
$(x).attr('src',newpath);
$(x).css('-webkit-transform','');
$(x).css('transform','');
e.stopPropagation();
});
$(x).on('mouseout', function(e) {
$(x).css('-webkit-transform','rotateY(90deg)');
$(x).css('transform','rotateY(90deg)');
$(x).on('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd',
function(e) {
if (img.split('.png')[0].substr(img.split('.png')[0] - 4) == 'back') {var imgo = img.split('back')[0]+'.png';}
else {var imgo = img.split('.png')[0]+'.png';}
$(x).attr('src',imgo);
$(x).css('-webkit-transform','');
$(x).css('transform','');
});
});
});
I have created a fiddle, but, somehow, I am just fiddle-tarded and my fiddles never work properly, or in this case at all. Nonetheless you can view my somewhat simplified attempt here: http://jsfiddle.net/Xenthide/u6nauzqg/
The above code SORT OF works, the HTML is fairly trivial so I won't bother posting it, basically I have a selection of images classed as designthumb, with names such as image1.png, image2.png, with corresponding files image1back.png image2back.png, etc. The intended effect is that the user can hover over an image and see the back image.
However, it only really works if the user firmly moves the mouse onto the image, then stops moving it entirely. Otherwise the transition wobbles around, doesn't complete, and is just buggy as fuck. I'm not sure if that current version is still doing it but previous attempts of mine have somehow managed to get stuck on the back image even when the cursor is moved away from it. The possibly odd looking if/else statements are my efforts to prevent that.
Really I would like some way to FORCE the transition to complete, smoothly, as soon as the cursor touches that region, without the current annoying wobbly crap going on.
Any help would be much appreciated.
You could do this without javascript: DEMO
.design {
background:url(http://www.graphicsfuel.com/wp-content/uploads/2012/09/emoticon-sad.png) center no-repeat;
transition: 0.2s ease-in-out;
background-size:0 100%;
padding:0;
height:374px;
width:326px;
}
.design:hover {
width:0;
padding:0 163px ;
background-size:100% 100%;
}
here some more ideas with effects using same method : http://codepen.io/gc-nomade/pen/Joqzp
and a flip effect very close to what you try to do : http://codepen.io/gc-nomade/pen/cHirI

Categories

Resources