I have the following
$('.left_arrow').hover(function() {
$('.chart').stop().animate({
left: "+=10"
});
},
function() {
$('.chart').stop();
});
And I want to have it when you mouse over the arrow it smoothly moves the .chart to the left, and the right arrow it moves it to the right. I am doing this by applying a - left (-7500px is the max) to move it to the left and a 0 is the farthest it can go right.
The above moves it over 10, but it doesn't keep on moving it. How can I get it so it keeps on moving it. I was using something like
$('.left_arrow').hover(function() {
$('.chart').stop().animate({
left: "-7500px"
}, 20000);
},
function() {
$('.chart').stop();
});
But the problem is if I am say -6500px over it takes 20 seconds to go the rest of the 1000, vs 20 seconds to go the full distance. So the speed is skewed, I want a standard increment.
Basically what you need is a rate function. I had the same issue when I was creating my carousel.
rate = distance/time
So, your rate is 0.375
Now, all you will need to do is find the distance and you can adjust your timing accordingly.
time = distance/0.375
So it should look something like this:
$('.left_arrow').hover(function() {
var distance = /*Get Distance Remaining*/
var sd = 7500;
var time = 20000;
var rate = sd/time;
var time = distance/rate
$('.chart').stop().animate({
left: "-7500px"
}, time);
},
function() {
$('.chart').stop();
});
Obviously it would need some tweaking to get just right. But the concept is there.
For my situation, because I was using a <ul> since it was a carousel this is the way I got distance:
distance = Math.abs($ul.position().left);
Not fully understanding the question, but you can increment/decrement animations like so:
$('.chart').stop().animate({
"left": "+=100px"
}, 250);
Note the += operator.
EDIT: This answer is only partially correct. Animation behavior on hover is not as desired. Trying to solve.
Related
I'm currently experimenting a bit with Famo.us and there is actually one thing I can't yet wrap my head around.
In a small example i tried to create a HeaderFooterLayout, where the header contains a simple icon left aligned. A click on it will bounce it to the right end of the header.
Now with a simple Transform.translate this works not as smooth as expected on my Nexus4 and Nexus 7, but hell changing it to a SpringTransition rocks. Here is the code example:
var Transitionable = require('famous/transitions/Transitionable');
var SpringTransition = require('famous/transitions/SpringTransition');
Transitionable.registerMethod('spring', SpringTransition);
var logoStateModifier = new StateModifier({});
var logo = new ImageSurface({
size: [186, 43],
content: 'images/my-logo.png'
});
var posX = 0;
var adjustment = 20;
// Click event on image
logo.on('click', function() {
if(posX === 0) {
posX = (window.innerWidth - logo.size[0] - adjustment);
} else {
posX = 0;
}
var spring = {
method: 'spring',
period: 10,
dampingRatio: 0.3,
};
// transform translate with Easing
logoStateModifier.setTransform(
Transform.translate(posX,0,0),
{ duration: 1000, curve: Easing.inOutBack}
);
// spring transition
logoStateModifier.setTransform(
Transform.translate(posX, 0, 0), spring
);
});
So what I don't understand here is why Easing is so "slow" compared to the Physics driven SpringTransition?
The spring transition your requesting has a period of 10ms while the easing transition is 1000ms or 100 times slower. I tried your code "as is" and with a modification that compares more apples to apples and the transitions can run at the same speed (both laptop and devices.) First you should note that the minimum spring period is 150ms so the 10ms your asking for is actually 150. Second you are stacking the transitions so that one follows the other. The easing will take 1 second and then the spring will oscillate. You may want to try something slightly different... set the transitions to the following:
// transform translate with Easing
logoStateModifier.setTransform(
Transform.translate(posX,0,0),
{ duration: 150, curve: Easing.inOutBack}
);
// spring transition
logoStateModifier.setTransform(
Transform.translate(0, 0, 0), spring
);
This will behave slightly differently. On click (every other click actually) the logo will cross the screen at high speed and then come back. I expect you'll find that these transitions run at comparable high speeds. Of course for a slower more viewable test you can set the spring period to 1000 and the easing duration to the same and again the speeds should be comparable.
http://www.deviantart.com/ is vertically scrolling the content of one of their container upwards when you move your cursor over it. and on mouseleave, it scrolling back down.
You can see it in action on their main page - right now at least - in a container with the text "Project Giveaway: 100 point giveaway #4". I'm wondring how they do this?
Found this line of code trough firebug:
onmouseout="if (window.LitBox) LitBox.out(this)" onmouseover="if (window.LitBox) LitBox.hover(this, true)".
So I tried to google for "LitBox" - but didn't get any luck. All I found was lightbox and listbox...
The exact effect is what I'm looking for.
Anyone know how?
$(document).ready(function () {
if ($('.content').height() > $('.container').height()) {
$(".content").hover(function () {
animateContent("down");
}, function () {
animateContent("up");
});
}
});
function animateContent(direction) {
var animationOffset = $('.container').height() - $('.content').height();
var speed = "slow";
if (direction == 'up') {
animationOffset = 0;
speed = "fast";
}
$('.content').animate({
"marginTop": animationOffset + "px"
}, speed);
}
See in JSFiddle
my code based on this code :)
Well.. it's really not that difficult to implement with jquery or css3. With jquery, on mouseover you start running a function to scroll the div up, using animate() perhaps. Then on mouseleave you stop the animation and run another animation to scroll it back.
With css 3, you can achieve it with transitions.
You can check out http://www.w3schools.com/css3/css3_transitions.asp.
I have a timeline that can be zoomed by clicking a zoom in or zoom out button. This timeline doesn't all fit on the screen at once, so it is a scrollable div. When the user clicks to zoom, I want the position in the timeline to be the same, so I calculate a new scrollTop for the scrollable div. Here's a simplified version of what I'm doing:
var self = this;
...
this.zoomIn = function() {
var offset = $("#scrollable").scrollTop();
self.increaseZoomLevel(); // Assume this sets the correct zoom level
var newOffset = offset * self.zoomLevel();
$("#scrollable").scrollTop(newOffset);
};
This works fine. Now I'd like to animate the scrolling. This almost works:
var self = this;
...
this.zoomIn = function() {
var offset = $("#scrollable").scrollTop();
self.increaseZoomLevel(); // Assume this sets the correct zoom level
var newOffset = offset * self.zoomLevel();
$("#scrollable").animate({ scrollTop: newOffset });
};
It works if it's clicked once. However, if a second call to zoomIn happens while the animation is still running, the newOffset calculation is wrong because the offset is set to scrollTop() before scrollTop() is correct since the animation is still manipulating it.
I've tried to use jQuery's queue in various ways to make this calculation happen first, and that seems to work sometimes:
var self = this;
...
this.zoomIn = function() {
$("#scrollable").queue(function(next) {
var offset = $("#scrollable").scrollTop();
self.increaseZoomLevel(); // Assume this sets the correct zoom level
var newOffset = offset * self.zoomLevel();
next();
}).animate({ scrollTop: newOffset });
};
I think I'm just not understanding queue properly. How do I keep everything in order even when zoomIn is called repeatedly and rapidly? I want:
zoomIn x 2 clicks
to give me:
calculate 1 -> animate 1 start -> animate 1 finish -> calculate 2 -> animate 2 start -> animate 2 finish
and not
calculate 1 -> animate 1 start -> calculate 2 -> animate 1 finish -> animate 2 start -> animate 2 finish
Because then animate 2 is based on incorrect calculations.
Thanks!
Hm... what about: stop(true,true)? See: http://api.jquery.com/stop/
var self = this;
...
this.zoomIn = function() {
var offset = $("#scrollable").stop(true,true).scrollTop();
self.increaseZoomLevel(); // Assume this sets the correct zoom level
var newOffset = offset * self.zoomLevel();
$("#scrollable").animate({ scrollTop: newOffset });
};
Here's an implementation of #RobinJonsson's comment, which would be my proposed solution too, using a boolean to allow a new zoom action only after the previous animation is complete:
var self = this;
...
this.zooming = false;
this.zoomIn = function() {
if(!self.zooming){
self.zooming = true;
var offset = $("#scrollable").scrollTop();
self.increaseZoomLevel(); // Assume this sets the correct zoom level
var newOffset = offset * self.zoomLevel();
$("#scrollable").animate({ scrollTop: newOffset },function(){
self.zooming = false;
});
}
};
I very much appreciate the answers given. They both would work, but my unwritten requirements included animations that completed entirely as well as no loss of clicks. I know, I should have been more thorough in my question.
Anyway, I believe I have a solution that fits both of those requirements using jQuery queues. There were a couple of things I didn't realize about queues that I learned that got me going in the right direction. The biggest thing is this from the jQuery .animate docs:
When a custom queue name is used the animation does not automatically
start...
This allowed me to have complete control over the queue. I believe this is similar to (or maybe exactly what) #RobinJonsson's comment meant.
var top = 0;
var animating = false;
function calcAndAnimate(top) {
$("#block").queue("other", function() {
// Calculations go here
animating = true;
// This kicks off the next animation
$("#block").dequeue("other");
});
$("#block").animate({
top: top
}, {
duration: 2000,
queue: "other",
complete: function () {
animating = false;
// No need; it looks like animate dequeues for us, which makes sense.
// So the next calculation will be kicked off for us.
//$("#block").dequeue("other");
}
});
}
$("#queueButton").click(function() {
top += 20;
calcAndAnimate(top);
if (!animating) {
// Initial animation, need to kick it off
$("#block").dequeue("other");
}
});
There's a working example with log messages showing the enforced order at http://jsfiddle.net/cygnl7/6h3c2/3/
I had an idea for like a bus window as a fixed frame, about 800px wide, with a parallax city with the content on billboards spaced out so when you scroll between them it allows the parallax to look like bus is moving. The content will be much bigger than the window like a sprite and I'll put forward and back buttons that will scrollBy (x amount, 0). I have a working parallax script and a rough cityscape of 3 layers that all work fine.
I have hit a wall. I am trying to clear a scrollBy animation after it scrolls 1000px. Then you click it again and it goes another 1000px. This is my function.
function scrollForward() {
window.scrollBy(5,0);
scrollLoop = setInterval('scrollForward()',10);
}
So far I can only clear it when it gets to 1000. I tried doing 1000 || 2000 ect but after the first one it goes really fast and won't clear.
Excelsior https://stackoverflow.com/users/66580/majid-fouladpour wrote a great piece of code for someone else with a different question. It wasn't quite right for what the other guy wanted but it is perfect for me.
function scrollForward() {
var scrolledSoFar = 0;
var scrollStep = 75;
var scrollEnd = 1000;
var timerID = setInterval(function() {
window.scrollBy(scrollStep, 0);
scrolledSoFar += scrollStep;
if( scrolledSoFar >= scrollEnd ) clearInterval(timerID);
}, 10);
}
function scrollBack() {
var scrolledSoFar = 0;
var scrollStep = -75;
var scrollEnd = -1000;
var timerID = setInterval(function() {
window.scrollBy(scrollStep, 0);
scrolledSoFar += scrollStep;
if( scrolledSoFar <= scrollEnd ) clearInterval(timerID);
}, 10);
}
Now for step two figuring out how to put this content animation behind a frame.
Not quite sure what your asking here. Perhaps you could provide more relevant code?
I do see a potential issue with your code. You call setInterval('scrollForward()', 10) which will cause scrollForward to be called every 10ms. However, each of those calls to scrollForward will create more intervals to scrollForward creating a sort of explosion of recursion. You probably want to use setTimeout or create your interval outside of this function.
Also, as an aside you can change your code to simply: setInterval(scrollForward, 10). Removing the quotes and the parens makes it a littler easier to read and manager. You can even put complex, lambda functions like:
setInterval(function() {
scrollForward();
// do something else
}, 10);
edit:
So if you know that scrollForward moves the item 10px, and you want it to stop after it moves the item 1000px, then you simply need to stop it has moved that much. I still don't know how your code is actually structured, but it might look something like the following:
(function() {
var moved_by = 0;
var interval = null;
var scrollForward = function() {
// move by 10px
moved_by += 10;
if (moved_by === 1000 && interval !== null) {
clearInterval(interval);
}
};
var interval = setInterval(scrollForward, 10);
})();
If you want to clear it after 1000 or 2000, you simply adjust the if statement accordingly. I hope that helps.
I'm trying to implement the marquee tag in jQuery by animation a set of images using animate() function, making them move to the right or left direction.
But, I couldn't figure out when a single image goes to the end of the screen returns individually to the other side.
Because I heard that the window size is not constant for every browser, So is there anyway to implement that?
this is what I came up so far(it's simple and basic):
$(document).ready(function(){
moveThumbs(500);
function moveThumbs(speed){
$('.thumbnails').animate({
right:"+=150"
}, speed);
setTimeout(moveThumbs, speed);
}
});
note: I searched in SO for related questions, but had no luck to find exact information for my specific issue.
Here's a basic script that moves an image across the screen and then resumes on the other side and adapts to the window width.
You can see it working here: http://jsfiddle.net/jfriend00/rnWa2/
function startMoving(img) {
var img$ = $(img);
var imgWidth = img$.width();
var screenWidth = $(window).width();
var amount = screenWidth - (parseInt(img$.css("left"), 10) || 0);
// if already past right edge, reset to
// just left of left edge
if (amount <=0 ) {
img$.css("left", -imgWidth);
amount = screenWidth + imgWidth;
}
var moveRate = 300; // pixels per second to move
var time = amount * 1000 / moveRate;
img$.stop(true)
.animate({left: "+=" + amount}, time, "linear", function() {
// when animation finishes, start over
startMoving(this);
})
}
$(document).ready(function() {
// readjust if window changes size
$(window).resize(function() {
$(".mover").each(function() {
startMoving(this);
});
});
});