123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- import curves from './config/curves'
- const defaultTransitionBC = 'linear'
- /**
- * @description Get the N-frame animation state by the start and end state
- * of the animation and the easing curve
- * @param {String|Array} tBC Easing curve name or data
- * @param {Number|Array|Object} startState Animation start state
- * @param {Number|Array|Object} endState Animation end state
- * @param {Number} frameNum Number of Animation frames
- * @param {Boolean} deep Whether to use recursive mode
- * @return {Array|Boolean} State of each frame of the animation (Invalid input will return false)
- */
- export function transition (tBC, startState = null, endState = null, frameNum = 30, deep = false) {
- if (!checkParams(...arguments)) return false
- try {
- // Get the transition bezier curve
- const bezierCurve = getBezierCurve(tBC)
- // Get the progress of each frame state
- const frameStateProgress = getFrameStateProgress(bezierCurve, frameNum)
- // If the recursion mode is not enabled or the state type is Number, the shallow state calculation is performed directly.
- if (!deep || typeof endState === 'number') return getTransitionState(startState, endState, frameStateProgress)
- return recursionTransitionState(startState, endState, frameStateProgress)
- } catch(e) {
- console.warn('Transition parameter may be abnormal!')
- return [endState]
- }
- }
- /**
- * @description Check if the parameters are legal
- * @param {String} tBC Name of transition bezier curve
- * @param {Any} startState Transition start state
- * @param {Any} endState Transition end state
- * @param {Number} frameNum Number of transition frames
- * @return {Boolean} Is the parameter legal
- */
- function checkParams (tBC, startState = false, endState = false, frameNum = 30) {
- if (!tBC || startState === false || endState === false || !frameNum) {
- console.error('transition: Missing Parameters!')
- return false
- }
- if (typeof startState !== typeof endState) {
- console.error('transition: Inconsistent Status Types!')
- return false
- }
- const stateType = typeof endState
- if (stateType === 'string' || stateType === 'boolean' || !tBC.length) {
- console.error('transition: Unsupported Data Type of State!')
- return false
- }
- if (!curves.has(tBC) && !(tBC instanceof Array)) {
- // console.warn('transition: Transition curve not found, default curve will be used!')
- }
- return true
- }
- /**
- * @description Get the transition bezier curve
- * @param {String} tBC Name of transition bezier curve
- * @return {Array} Bezier curve data
- */
- function getBezierCurve (tBC) {
- let bezierCurve = ''
- if (curves.has(tBC)) {
- bezierCurve = curves.get(tBC)
- } else if (tBC instanceof Array) {
- bezierCurve = tBC
- } else {
- bezierCurve = curves.get(defaultTransitionBC)
- }
- return bezierCurve
- }
- /**
- * @description Get the progress of each frame state
- * @param {Array} bezierCurve Transition bezier curve
- * @param {Number} frameNum Number of transition frames
- * @return {Array} Progress of each frame state
- */
- function getFrameStateProgress (bezierCurve, frameNum) {
- const tMinus = 1 / (frameNum - 1)
- const tState = new Array(frameNum).fill(0).map((t, i) => i * tMinus)
- const frameState = tState.map(t => getFrameStateFromT(bezierCurve, t))
- return frameState
- }
- /**
- * @description Get the progress of the corresponding frame according to t
- * @param {Array} bezierCurve Transition bezier curve
- * @param {Number} t Current frame t
- * @return {Number} Progress of current frame
- */
- function getFrameStateFromT (bezierCurve, t) {
- const tBezierCurvePoint = getBezierCurvePointFromT(bezierCurve, t)
- const bezierCurvePointT = getBezierCurvePointTFromReT(tBezierCurvePoint, t)
- return getBezierCurveTState(tBezierCurvePoint, bezierCurvePointT)
- }
- /**
- * @description Get the corresponding sub-curve according to t
- * @param {Array} bezierCurve Transition bezier curve
- * @param {Number} t Current frame t
- * @return {Array} Sub-curve of t
- */
- function getBezierCurvePointFromT (bezierCurve, t) {
- const lastIndex = bezierCurve.length - 1
- let [begin, end] = ['', '']
- bezierCurve.findIndex((item, i) => {
- if (i === lastIndex) return
- begin = item
- end = bezierCurve[i + 1]
- const currentMainPointX = begin[0][0]
- const nextMainPointX = end[0][0]
- return t >= currentMainPointX && t < nextMainPointX
- })
- const p0 = begin[0]
- const p1 = begin[2] || begin[0]
- const p2 = end[1] || end[0]
- const p3 = end[0]
- return [p0, p1, p2, p3]
- }
- /**
- * @description Get local t based on t and sub-curve
- * @param {Array} bezierCurve Sub-curve
- * @param {Number} t Current frame t
- * @return {Number} local t of sub-curve
- */
- function getBezierCurvePointTFromReT (bezierCurve, t) {
- const reBeginX = bezierCurve[0][0]
- const reEndX = bezierCurve[3][0]
- const xMinus = reEndX - reBeginX
- const tMinus = t - reBeginX
- return tMinus / xMinus
- }
- /**
- * @description Get the curve progress of t
- * @param {Array} bezierCurve Sub-curve
- * @param {Number} t Current frame t
- * @return {Number} Progress of current frame
- */
- function getBezierCurveTState ([[, p0], [, p1], [, p2], [, p3]], t) {
- const { pow } = Math
- const tMinus = 1 - t
- const result1 = p0 * pow(tMinus, 3)
- const result2 = 3 * p1 * t * pow(tMinus, 2)
- const result3 = 3 * p2 * pow(t, 2) * tMinus
- const result4 = p3 * pow(t, 3)
- return 1 - (result1 + result2 + result3 + result4)
- }
- /**
- * @description Get transition state according to frame progress
- * @param {Any} startState Transition start state
- * @param {Any} endState Transition end state
- * @param {Array} frameState Frame state progress
- * @return {Array} Transition frame state
- */
- function getTransitionState (begin, end, frameState) {
- let stateType = 'object'
- if (typeof begin === 'number') stateType = 'number'
- if (begin instanceof Array) stateType = 'array'
- if (stateType === 'number') return getNumberTransitionState(begin, end, frameState)
- if (stateType === 'array') return getArrayTransitionState(begin, end, frameState)
- if (stateType === 'object') return getObjectTransitionState(begin, end, frameState)
- return frameState.map(t => end)
- }
- /**
- * @description Get the transition data of the number type
- * @param {Number} startState Transition start state
- * @param {Number} endState Transition end state
- * @param {Array} frameState Frame state progress
- * @return {Array} Transition frame state
- */
- function getNumberTransitionState (begin, end, frameState) {
- const minus = end - begin
- return frameState.map(s => begin + minus * s)
- }
- /**
- * @description Get the transition data of the array type
- * @param {Array} startState Transition start state
- * @param {Array} endState Transition end state
- * @param {Array} frameState Frame state progress
- * @return {Array} Transition frame state
- */
- function getArrayTransitionState (begin, end, frameState) {
- const minus = end.map((v, i) => {
- if (typeof v !== 'number') return false
- return v - begin[i]
- })
- return frameState.map(s =>
- minus.map((v, i) => {
- if (v === false) return end[i]
- return begin[i] + v * s
- }))
- }
- /**
- * @description Get the transition data of the object type
- * @param {Object} startState Transition start state
- * @param {Object} endState Transition end state
- * @param {Array} frameState Frame state progress
- * @return {Array} Transition frame state
- */
- function getObjectTransitionState (begin, end, frameState) {
- const keys = Object.keys(end)
- const beginValue = keys.map(k => begin[k])
- const endValue = keys.map(k => end[k])
- const arrayState = getArrayTransitionState(beginValue, endValue, frameState)
- return arrayState.map(item => {
- const frameData = {}
- item.forEach((v, i) => (frameData[keys[i]] = v))
- return frameData
- })
- }
- /**
- * @description Get the transition state data by recursion
- * @param {Array|Object} startState Transition start state
- * @param {Array|Object} endState Transition end state
- * @param {Array} frameState Frame state progress
- * @return {Array} Transition frame state
- */
- function recursionTransitionState (begin, end, frameState) {
- const state = getTransitionState(begin, end, frameState)
- for (let key in end) {
- const bTemp = begin[key]
- const eTemp = end[key]
- if (typeof eTemp !== 'object') continue
- const data = recursionTransitionState(bTemp, eTemp, frameState)
- state.forEach((fs, i) => (fs[key] = data[i]))
- }
- return state
- }
- /**
- * @description Inject new curve into curves as config
- * @param {Any} key The key of curve
- * @param {Array} curve Bezier curve data
- * @return {Undefined} No return
- */
- export function injectNewCurve (key, curve) {
- if (!key || !curve) {
- console.error('InjectNewCurve Missing Parameters!')
- return
- }
- curves.set(key, curve)
- }
- export default transition
|