snapsvg
Version:
JavaScript Vector Library
208 lines (207 loc) • 7.4 kB
JavaScript
// Copyright (c) 2016 Adobe Systems Incorporated. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
var elproto = Element.prototype,
is = Snap.is,
Str = String,
has = "hasOwnProperty";
function slice(from, to, f) {
return function (arr) {
var res = arr.slice(from, to);
if (res.length == 1) {
res = res[0];
}
return f ? f(res) : res;
};
}
var Animation = function (attr, ms, easing, callback) {
if (typeof easing == "function" && !easing.length) {
callback = easing;
easing = mina.linear;
}
this.attr = attr;
this.dur = ms;
easing && (this.easing = easing);
callback && (this.callback = callback);
};
Snap._.Animation = Animation;
/*\
* Snap.animation
[ method ]
**
* Creates an animation object
**
- attr (object) attributes of final destination
- duration (number) duration of the animation, in milliseconds
- easing (function) #optional one of easing functions of @mina or custom one
- callback (function) #optional callback function that fires when animation ends
= (object) animation object
\*/
Snap.animation = function (attr, ms, easing, callback) {
return new Animation(attr, ms, easing, callback);
};
/*\
* Element.inAnim
[ method ]
**
* Returns a set of animations that may be able to manipulate the current element
**
= (object) in format:
o {
o anim (object) animation object,
o mina (object) @mina object,
o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
o status (function) gets or sets the status of the animation,
o stop (function) stops the animation
o }
\*/
elproto.inAnim = function () {
var el = this,
res = [];
for (var id in el.anims) if (el.anims[has](id)) {
(function (a) {
res.push({
anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
mina: a,
curStatus: a.status(),
status: function (val) {
return a.status(val);
},
stop: function () {
a.stop();
}
});
}(el.anims[id]));
}
return res;
};
/*\
* Snap.animate
[ method ]
**
* Runs generic animation of one number into another with a caring function
**
- from (number|array) number or array of numbers
- to (number|array) number or array of numbers
- setter (function) caring function that accepts one number argument
- duration (number) duration, in milliseconds
- easing (function) #optional easing function from @mina or custom
- callback (function) #optional callback function to execute when animation ends
= (object) animation object in @mina format
o {
o id (string) animation id, consider it read-only,
o duration (function) gets or sets the duration of the animation,
o easing (function) easing,
o speed (function) gets or sets the speed of the animation,
o status (function) gets or sets the status of the animation,
o stop (function) stops the animation
o }
| var rect = Snap().rect(0, 0, 10, 10);
| Snap.animate(0, 10, function (val) {
| rect.attr({
| x: val
| });
| }, 1000);
| // in given context is equivalent to
| rect.animate({x: 10}, 1000);
\*/
Snap.animate = function (from, to, setter, ms, easing, callback) {
if (typeof easing == "function" && !easing.length) {
callback = easing;
easing = mina.linear;
}
var now = mina.time(),
anim = mina(from, to, now, now + ms, mina.time, setter, easing);
callback && eve.once("mina.finish." + anim.id, callback);
return anim;
};
/*\
* Element.stop
[ method ]
**
* Stops all the animations for the current element
**
= (Element) the current element
\*/
elproto.stop = function () {
var anims = this.inAnim();
for (var i = 0, ii = anims.length; i < ii; i++) {
anims[i].stop();
}
return this;
};
/*\
* Element.animate
[ method ]
**
* Animates the given attributes of the element
**
- attrs (object) key-value pairs of destination attributes
- duration (number) duration of the animation in milliseconds
- easing (function) #optional easing function from @mina or custom
- callback (function) #optional callback function that executes when the animation ends
= (Element) the current element
\*/
elproto.animate = function (attrs, ms, easing, callback) {
if (typeof easing == "function" && !easing.length) {
callback = easing;
easing = mina.linear;
}
if (attrs instanceof Animation) {
callback = attrs.callback;
easing = attrs.easing;
ms = attrs.dur;
attrs = attrs.attr;
}
var fkeys = [], tkeys = [], keys = {}, from, to, f, eq,
el = this;
for (var key in attrs) if (attrs[has](key)) {
if (el.equal) {
eq = el.equal(key, Str(attrs[key]));
from = eq.from;
to = eq.to;
f = eq.f;
} else {
from = +el.attr(key);
to = +attrs[key];
}
var len = is(from, "array") ? from.length : 1;
keys[key] = slice(fkeys.length, fkeys.length + len, f);
fkeys = fkeys.concat(from);
tkeys = tkeys.concat(to);
}
var now = mina.time(),
anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
var attr = {};
for (var key in keys) if (keys[has](key)) {
attr[key] = keys[key](val);
}
el.attr(attr);
}, easing);
el.anims[anim.id] = anim;
anim._attrs = attrs;
anim._callback = callback;
eve("snap.animcreated." + el.id, anim);
eve.once("mina.finish." + anim.id, function () {
eve.off("mina.*." + anim.id);
delete el.anims[anim.id];
callback && callback.call(el);
});
eve.once("mina.stop." + anim.id, function () {
eve.off("mina.*." + anim.id);
delete el.anims[anim.id];
});
return el;
};
});