Reputation: 5844
I have a circle. I want to create a function that animates it from 1 scale to 0.8 and back to 1. What I currently have works, but when I invoke it several times in a row with little delay, the animations conflict and the circle ends up with a different (smaller) scale.
While doing all that scaling stuff, I want the circle to remain at its position. Also, I want the scaling to be done with an anchor point at the center of the circle. This is currently the case.
Take a look at this fiddle.
Because of the above reasons, I get the circle's current transform:
var trans = elem.attr("transform");
reset its scale:
trans.totalMatrix.scale(1);
and apply it:
elem.attr({transform: trans});
Then, I animate()
to the desired scale (0.8
in this case) like so:
transform: "s" + scale + "," + scale + trans
and when that completes, I animate()
back to the original transform with scale 1
:
transform: trans
After the animation is run several times, the circle ends up with a smaller scale. Why?
Edit:
The delay between the animations is intentionally smaller than the length of the animation itself. My question is how to make the animation work despite that.
Upvotes: 0
Views: 338
Reputation: 13842
You need to store the initial transformation, otherwise with multiple animations on the same object, they will get confused (they will anyway). So firstly, you need to make sure the animations aren't overlapping. I see from the other comments, this is part of an example, so leaving that aside for the moment, but make sure that doesn't happen in live code :).
So you can store the transformation
var trans = circ.attr("transform");
Then pass it into the func
bounce(circ, 0.8, 500, trans);
And in the func, use that...
var bounce = function (elem, scale, duration, trans) {
....
Upvotes: 0
Reputation: 101820
Your main problem was that the value in your setInterval()
was too short. You were restarting the animation before it was finished.
You can also simplify everything a little if you don't try and merge two transforms. Move the translate()
to a parent group, and things are a little cleaner.
var snapelem = Snap("svg");
circ = snapelem.select("#mycirc");
var bounce = function (elem, scale, duration) {
elem.animate({
transform: "s" + scale + "," + scale
}, duration * 0.33, mina.easeout, function () {
elem.animate({
transform: "s1,1"
}, duration * 0.67, mina.easein);
});
};
var count = 0;
setInterval(function () {
if (++count > 10) return;
bounce(circ, 0.8, 500);
}, 500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<svg height="300px" width="500px">
<g transform="translate(40 40)">
<circle id="mycirc" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</g>
</svg>
Upvotes: 1
Reputation: 876
I changed the bounce and setInterval functions like this and It worked well. The setInterval time must be greater than 500ms (I used 550ms), and in the callback of animate function you shouldn't use the scale (0.8) again, you must return it to its default scale, which is 1:
var bounce = function (elem, scale, duration) {
var trans = elem.attr("transform");
trans.totalMatrix.scale(1);
elem.attr({
transform: trans
});
elem.animate({
transform: "s" + scale + "," + scale + trans
}, duration * 0.33, mina.easeout, function () {
elem.animate({
transform: "s" + 1 + "," + 1 + trans // I changed the scale to 1
}, duration * 0.67, mina.easein);
});
};
var count = 0;
setInterval(function () {
if (++count > 10) return;
bounce(circ, .8, 500);
}, 550); // I canged this to 550
Upvotes: 0