I am using jQuery Animate to create a Pan-Zoom effect on an image. Overall it works well with two exceptions.
First it starts the animation and seems to hit a wall then continue to zoom in. Is there a way to prevent this and make the motion one smooth motion.
Second is the motion is a bit jerky, especially at the end. Is there a way to smooth this out? I am using easing on the page if I should try adding some form of easing. (This was testing in Firefox and Chrome and both are jerky.)
Here is a jsFiddle of the animation.
Notes: I am using jQuery 1.8.3 and I could use CSS but sticking with jQuery for cross browser compatibility. (Majority of my users are on IE unfortunately.)
HTML
<div style="width:1140px; height:500px; overflow:hidden; text-align:center;">
<img id="pan-zoom" style="width:900px; height:600px; position:relative; top:-80px; left:0;" alt="European Bee-eaters" src="http://upload.wikimedia.org/wikipedia/commons/9/96/Pair_of_Merops_apiaster_feeding.jpg" />
</div>
JS
$(window).load(function() {
$('#pan-zoom').animate({
width: '2141px',
height: '1428px',
top: '-200px',
left: '-405px'
}, 8000, function() {
// Fade In Hidden DIV
});
});
If you speed up the animation, it will appear to be smoother. The slower the animation, the more noticeable any roughness of it will be.
Changing the easing to linear seemed to help as well. The slowness at end of the default easing (swing) makes the roughness of the animation very noticeable. The code below uses linear easing and is sped up twice as fast (as well changing the outer width to 900px, as #loxxy suggested), and it looked reasonably good.
$(window).load(function() {
$('#pan-zoom').animate({
width: '2141px',
height: '1428px',
top: '-200px',
left: '-405px'
}, 4000, 'linear', function() {
// Fade In Hidden DIV
});
});
Getting a large animation to be both smooth and slow may only be possible with hardware support like WebGL. Short of that, choose between smooth and slow, whichever is more important.
Change
<div style="width:1140px; ...
To
<div style="width:900px; ...
The idea is, that before zooming in, the image is scaled to fit the parent width, which is the effect you want to remove.
Updated fidde.
EDIT : Or position absolute, as commented.
Both problems would be resolved if you used the scale function of the css transform property. I think (it has been a long time since i've user jquery and did not follow up) that the jquery.animate function is not compatible with these. You should use a plugin or write one that does if you want to keep using jquery.
In your fiddle you use the left, top, width and height properties. This will be especially jerky in webkit.
Jquery transform plugin top google result:
http://ricostacruz.com/jquery.transit/
Related
I currently have a full screen hero image slideshow on the homepage of a site. I have an javascript effect which gets the scroll position and divides it by 1.5 then sets the image transformY position causing a parallex effect.
Here is the code I currently have:
$(window).on("load scroll resize", function () {
$("form:not(.blive_PageEdit) .hero-img .blive_Control img").css({ "margin-top": $(window).scrollTop() / 1.5 });
});
This works as I want, but I have noticed that performance is a major issue expecially on browsers which support asynchronous scrolling which causes a juddering effect.
What I want to know is if there is a better way to implement this? What would be perfect would be to have something like the following but I don't think this is possible with just CSS:
img {
transformY(calc(scrollTop / 1.5));
}
I have also looked at IntersectionObserver, but I am unsure this would achieve what I want to do.
Any thoughts would be helpful. Thanks
I have a jQuery transition with a css overlay that will work fine if the user mouses over for a second or more....however if the user mouses over quickly then the overlay text stays put without the overlay background. Here is my jQuery code:
$(".cascade-t1").hover(function(){
$(".cascade-corner").fadeOut();
$(".overlay-t1").animate({"left": "-300px"}, 300, function(){
$(".cascade-overlay-content").fadeIn(200);
});
}, function(){
$(".cascade-corner").fadeIn();
$(".cascade-overlay-content").fadeOut(200, function(){
$(".overlay-t1").animate({"left": "130px"}, 300);
});
});
Here is the script in action
It looks like the issue is that you don't fadeIn() the .overlay-t1 text until the mouseenter animation is done, and on mouseleave you fadeOut() the text out right away before the animation. When you move your mouse in and out faster than initial the animation the code will fade out the text and then fade it in again (the issue you're seeing).
One possible solution is to slightly alter your bottom (mouseleave) function to resemble your top (mouseenter) function more closely. Something like:
$(".cascade-corner").fadeIn();
$(".overlay-t1").stop(true, true).animate({"left": "130px"}, 300, function () {
$(".cascade-overlay-content").fadeOut(200);
});
The .stop() is there to keep the animation from playing over and over when someone spams the box.
FIDDLE DEMO
Not sure how jquery animate works under the hood but it's possible it's using javascript to animate instead of css transitions. The benefit of css transitions is that it does all of the animation calculations before the animation begins and is hardware accelerated. Javascript is at the mercy of the scheduler at a very high level so it will always be choppy.
Try jquery transit.
http://ricostacruz.com/jquery.transit/
I am building a website that has a few animations when you load the home page (for example, the main logo and a few menus slide in from the sides of the screen). Simultaneously, I am also using AJAX in the background to start to load some images that might be viewed later. The problem with this is that when the images are loading, the animations become quite choppy. Is there any way to stop this? Or maybe give the AJAX function a lower priority so that it doesn't try to do anything when an animation is running?
Here is the current script I'm using to load these images:
$('.lightbox-container.first').load('/images/first_set/', function(){
$('.lightbox-container.second').load('/images/second_set/', function(){
$('.lightbox-container.third').load('/images/third_set/', function(){
$('.lightbox-container.fourth').load('/images/fourth_set/', function(){
$('.lightbox-container.fifth').load('/images/fifth_set/', function(){
$('.lightbox-container.sixth').load('/images/sixth_set/');
});
});
});
});
});
An all of my animation function look something like:
$('.third-section').animate({ 'opacity': '1', 'height': '200px', 'padding-top': '20px', }, 500);
The problem
Since all your ajax and js animations run on the same browser thread, you are bound to have this problems. You are reaching the limits of your CPU, which causes the choppiness.
How to solve this
Use CSS3 transforms. Those are hardware accelerated in all modern browsers and run on a separate threads, so their performance is generally not affected by ajax calls. Since you said you only slide things around, I think this would be the ideal solution for you. There is a great article about it here:
http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/
Your case
So to actually make this work for you. Leave the ugly ajax calls as they are for now. Instead of using jQuery animate, you need 2 states - the initial, which positions the slide away and one with an extra class, which positions your slide in it's target place.
All you have to do is add the class to the slide and it will nicely come in place. Theory is simple.
Sample
Your initial state could be something like this:
.slide {
transform: translate(-400px, -200px);
transition: all 5s;
}
And the one to show in place:
.slide.show {
transform: translate(0px, 0px);
}
Im having an absolute nightmare with a plugin im trying to integrate.
Im trying to make X elements on my page flip on hover, and then on mouseout revert back.
Im using the flip function, and it works fine if i hover over an element, wait a few seconds for the flip to finsih animating, and then move my cursor. If i hover quickly however, my flip happens but messes up completely, and you cant quickly move your mouse across multiple elements.
I've tried using stop() to no avail so thought I'd ask on here, I've attached a fiddle, when looking at my fiddle, quickly run your mouse across all elements and you will see what I mean
http://jsfiddle.net/5JyVC/
$('.sec-con').prepend('<div class="target" style="width:100%; height:100%; z-index:999999; cursor:pointer;top:0; left:0; display:block; position:absolute; "></div>');
$('body').on({
mouseenter:
function () {
$(this).stop(true, true).next('.sector').flip({
direction:'rl',
color:'#2d6995',
speed: 200,
content:'<span class="all-vacancies">View all Vacancies <br />in this sector.</span><span class="read-more">Click here to read more.</span>'
});
},
mouseleave: function () {
$(this).next('.sector').revertFlip();
}
}, '.target');
It's something to do with the flipLock data attribute. If you mouseout too soon flipLock is true and the revert flip wont happen causing the next mouseover to start with the wrong content. So from then on you're flipping back and forth between the same content.
If you remove the flipLock detection and return false and add stop to the animation call in flip it will revert properly.
The animation looks a bit wonky though, I'm not sure what can be done about that.
This works for me: http://jsfiddle.net/5JyVC/5/ If you move fast enough it will still mess up, not sure why that is, maybe multiple mouseover events? This is what the original flipLock intended to prevent I guess.
Maybe flipLock should be more complex, when flipped, only allow flip backs and vice versa. The current implemenation of flip and revertFlip doesn't allow for this though.
Here is an alternative way in pure css (as requested)
the javascript is here just to add the elements faster
Anyway i modified the function sothat you can add HTMLElements direct to the function that adds the various divs that needs to be flipped.
A & B, where A is the front and B is the back.
in this example i add 6 elements to the page.
here is the javascript to test the elements
var D,
flip=function(A,B){// HTMLElement,HTMLElement - no text
var box=D.createElement('div');
box.appendChild(D.createElement('div')).appendChild(A);
box.appendChild(D.createElement('div')).appendChild(B);
return box;
},
init=function(){
D=window.document;
for(var i=0,f=D.createDocumentFragment();i<6;i++){
var a=D.createTextNode('Front '+i),
b=D.createTextNode('Back '+i);
f.appendChild(flip(a,b));
}
D.getElementsByClassName('flip')[0].appendChild(f);
}
window.onload=init;
As you can see no eventlisteners or complex code as if you use css3 you totally can put the :hover on the divs without the need of javascript (mouseenter,mouseleave).
to add this animation to every element i added a class for the container of the elements.
html,body{width:100%;height:100%;margin:0;padding:0;} /* important */
.flip{
width:100%;height:100%; /* in this case the perspective center */
-webkit-perspective:1200; /* is in the page center */
}
.flip>div{
width:200px;height:160px; /* width && height of the flip box */
float:left;
margin:16px;
-webkit-transform-style:preserve-3d;
-webkit-transition:all 600ms ease;/* animation speed is 600ms */
}
.flip>div>div{
width:100%;height:100%; /*to fit the flip container*/
-webkit-backface-visibility:hidden;/* hide the back side */
line-height:160px;text-align:center;/*center the text*/
background-color:grey;/* both sides color */
}
.flip>div>:nth-child(2){
-webkit-transform:rotateY(180deg);
margin-top:-160px;/* hack so no need for position absolute*/
}
.flip>div:hover{
/*-webkit-transition:all 1000ms ease 1000ms;
want to close it slowly with a delay? */
-webkit-transform:rotateY(180deg);
}
/* no position relative or absolute which slows down ios */
this is writtenfor webkit browsers (chrom, safari, android, ios)
i made it for my ipad.
to use it with firefox and the latest ie's that support css3 you need to duplicate this -webkit styles with the -moz,-ms,-o prefixes and check the support.
this example is based on 3d so the container has also a perspective value.
and the elements flip in real 3d and so you trigger the HW GPU acceleration on the various browsers.
the html just needs that container with the class flip
using classallows you to add multiple containers with multiple flipping elements.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>flip</title>
//add here the links to css3 or the <style>
//add here the the script or link to the script
</head>
<body><div class="flip"></div></body>
</html>
so this is very simple as you can see but from this base you can create veri impressive animations just changind the flip css.
if you need some more advanced features you can handler that with javascript event
transitionend
if you want to add the boxes manually this is all you need to write.
<div class="flip">
<div>
<div>Element1 Front</div>
<div>Element1 Back</div>
</div>
<div>
<div>Element2 Front</div>
<div>Element2 Back</div>
</div>
</div>
Want to triggerthe animation on click/mouseevent/dragevent/scrollevent whatever?
replace .flip>div:hover with .flip>div.flipped
and in javascript on event
this.parentNode.classList.toggle('flipped')
or
this.parentNode.classList.add('flipped') & this.classList.remove('flipped')
Now this is all about modern browsers and uses modern javascript&&css3 but as you want to flip something you anyway need a modern browser.
also jQuery can't flip something in ie6
like always
javascript handle the events or adds multiple elements
css to create the style of the page
html just for a basic structure.
for any other questions just ask
fiddle (test with chrome)
http://jsfiddle.net/gNB3z/2/
I am using this code to create a scroll-up marquee text but after 7000 miliseconds it jitters and thus doesn't offer a good look for the text inside.
Have you any idea where I can fix it ?
<script language="javascript">
jQuery(function() {
var marquee = jQuery("#marquee");
marquee.css({"overflow": "hidden", "height": "100%"});
marquee.wrapInner("<span>");
marquee.find("span").css({ "height": "50%", "display": "inline-block", "text-align":"left" });
marquee.append(marquee.find("span").clone());
marquee.wrapInner("<div>");
marquee.find("div").css("height", "200%");
var reset = function() {
jQuery(this).css("margin-top", "0%");
jQuery(this).animate({ "margin-top": "-100%" }, 7000, 'linear', reset);
};
reset.call(marquee.find("div"));
});
BTW, you can it like this
<div id="marquee">text</div>
[UPDATE]Sorry Kamal for having to edit this post to add the jsfiddle to reproduce the problem [I always know I can do this :-D]
http://jsfiddle.net/xRcwH/
why not use the <marquee> tags?
<marquee behavior="scroll" direction="up">Your upward scrolling text goes here</marquee>
I've already answered the same question at <marquee> html tag usage/replacment.
There is CSS3 WebKit specific -webkit-marquee-, that you can read about at http://davidwalsh.name/webkit-marquee-css. However, for whatever reason, even the native CSS marquee implementation is glitchy.
The same applies to the <marquee> element. It is well supported by the browsers, though, apart from being deprecated, it is glitchy.
I've been looking for the most efficient and cross-browser supported marquee implementation. None of the above fit the bill. The common approach is to use timer (or jQuery animate implementation) to adjust the CSS margin property of the element. This is what your script does. Unfortunately, this operation is very resource intensive. It requires applying new CSS every few milliseconds resulting in recalculation of the whole layout.
I came up with implementation that utilises CSS3 transitions for browsers that support it and otherwise animate the scrollLeft property of the containing element. It is an experimental implementation, though it works well with IE7+. The code is available at https://github.com/gajus/marquee (demo https://dev.anuary.com/60244f3a-b8b2-5678-bce5-f7e8742f0c69/).