Here, I am trying to apply bounce animation to my dynamically generated messages called by API but no effect is coming. Also, I tried using effect() but it was also of no use. Here is the link to my Codepen. Link
$(document).ready(function () {
$("#getMessage").on("click",function () {
//(".message").effect("bounce", {times:300}, 300);
move();
});
var divObj = null;
function init () {
divObj = document.getElementById("message");
// $("#message").toggle("bounce", {times: 6}, "slow");
divObj.style.position = "relative";
divObj.style.top = "0px";
}
function move () {
divObj.style.top = parseInt(divObj.style.top) + 10 + "px";
}
});
What you've supplied above isn't too far off from the result(s) you're looking for. Essentially the {times:300} you are supplying is far too many for the speed/ratio - resulting in no visible animation.
From what I have just tested, any bounces >10 with the speed #300 seem to display in an abnormal manner.
Please see this codepen: http://codepen.io/anon/pen/BWyqpY
Give this a try:
$("#getMessage").on("click",function () {
$(".message").effect("bounce",{times:3},300);
// I'm not sure if you still want this method.
move();
});
Related
I'm playing around with pure JavaScript, so I created a small fade in/out object, to adjust images opacity onmouseover and onmouseout. Fading works fine when the mouseover and mouseout actions are precise:
Start moving the cursor from the white background
Hover over an image
Hover back over the white background
The problem is, as soon as I start to move the mouse "naturally" from one image to another, the fading (or rather the script itself) freezes.
I'm not sure whether it's a animation-speed problem, or there's something I'm missing in the implementation.
If someone has the time to take a look, I would appreciate a peer check, so I can crack the issue and learn new stuff.
Here's a fiddle: http://jsfiddle.net/6bd3xepe/
Thanks!
As I see it, you have one INTERVAL for you FADER, you need one for each IMG.
My jsfiddle fixes this. I added an ALT-attribute to each IMG with "dome" content, so as to circumvent the jsfiddle working on non-cat-images .. ignore that part - commented out below.
There are some fundamental things wrong with the design - keeping track of objects & references is key. Usage of "this" & "that" aren't helping in the current implementation (see comments to OP). Also, on another note, the usage of "toFixed(2)" is not really required IMHO and you can shorten "o = o + 0.1" to "o += 0.1".
JS:
var fader = {
target: document.getElementsByTagName('img'),
interval: [],
speed: 25,
default_opacity: 1,
init: function() {
this.bindEvents();
},
// Get element's opacity and increase it up to 1
fadeIn: function(element) {
var element_opacity = this.getOpacity(element),
that = this,
idx = element.getAttribute('data-idx');
console.log("fI: "+idx+" "+element_opacity);
this.default_opacity = element_opacity.toFixed(2);
this.interval[idx] = setInterval(function() {
if (element_opacity.toFixed(2) < 1) {
element_opacity = element_opacity + 0.1;
element.style.opacity = element_opacity.toFixed(2);
} else {
clearInterval(that.interval[idx]);
}
}, that.speed);
},
// Get current opacity and decrease it back to the default one
fadeOut: function(element) {
var element_opacity = this.getOpacity(element),
that = this,
idx = element.getAttribute('data-idx');
console.log("fO: "+idx+" "+element_opacity);
this.interval[idx] = setInterval(function() {
if (element_opacity.toFixed(2) > that.default_opacity) {
element_opacity = element_opacity - 0.1;
element.style.opacity = element_opacity.toFixed(2);
} else {
clearInterval(that.interval[idx]);
element.removeAttribute('style');
}
}, that.speed);
},
// Get opacity of an element using computed styles
getOpacity: function(element) {
var styles = window.getComputedStyle(element),
opacity = parseFloat(styles.getPropertyValue('opacity'));
return opacity;
},
bindEvents: function() {
var that = this, count = 0;
for (var i in this.target) {
// the whole "dome" is just a fsfiddle hack - otherwise it sees 7 images instead of 4!
//if( this.target[i].alt == "dome" ){
console.log("COUNT: "+count);
this.target[i].setAttribute('data-idx',count);
this.target[i].onmouseover = function() {
that.fadeIn(this);
}
this.target[i].onmouseout = function() {
that.fadeOut(this);
}
count++;
//}
}
}
};
fader.init();
Here I have an odd problem. I'm building a simple helicopter game (the old type - click to go up, avoid obstacles). My problem is that the obstacles generate, but don't position correctly, and then they won't move. I'm trying to move them with jQuery's css() - the css method works fine on anything else but when used with top and left doesn't.
The problem functions (generate and move obstacles):
game.background.generateObs = function() {
var top = Math.floor(Math.random()*game.canvas.height);
var left = game.canvas.width-10;
var $obs = $("<div></div>")
$obs.addClass("obs").appendTo("#canvas");
$obs.css({
background: "black",
position: "absolute",
height: game.obstacle.height,
width: game.obstacle.width,
});
$obs.css("top", $("#canvas").offset().top + top )
.css("left",$("#canvas").offset().left + left);
game.obstacle.width = Math.floor(Math.random()*200);
if(game.gameState=="running") {
setTimeout("game.background.generateObs()",obsInterval);
}
else {
return;
}
}
game.background.moveObs = function() {
var currentPos = $("#canvas div.obs").css("left");
var newPos = currentPos - game.obstacle.frameWidth;
$("#canvas div.obs").css("left",newPos);
if(game.gameState=="running") {
setTimeout("game.background.moveObs()",interval);
}
else {
return;
}
}
The other thing is that jsFiddle is now telling me that game is undefined, when I have defined it right at the start.
Can anyone tell me what I'm doing wrong? Here's the fiddle.
$("#canvas div.obs").css("left") is returning auto in your fiddle, not a number.
Try using .offset().left instead.
Additionally, you should change your setTimeout calls like this:
setTimeout(game.background.moveObs,interval);
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'm trying to put together a fluid sliding panel which should take into account the inner width of the window on load, as well as on resizes : depending on the actual window size, the panel should be moved left / right a fourth of the window width.
So far i managed to bypass the multiple resize events happening when the user resizes the window, thx to this thread.
var waitForFinalEvent = (function () {
var timers = {};
return function (callback, ms, uniqueId) {
if (!uniqueId) {
uniqueId = "Don't call this twice without a uniqueId";
}
if (timers[uniqueId]) {
clearTimeout (timers[uniqueId]);
}
timers[uniqueId] = setTimeout(callback, ms);
};
})();
var slidinNav = function(rtr){
document.getElementById('navPanel').style.left = -rtr + "px";
document.getElementById('navPanel').style.width = rtr + "px";
$('.showMenu').click(function(){
$('#navPanel').animate({left: '+=' + rtr +'px'}, 400);
});
$('.hideMenu').click(function(){
$('#navPanel').animate({left: '-=' + rtr + 'px'}, 400);
});
}
$(document).ready(function(){
var winW = window.innerWidth;
var navPosLeft=winW/4;
slidinNav(navPosLeft);
});
$(window).resize(function () {
waitForFinalEvent(function(){
var winW = window.innerWidth;
var navPosLeft=winW/4;
slidinNav(navPosLeft);
console.log(" Left / Width : " + navPosLeft);
}, 200, "un identifiant unique ?");
});
But being a complete javascript newbie i haven't found the solution to prevent the variables i use to store the window width value and offset to take all the successive values computed.
Better than a long and unclear explanation see jsfiddle here.
Here's my question : Should i reset variables (how and when) or rather try and get the last value (and again : how and when) ?
Thx for any help on this one ; - )
Correct me if I am not understanding exactly what you are looking for here but it looks to me like you may be making it more complicated than it needs to be.
Looks like you could simply just stay with using % and just have these functions:
$('.showMenu').click(function(){
$('#navPanel').animate({left: 0}, 400);
});
$('.hideMenu').click(function(){
$('#navPanel').animate({left: "-20%"}, 400);
});
As demonstrated here: http://jsfiddle.net/X9Jrc/3/
I am newbie in JS. Right now i am working on an effect in which i want when page scroll first time then the natural motion animation starts but it's creating a problem because when i scroll the element animation became fast.
Check this more you got the idea.
http://jsfiddle.net/byvLy/
i know that this is a swinging box (figured it out due to the Math.sin())
however, you have to note that scrolling event is fired every few milliseconds during scrolling. in your code, you are calling animate and creating an interval every time the scroll event is fired. that's why your animation is jumpy;
try this instead:
$(function() {
$(window).on('scroll', function() {
swing.start('.cloud1, .cloud2');
});
var swing = (function() {
var animated = false;
function startAnimation(selector) {
if (!animated) {
var banner = $(selector);
var start = 0;
animated = true;
window.setInterval(function() {
banner.css('left', 100 * Math.sin(start) + 80);
start += 0.1;
}, 30);
}
}
return {
start: startAnimation
}
}());
});