snapsvg/src/mina.js

355 lines
8.0 KiB
JavaScript
Raw Normal View History

2024-03-05 13:02:24 +08:00
// Copyright (c) 2017 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 { Snap } from './svg.js'
2024-03-06 18:36:03 +08:00
import { uuid } from './utils.js'
2024-03-05 13:02:24 +08:00
2024-03-06 18:36:03 +08:00
let animations = {},
2024-03-05 13:02:24 +08:00
requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
2024-03-06 18:36:03 +08:00
window.mozRequestAnimationFrame,
2024-03-05 13:02:24 +08:00
requestID,
2024-03-06 18:36:03 +08:00
isArray = Array.isArray,
2024-03-05 13:02:24 +08:00
diff = function (a, b, A, B) {
if (isArray(a)) {
res = []
2024-03-06 18:36:03 +08:00
for (let i = 0, ii = a.length; i < ii; i++) {
2024-03-05 13:02:24 +08:00
res[i] = diff(a[i], b, A[i], B)
}
return res
}
2024-03-06 18:36:03 +08:00
let dif = (A - a) / (B - b)
2024-03-05 13:02:24 +08:00
return function (bb) {
return a + dif * (bb - b)
}
},
2024-03-06 18:36:03 +08:00
timer = Date.now,
2024-03-05 13:02:24 +08:00
sta = function (val) {
2024-03-06 18:36:03 +08:00
let a = this
2024-03-05 13:02:24 +08:00
if (val == null) {
return a.s
}
2024-03-06 18:36:03 +08:00
let ds = a.s - val
2024-03-05 13:02:24 +08:00
a.b += a.dur * ds
a.B += a.dur * ds
a.s = val
},
speed = function (val) {
if (val == null) {
2024-03-06 18:36:03 +08:00
return this.spd
2024-03-05 13:02:24 +08:00
}
2024-03-06 18:36:03 +08:00
this.spd = val
2024-03-05 13:02:24 +08:00
},
duration = function (val) {
if (val == null) {
2024-03-06 18:36:03 +08:00
return this.dur
2024-03-05 13:02:24 +08:00
}
2024-03-06 18:36:03 +08:00
this.s = (this.s * val) / this.dur
this.dur = val
2024-03-05 13:02:24 +08:00
},
stopit = function () {
2024-03-06 18:36:03 +08:00
delete animations[this.id]
this.update()
eve('mina.stop.' + this.id, a)
2024-03-05 13:02:24 +08:00
},
pause = function () {
2024-03-06 18:36:03 +08:00
let a = this
2024-03-05 13:02:24 +08:00
if (a.pdif) {
return
}
delete animations[a.id]
a.update()
a.pdif = a.get() - a.b
},
resume = function () {
2024-03-06 18:36:03 +08:00
let a = this
2024-03-05 13:02:24 +08:00
if (!a.pdif) {
return
}
a.b = a.get() - a.pdif
delete a.pdif
animations[a.id] = a
frame()
},
update = function () {
2024-03-06 18:36:03 +08:00
let a = this,
2024-03-05 13:02:24 +08:00
res
if (isArray(a.start)) {
res = []
2024-03-06 18:36:03 +08:00
for (let j = 0, jj = a.start.length; j < jj; j++) {
2024-03-05 13:02:24 +08:00
res[j] = +a.start[j] + (a.end[j] - a.start[j]) * a.easing(a.s)
}
} else {
res = +a.start + (a.end - a.start) * a.easing(a.s)
}
a.set(res)
},
frame = function (timeStamp) {
// Manual invokation?
if (!timeStamp) {
// Frame loop stopped?
if (!requestID) {
// Start frame loop...
requestID = requestAnimFrame(frame)
}
return
}
2024-03-06 18:36:03 +08:00
let len = 0
for (let i in animations)
2024-03-05 13:02:24 +08:00
if (animations.hasOwnProperty(i)) {
2024-03-06 18:36:03 +08:00
let a = animations[i],
2024-03-05 13:02:24 +08:00
b = a.get(),
res
len++
a.s = (b - a.b) / (a.dur / a.spd)
if (a.s >= 1) {
delete animations[i]
a.s = 1
len--
;(function (a) {
setTimeout(function () {
eve('mina.finish.' + a.id, a)
})
})(a)
}
a.update()
}
requestID = len ? requestAnimFrame(frame) : false
},
/*\
* mina
[ method ]
**
* Generic animation of numbers
**
- a (number) start _slave_ number
- A (number) end _slave_ number
- b (number) start _master_ number (start time in general case)
- B (number) end _master_ number (end time in general case)
- get (function) getter of _master_ number (see @mina.time)
- set (function) setter of _slave_ number
- easing (function) #optional easing function, default is @mina.linear
= (object) animation descriptor
o {
o id (string) animation id,
o start (number) start _slave_ number,
o end (number) end _slave_ number,
o b (number) start _master_ number,
o s (number) animation status (0..1),
o dur (number) animation duration,
o spd (number) animation speed,
o get (function) getter of _master_ number (see @mina.time),
o set (function) setter of _slave_ number,
o easing (function) easing function, default is @mina.linear,
o status (function) status getter/setter,
o speed (function) speed getter/setter,
o duration (function) duration getter/setter,
o stop (function) animation stopper
o pause (function) pauses the animation
o resume (function) resumes the animation
o update (function) calles setter with the right value of the animation
o }
\*/
mina = function (a, A, b, B, get, set, easing) {
2024-03-06 18:36:03 +08:00
let anim = {
id: uuid('M'),
2024-03-05 13:02:24 +08:00
start: a,
end: A,
b: b,
s: 0,
dur: B - b,
spd: 1,
get: get,
set: set,
easing: easing || mina.linear,
status: sta,
speed: speed,
duration: duration,
stop: stopit,
pause: pause,
resume: resume,
update: update
}
animations[anim.id] = anim
2024-03-06 18:36:03 +08:00
let len = 0,
2024-03-05 13:02:24 +08:00
i
for (i in animations)
if (animations.hasOwnProperty(i)) {
len++
if (len == 2) {
break
}
}
len == 1 && frame()
return anim
}
/*\
* mina.time
[ method ]
**
* Returns the current time. Equivalent to:
| function () {
| return (new Date).getTime();
| }
\*/
mina.time = timer
/*\
* mina.getById
[ method ]
**
* Returns an animation by its id
- id (string) animation's id
= (object) See @mina
\*/
mina.getById = function (id) {
return animations[id] || null
}
/*\
* mina.linear
[ method ]
**
* Default linear easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.linear = function (n) {
return n
}
/*\
* mina.easeout
[ method ]
**
* Easeout easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.easeout = function (n) {
return Math.pow(n, 1.7)
}
/*\
* mina.easein
[ method ]
**
* Easein easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.easein = function (n) {
return Math.pow(n, 0.48)
}
/*\
* mina.easeinout
[ method ]
**
* Easeinout easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.easeinout = function (n) {
if (n == 1) {
return 1
}
if (n == 0) {
return 0
}
2024-03-06 18:36:03 +08:00
let q = 0.48 - n / 1.04,
2024-03-05 13:02:24 +08:00
Q = Math.sqrt(0.1734 + q * q),
x = Q - q,
X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1),
y = -Q - q,
Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1),
t = X + Y + 0.5
return (1 - t) * 3 * t * t + t * t * t
}
/*\
* mina.backin
[ method ]
**
* Backin easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.backin = function (n) {
if (n == 1) {
return 1
}
2024-03-06 18:36:03 +08:00
let s = 1.70158
2024-03-05 13:02:24 +08:00
return n * n * ((s + 1) * n - s)
}
/*\
* mina.backout
[ method ]
**
* Backout easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.backout = function (n) {
if (n == 0) {
return 0
}
n = n - 1
2024-03-06 18:36:03 +08:00
let s = 1.70158
2024-03-05 13:02:24 +08:00
return n * n * ((s + 1) * n + s) + 1
}
/*\
* mina.elastic
[ method ]
**
* Elastic easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.elastic = function (n) {
if (n == !!n) {
return n
}
return (
Math.pow(2, -10 * n) * Math.sin(((n - 0.075) * (2 * Math.PI)) / 0.3) + 1
)
}
/*\
* mina.bounce
[ method ]
**
* Bounce easing
- n (number) input 0..1
= (number) output 0..1
\*/
mina.bounce = function (n) {
2024-03-06 18:36:03 +08:00
let s = 7.5625,
2024-03-05 13:02:24 +08:00
p = 2.75,
l
if (n < 1 / p) {
l = s * n * n
} else {
if (n < 2 / p) {
n -= 1.5 / p
l = s * n * n + 0.75
} else {
if (n < 2.5 / p) {
n -= 2.25 / p
l = s * n * n + 0.9375
} else {
n -= 2.625 / p
l = s * n * n + 0.984375
}
}
}
return l
}
export default mina