hae
Version:
Mobile web UI based on Vux
142 lines (124 loc) • 4.42 kB
JavaScript
const time = Date.now || function () {
return +new Date()
}
let running = {}
let counter = 1
let desiredFrames = 60
let millisecondsPerSecond = 1000
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel
if (typeof window !== 'undefined') {
;(function () {
var lastTime = 0
var vendors = ['ms', 'moz', 'webkit', 'o']
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime()
var timeToCall = Math.max(0, 16 - (currTime - lastTime))
var id = window.setTimeout(function () {
callback(currTime + timeToCall)
}, timeToCall)
lastTime = currTime + timeToCall
return id
}
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id)
}
}
}())
}
export default {
// A requestAnimationFrame wrapper / polyfill.
requestAnimationFrame: (function () {
if (typeof window !== 'undefined') {
var requestFrame = window.requestAnimationFrame
return function (callback, root) {
requestFrame(callback, root)
}
}
})(),
// Stops the given animation.
stop (id) {
var cleared = running[id] != null
if (cleared) {
running[id] = null
}
return cleared
},
// Whether the given animation is still running.
isRunning (id) {
return running[id] != null
},
// Start the animation.
start (stepCallback, verifyCallback, completedCallback, duration, easingMethod, root) {
var _this = this
var start = time()
var lastFrame = start
var percent = 0
var dropCounter = 0
var id = counter++
if (!root) {
root = document.body
}
// Compacting running db automatically every few new animations
if (id % 20 === 0) {
var newRunning = {}
for (var usedId in running) {
newRunning[usedId] = true
}
running = newRunning
}
// This is the internal step method which is called every few milliseconds
var step = function (virtual) {
// Normalize virtual value
var render = virtual !== true
// Get current time
var now = time()
// Verification is executed before next animation step
if (!running[id] || (verifyCallback && !verifyCallback(id))) {
running[id] = null
completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), id, false)
return
}
// For the current rendering to apply let's update omitted steps in memory.
// This is important to bring internal state variables up-to-date with progress in time.
if (render) {
var droppedFrames = Math.round((now - lastFrame) / (millisecondsPerSecond / desiredFrames)) - 1
for (var j = 0; j < Math.min(droppedFrames, 4); j++) {
step(true)
dropCounter++
}
}
// Compute percent value
if (duration) {
percent = (now - start) / duration
if (percent > 1) {
percent = 1
}
}
// Execute step callback, then...
var value = easingMethod ? easingMethod(percent) : percent
if ((stepCallback(value, now, render) === false || percent === 1) && render) {
running[id] = null
completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), id, percent === 1 || duration == null)
} else if (render) {
lastFrame = now
_this.requestAnimationFrame(step, root)
}
}
// Mark as running
running[id] = true
// Init first step
_this.requestAnimationFrame(step, root)
// Return unique animation ID
return id
}
}