219 lines
6.2 KiB
JavaScript
219 lines
6.2 KiB
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.
|
|
|
|
import eve from './eve.js'
|
|
import { SnapElement } from './svg.js'
|
|
import mina from './mina.js'
|
|
import { is } from './utils.js'
|
|
|
|
let elproto = SnapElement.prototype,
|
|
Str = String,
|
|
has = 'hasOwnProperty'
|
|
function slice(from, to, f) {
|
|
return function (arr) {
|
|
let res = arr.slice(from, to)
|
|
if (res.length == 1) {
|
|
res = res[0]
|
|
}
|
|
return f ? f(res) : res
|
|
}
|
|
}
|
|
let 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)
|
|
}
|
|
export { Animation }
|
|
/**
|
|
* 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
|
|
*/
|
|
export function createAnimation(attr, ms, easing, callback) {
|
|
return new Animation(attr, ms, easing, callback)
|
|
}
|
|
/**
|
|
* Returns a set of animations that may be able to manipulate the current element
|
|
**
|
|
= (object) in format:
|
|
{
|
|
anim (object) animation object,
|
|
mina (object) @mina object,
|
|
curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
|
|
status (function) gets or sets the status of the animation,
|
|
stop (function) stops the animation
|
|
}
|
|
*/
|
|
elproto.inAnim = function () {
|
|
let el = this
|
|
let res = []
|
|
|
|
for (let id in el.anims) {
|
|
if (el.anims.hasOwnProperty(id)) {
|
|
let a = el.anims[id]
|
|
res.push({
|
|
anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
|
|
mina: a,
|
|
curStatus: a.status(),
|
|
status(val) {
|
|
return a.status(val)
|
|
},
|
|
stop() {
|
|
a.stop()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
/**
|
|
* 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
|
|
{
|
|
id (string) animation id, consider it read-only,
|
|
duration (function) gets or sets the duration of the animation,
|
|
easing (function) easing,
|
|
speed (function) gets or sets the speed of the animation,
|
|
status (function) gets or sets the status of the animation,
|
|
stop (function) stops the animation
|
|
}
|
|
let rect = new Snap().rect(0, 0, 10, 10);
|
|
animate(0, 10, function (val) {
|
|
rect.attr({
|
|
x: val
|
|
});
|
|
}, 1000);
|
|
// in given context is equivalent to
|
|
rect.animate({x: 10}, 1000);
|
|
*/
|
|
export function animate(from, to, setter, ms, easing, callback) {
|
|
if (typeof easing == 'function' && !easing.length) {
|
|
callback = easing
|
|
easing = mina.linear
|
|
}
|
|
let now = mina.time(),
|
|
anim = mina(from, to, now, now + ms, mina.time, setter, easing)
|
|
callback && eve.once('mina.finish.' + anim.id, callback)
|
|
return anim
|
|
}
|
|
/*\
|
|
* SnapElement.stop
|
|
[ method ]
|
|
**
|
|
* Stops all the animations for the current element
|
|
**
|
|
= (SnapElement) the current element
|
|
\*/
|
|
elproto.stop = function () {
|
|
let anims = this.inAnim()
|
|
for (let i = 0, ii = anims.length; i < ii; i++) {
|
|
anims[i].stop()
|
|
}
|
|
return this
|
|
}
|
|
/*\
|
|
* SnapElement.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
|
|
= (SnapElement) 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
|
|
}
|
|
let fkeys = [],
|
|
tkeys = [],
|
|
keys = {},
|
|
from,
|
|
to,
|
|
f,
|
|
eq,
|
|
el = this
|
|
for (let 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]
|
|
}
|
|
let len = is(from, 'array') ? from.length : 1
|
|
keys[key] = slice(fkeys.length, fkeys.length + len, f)
|
|
fkeys = fkeys.concat(from)
|
|
tkeys = tkeys.concat(to)
|
|
}
|
|
let now = mina.time(),
|
|
anim = mina(
|
|
fkeys,
|
|
tkeys,
|
|
now,
|
|
now + ms,
|
|
mina.time,
|
|
function (val) {
|
|
let attr = {}
|
|
for (let 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
|
|
}
|