I'm trying to let a cricle spin and on mouseenter I want the circle to stop spinning and rotate "x" degree, on mouseleave the circle should spin back to its origin and continue the spinning animation.
function rotatingCircle(degree) {
var test =
anime({
targets: [document.getElementsByTagName("svg")[0]],
rotate: degree,
duration: 800,
loop: true,
elasticity: 0,
easing: "linear"
});
};
rotatingCircle(360);
var buttonEl = document.querySelector('.trigger');
var circleOne = document.getElementsByTagName("svg");
buttonEl.addEventListener('mouseenter', rotatingCircle(20));
buttonEl.addEventListener('mouseleave', rotatingCircle(0));
Add the moment my svg is not rotating at all. When I remove the 'mouseenter' and 'mouseleave' event, then my svg is rotating as wanted. How do I keep a rotating loop animation AND can add a 'mouseenter' / 'mouseleave' event, which triggers the rotating SVG to rotate to a specifig angle?
One problem I see with your code is that
buttonEl.addEventListener('mouseenter', rotatingCircle(20));
buttonEl.addEventListener('mouseleave', rotatingCircle(0));
are actually calling the function rotatingCircle where as you want to send a function name or anonymous function here instead.
Function name example if these were parameterless functions
buttonEl.addEventListener('mouseenter', rotatingCircle);
buttonEl.addEventListener('mouseleave', rotatingCircle);
Anonymous function example when you need to send parameters (use this one)
buttonEl.addEventListener('mouseenter', () => rotatingCircle(20));
buttonEl.addEventListener('mouseleave', () => rotatingCircle(20));
How to think about it with an example:
listeners just need the reference to what to call when they are triggered, they don't need what the function returns from calling
I made a code sandbox of what I think you are talking about. Check it out here: https://codesandbox.io/s/aninejs-different-animations-for-different-hover-states-ld76r
Related
Just to see how event bubbling works I created many div controls, one into another and so on and finally attached click event to all the div which make div to flash whenever it is clicked. I was hoping that one div will flash then another and like this it will bubble up to the parent but all the div's are flashing at the same time.
Why doesn't one event handler complete before calling another one? Does animate function is doing something? Because it doesn't happen normally, I had always noticed that only after completing one event handler another one gets called.
Here is my js:
$("div").on("click", function (e) {
$(this).animate({ backgroundColor: "red" }, 400, "swing", function () {
$(this).animate({ backgroundColor: "white" }, 400, "swing")
})
})
Here is Html:
<div><div><div><div><div><div><div>
</div></div></div></div></div></div></div>
From Jquery http://api.jquery.com/animate/
Animation Properties and Values
All animated properties should be animated to a single numeric value, except as noted below; most properties that are non-numeric cannot be animated using basic jQuery functionality (For example, width, height, or left can be animated but background-color cannot be, unless the jQuery.Color plugin is used). Property values are treated as a number of pixels unless otherwise specified. The units em and % can be specified where applicable.
There is a plugin mentioned from that page to allow animating the background color. Also in your code you may or may not want to incorporate:
e.stopPropogation();
That will stop the div event from bubbling up.
You could:
$("div").on("click", function (e) {
$(this).css({backgroundColor: "red", opacity: 0})
$(this).animate({ opacity: 1 }, 400, "swing", function () {
$(this).css({backgroundColor: "white", opacity: 0})
$(this).animate({ opacity: 1 }, 400, "swing")
})
})
It will have a different effect though, the div will disappear and reappear red, then disappear and reappear white.
If you are just trying to pause the propagation then restart at the end of the annimation you could just retrigger the event on the parent element;
$("div.animate").on("click", function (e) {
e.stopPropagation();
$(this).animate({ backgroundColor: "red" }, 400, "swing", function () {
$(this).animate({ backgroundColor: "white" }, 400, "swing", function(){
$(e.target.parentElement).trigger(e.type);
})
})
})
To make only certain divs animate just add a class to them "animate" for instance and then attach the handler to divs with animate only and any other div will propogate the click automatically with your animation classed divs stopping the propogation, animating and when finished passing up the DOM tree.
I am trying to use VelocityJS in one of my React projects. The use case where I am facing the problem is:
There is pointer created in SVG, initially at the center of the screen. I want to move the pointer with the keyboard arrow keys. I have maintained a state variable for updating the X and Y values of the pointer on keydown event. On the callback of setState, I am calling a translate function which animates the translation. But the problem I faced is that The animation always happened from the initial position of the pointer i.e. center of the screen. So as a workaround I tried was that I maintained the previous position of the pointer in state too, using forcefeeding in velocityJS. Someone go through my code and see if I am doing something wrong.
$(".Aim").velocity(
{
translateX: [this.state.aimX, this.state.aimXOld],
translateY: [this.state.aimY, this.state.aimYOld]
},
{
duration: 500,
easing: [0.46, 0.46, 0.46, 0.46],
complete: () => {
console.log("completed");
}
}
);
I'm trying to write a simple card game on canvas + Fabricjs. Need to make bigger player's card when mouse is on it and return to normal size if mouse is out.
Here is my js code:
canvas.on('mouse:over', function(e) {
if(e.target.mytype && e.target.mytype=='card'){
e.target.animate({
top:352,
left: e.target.left - (max_width - min_width)/2,
scaleX:0.4,
scaleY:0.4
} , {
duration: 500,
onChange: function(value) {
canvas.renderAll.bind(canvas);
},
easing: fabric.util.ease.easeInOut
});
canvas.renderAll();
}
});
canvas.on('mouse:out', function(e) {
if(e.target.mytype && e.target.mytype=='card'){
e.target.animate({
top:385,
left: e.target.left + (max_width - min_width)/2,
scaleX:0.3,
scaleY:0.3
} , {
duration: 500,
onChange: function(value) {
canvas.renderAll.bind(canvas);
},
easing: fabric.util.ease.easeInOut
});
canvas.renderAll();
}
});
if player hover the card for 200ms (animation duration is 500ms) and move out, the animation freeze and the card remains at a new position. Hovering again wil start animation from this new position.
Here is a fiddle
Just try to move mouse in/out on the object and you'll see the bug. Please, help me to fix this.
The problem is the way that your code has relative positioning changes within the animation action - in the jsFiddle, the "top" value, in your code above, in the "left" value.
What each of these do is move the element +X or -X from the position the event starts at. If the animation finishes before the mouseout event is fired, it's fine, because the amount it moves back is equal (but opposite) to the amount it moved in the mouseover event.
However, if the animation for mouseout starts Before the first is finished, it takes it's current position, not the position it will be at when it finishes the animation. This leads to a situation where the element drifts away from its original position. This is certainly what the issue is in the JSFiddle, I understand from your comments that this is the same issue in your own code.
How to resolve it? As long as you are using a fixed relative position value in the mouseout event you probably can't. You could try logging the initial positioning (i.e., the value of "left/top" you started at) in the mouseover function and returning specifically to that point in the mouseout event.
I've been struggling with this issue for awhile and have decided to ditch the setTimeout approach since I just read creating too many timers is bad. Below is the function to animate a group of objects - which is called on hover. It's currently setup so that all animation settings are passed in from the user and apply to the correct object, then each object is animated on a per-property basis - allowing for control of speed in/out and easing for each property.
The only thing I'm working on now is the delays. I can't use .delay since it isn't queued and I can't use setTimeout (at least in the approach I've taken). Any ideas?
function animate_in(e){
$(this).find('.captionator_background').each(function(index){
// LOOP THROUGH OBJECTS
current_obj = $(this); current_obj.stop().clearQueue();
// 1. LEFT ANIMATION
current_obj.animate({'left':ends_x_set[index]},{duration:parseInt(bg_x_speed_in_set[index], 10), queue:false, specialEasing: {'left':bg_x_ease_in_set[index]}});
// 2. TOP ANIMATION
current_obj.animate({'top':ends_y_set[index]},{duration:parseInt(bg_y_speed_in_set[index], 10), queue:false, specialEasing: {'top': bg_y_ease_in_set[index]}});
// 3. OPACITY ANIMATION
current_obj.animate({'opacity':parseInt(end_opacity_set[index], 10)},{duration:parseInt(opacity_speed_in_set[index], 10), queue:false, specialEasing: {'opacity':opacity_ease_in_set[index]}});
// 4. BACKGROUND COLOR ANIMATION
current_obj.animate({'backgroundColor':bg_color_in_set[index]},{duration:parseInt(bg_color_speed_in_set[index], 10), queue:false, specialEasing: {'backgroundColor':bg_color_ease_in_set[index]}});
}); // END EACH LOOP
}; // END ANIMATE IN FUNCTION
Thanks!
Using Raphael JS, is there a way to make a circle move to the right (or any direction) during mouseover, and then pause/stop the movement when the cursor is no longer on the circle.
I've tried few different methods, but they have bugs. One of the main issues is: if the mouse cursor doesn't move after entering the circle, "mouseout" will not be triggered once the circle moves to a location where the mouse cursor is no longer over top of the circle.
You'll see what I mean in these different attempts:
1) Animate with pause / resume:
jsfiddle.net/fKKNt/
But the animation is jerky and unreliable. If you hover over the object, as the object moves outside of where the mouse cursor is, it doesn't trigger the "mouseout" listener.
2) Repositioning with mouseover & .attr("cx"):
jsfiddle.net/c4BFt/
But we want the animation to continue while the cursor is in the circle too.
3) Using setInterval (as suggested in:
An "if mouseover" or a "do while mouseover" in JavaScript/jQuery):
jsfiddle.net/9bBcm/
But "mouseout" is not called as the circle moves outside of where the cursor lies. I.e. the circle move to a location where "mouseout" should be called, but it is not called.
The same thing happens with "hover":
jsfiddle.net/STruB/
I'm sure there's a much more elegant way to do this, but off the top of my head, you could try something like this: http://jsfiddle.net/D6Ps4/2/
In case that disappears for some reason, I've included the code below. The solution simply initiates the animation, then checks to see if the mouse cursor (note the e.offsetX/e.offsetY) is within the bounding box of your Raphael Object (Element.getBBox()) at some set interval. If it is, do nothing and use setTimeout to check again in some time, if it's not, pause the animation.
var paper = Raphael("holder");
var animObject = Raphael.animation({cx: 400}, 5000);
circle = paper.circle(90, 90, 45).attr({fill: "#0E4"});
var timer;
circle.mouseover(function(e) {
var anim = function(shouldAnim) {
if (shouldAnim) {
circle.animate(animObject);
}
if (!mouseInsideCircle(e, circle)) {
circle.pause();
return;
} else {
timer = setTimeout(function() {anim(false)}, 20);
}
}
anim(true);
});
circle.mouseout(function() {
this.pause();
clearTimeout(timer);
});
var mouseInsideCircle = function(e, c) {
var bb = c.getBBox();
if (e.offsetX > bb.x && e.offsetY > bb.y) {
return true;
}
return false;
}
I'm sure the solution is flawed (it's checking the boundBox, not the circle itself; it also assumes the circle is moving right) and perhaps not ideal, but it seems to work reasonably smoothly and hopefully gets you on the right path.