I literally just started learning jquery and velocity at the same time for animation purposes. I was reading the velocity.js docs and trying to manipulate the "scale" of my box and ran into some trouble. Basically I have this code:
HTML:
<div id="box"></div>
CSS:
.box {
background-color:red;
height:300px;
width:300px;
transform:scale(0.3);
}
Velocity JS:
$("#box").velocity({
scale:1,
}, {
duration: 800
});
The idea is that the box would appear small(30% of its original size) at first and when the Velocity JS triggers, it scales into its normal size at 800ms. Problem is that when I'm setting the scale, it completely ignores the transform:scale(0.3) portion of the css. For example, if scale in the velocity js code was at 2, the animation starts of from 1 -> 2 in 800ms.
Any help is greatly appreciated. Thank you very much!
Bearing in mind that the velocityjs.org website docs are out of date (they refer to Velocity V1 which is no longer supported) - instead go to the Velocity Wiki and read on there.
In general the transform property is not simple to use, the browser changes the nice-to-read "scale(1)" into a "matrix(...)", and Velocity doesn't (currently) try to parse it (it's very easy to get that wrong, so we've been avoiding it).
Instead you should use ForceFeeding - this means you supply both the start and end values to Velocity, so it doesn't need to guess what you're actually meaning.
In addition the entire shortcut part of Velocity V1 has been removed because the premise itself is too broken (ie, there is no longer any scale property) - you need to use the transform property directly -
$("#box").velocity({
transform: ["scale(1)", "scale(0.3)"],
}, {
duration: 800,
});
It should be relatively clear there that the ForceFeeding is an array with a "[to, from]" layout. Potentially you can also add specific easings in between them, but check the documentation for more information.
Related
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".
I've got an ad with the size is 728x90 which was converted from Flash to Html5 using Google Swiffy.
Myself, I've never used flash. I've done some creative campaigns in the past on GDN, but I've built them directly using Html5. Anyway, I was asked if I can convert that 728x90 flash-built-converted-to-html5-with-swiffy ad to 835x90 format.
After opening the document, I've noticed an Object literal swiffyobject = {...} which is passed as parameter to the Stage() method which resides in Google's runtime.js library. This method apparently returns an object on which we call another method start() to make the magic happen:
var stage = new swiffy.Stage(document.getElementById('swiffycontainer'),
swiffyobject, {});
stage.start();
The object literal swiffyobject seems for me the right place to start in order to change the ad size. However, the most relevant part I found regarding changing the size is at the start, ymax & xmax:
swiffyobject = {
"as3": false,
"frameRate": 20,
"frameCount": 1,
"backgroundColor": -1,
"frameSize": {
"ymin": 0,
"xmin": 0,
"ymax": 1800,
"xmax": 15560
},
...
}
Since the height of the ad wilm remain the same and only the width is the problem, scaling up xmax to 17846 will change the add size but not in a way we desire, instead, for some reason, it shrinks the ad's height by approximately 4px.
Any idea where should I tackle this great swiffyobject (which after re-indented with my IDE has approximately 6000 lines) in order to change the ad size? Or is there any online convertor that solves this?
The only viable solution, other than completely remaking the ad in HTML5, was to get a hold of the flash files, resize them & reconvert them. Touching that swiffy object just creates a big mess and a headache.
in your html, there should be a part like that:
<div id="swiffycontainer" style="width: 728px; height: 90px">
</div>
do you also change it to 835? If not, swiffy may think it's a 835x90 flash in a 728x90 container, and scale it to fit the container.
We are coding a rather simple Javascript (jQuery) image cropper & resizer. Basically, for now, only features needed are indeed crop and resize.
I have been checking a few jQuery plugins like JCrop etc. and it seems there's no plugins doing both things at same time. Lots of croppers OR resizer, but not the two features on a same "natural" image view at same time. By natural I mean that examples like this (bottom right) are not very nice visually for users :
http://jsfiddle.net/opherv/74Jep/33/
Although I guess this would be a possible way to go to have the two features at same time. Though you can see this example only zooms too currently and it is qualified as using "ugly hacks" by the author himself to do so :
function changeZoom(percent){
var minWidth=viewport.width();
var newWidth= (orgWidth-minWidth)*percent/100+minWidth;
var newHeight= newWidth/orgRatio;
var oldSize=[img.width(),img.height()];
img.css({ width: newWidth+"px", height: newHeight+"px" });
adjustDimensions();
//ugly hack :(
if (img.offset().left+img.width()>dragcontainer.offset().left+dragcontainer.width()){
img.css({ left: dragcontainer.width()-img.width() +"px" });
}
if (img.offset().top+img.height()>dragcontainer.offset().top+dragcontainer.height()){
img.css({ top: dragcontainer.height()-img.height() +"px" });
}
}
We are rather looking for the possibilty to use a cropper frame/zone (as we see the most often on the web) + a zoom/de-zoom option on the image (handles on the border of the image for example)
Since we only need those two features we thought we would code this from scratch or almost as we don't want to add other javascript files/plugins which will be overkill anyway being packed with other features we will not need (at least for now).
The question is: is there a specific difficulty at trying to code the display of an image re-sizable by straightforward handles & croppable by a frame/zone selection (which would also be re-sizable on its own and draggable around so a user can fine tune which part of the image he wants)?
Are we definitely better separating the two features ?
Thanks a lot for your help.
Tried this plugin??
http://code.google.com/p/resize-crop/
It does both crop and resize
Here's the breakdown...
wrapper (position:relative; overflow:hidden; )
section-container (position:absolute)
multiple child sections
I attach a mousewheel event listener and animate (with easing) the 'top' position of 'section-container'. As this position changes, the 'background-position' of each section moves vertically based on the position of 'section-container's 'top' property (continually updated through a setTimeout()).
All of that works as it should, except as the 'background-position' changes, the image has a bit of a jitter. This doesn't happen if the 'background-attachment' is set to 'fixed'... but I don't want that.
Can anyone explain this, with a possible fix? I continually refer to the https://victoriabeckham.landrover.com/ site and can't figure out what they're doing differently to get theirs operating so efficiently.
You can check this out, i believe its where they do most of the animating:
https://victoriabeckham.landrover.com/js/ScrollAnimator.js?v=471
I would have to say they have some kind of framework that they are using to accomplish this.
EDIT: Sorry didn't see the new answer above mine, seems like a good starting point.
-Ken
If you inspect this website carefully, you will able to use it like landrover site.
You need to use: scrollTo plugin and parallax plugin
And document jQuery should be like this:
$(document).ready(function(){
$('#nav').localScroll(800);
//.parallax(xPosition, speedFactor, outerHeight) options:
//xPosition - Horizontal position of the element
//inertia - speed to move relative to vertical scroll. Example: 0.1 is one tenth the speed of scrolling, 2 is twice the speed of scrolling
//outerHeight (true/false) - Whether or not jQuery should use it's outerHeight option to determine when a section is in the viewport
$('#intro').parallax("50%", 0.1);
$('#second').parallax("50%", 0.1);
$('.bg').parallax("50%", 0.4);
$('#third').parallax("50%", 0.3);
});
Ok. So I figured out my issue was when trying to animate() the 'section-container' on the 'top' property. I was using a "+=" to allow it to increment from its current position. Not a good idea when using 'mousewheel' events. I changed it to a hard-set variable that is continually incremented/decremented.
Why this example not working in IE http://jsfiddle.net/8RZVt/
I'm getting this error in IE8.
Message: Invalid argument.
Line: 156
Char: 295
Code: 0
URI: http://code.jquery.com/jquery-1.4.4.min.js
According to jQuery, this is because, as stated on the animate documentation page:
All animated properties should be a
single numeric value (except as noted
below); properties that are
non-numeric cannot be animated using
basic jQuery functionality....
So, in fact, in Firefox you are using undefined behavior. The correct thing to do would be to animate on backgroundPositionX, however Firefox does not support this.
There is, however, a jQuery plugin that does what you want:
http://plugins.jquery.com/project/backgroundPosition-Effect
Update
On closer inspection, the plugin does not support += or -= formats.
I hacked it into this example:
http://jsfiddle.net/CxqSs/ (See new example at bottom.)
Could definitely use some cleanup, and should probably be added to that plug-in, but it works in both browsers and doesn't rely on undefined behavior.
BTW, I don't know if it's worth noting, but if you leave this animation running a long time, it will eventually overflow the value and break. This could be overcome by animating the full length of the background image and then resetting the offset to 0px in the callback before the next animate. This would also avoid needing the += format.
Also,
It should be noted that speed: 1, step: 1 and speed: 50, step: 50 are equivalent.
The reason they look different speeds is because
There is more overhead in a speed of 1 (which is really a millisecond duration) because animate gets called more often.
The default easing is "swing", meaning that the animation speeds up and slows down slightly throughout it's course, meaning that the overall speed is affected a bit. You should change the easing to "linear" for your scrolling case:
var animate = function() {
element.animate({
...
}, speed, "linear", animate);
};
This means that you could use the backgroundPosition-Effect plugin, without the '+=', by setting your step to 2247 (the width of the image), like I stated above.
And that finally brings us to... wait for it...
http://jsfiddle.net/zyQj3/20/
Cross-platform, non-kludgy, non-overflowing, correctly easing, extra parameter-lacking, solution.
The script fails at this point because you are passing an invalid CSS value:
element.animate({
backgroundPosition: animStep + " 0px" /* evaluates to "+=50px 0px" */
}, speed, animate);
OK here we go again :D
http://jsfiddle.net/c7rKV/1/
Again identical to original however again just animating backgroundPositionX when in IE.
Apologies on not actually looking at FF/Chrome last time.
Additionally: this of course is not very graceful and Adam Prax is absolutely correct on what the problem is. I just wanted to post a solution to it.
If you check the source code of jQuery, you will see it uses this regexp to parse the parameter (which in your case is +=50px 0px). So it will see it as += (increase) 50 (to fifty) px 0px (unit, append after the number). When trying to read the current value, jQuery uses parseFloat, which just grabs the number at the start of the string. So it works perfectly, even if a multi-dimensional property is probably not what the jQuery programmers had in mind.
Except that IE8 does not support getting the current value of background-position. There is background-position-x and background-position-y but no background-position. Duh. So your best bet is checking the browser type, and animating either background-position or background-position-x depending on that: http://jsfiddle.net/22UWW/
(There is actually a jQuery bug report about this, with a more elegant solution.)