264 lines
No EOL
7.9 KiB
JavaScript
264 lines
No EOL
7.9 KiB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.amator = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||
var BezierEasing = require('bezier-easing')
|
||
|
||
// Predefined set of animations. Similar to CSS easing functions
|
||
var animations = {
|
||
ease: BezierEasing(0.25, 0.1, 0.25, 1),
|
||
easeIn: BezierEasing(0.42, 0, 1, 1),
|
||
easeOut: BezierEasing(0, 0, 0.58, 1),
|
||
easeInOut: BezierEasing(0.42, 0, 0.58, 1),
|
||
linear: BezierEasing(0, 0, 1, 1)
|
||
}
|
||
|
||
|
||
module.exports = animate;
|
||
module.exports.makeAggregateRaf = makeAggregateRaf;
|
||
module.exports.sharedScheduler = makeAggregateRaf();
|
||
|
||
|
||
function animate(source, target, options) {
|
||
var start = Object.create(null)
|
||
var diff = Object.create(null)
|
||
options = options || {}
|
||
// We let clients specify their own easing function
|
||
var easing = (typeof options.easing === 'function') ? options.easing : animations[options.easing]
|
||
|
||
// if nothing is specified, default to ease (similar to CSS animations)
|
||
if (!easing) {
|
||
if (options.easing) {
|
||
console.warn('Unknown easing function in amator: ' + options.easing);
|
||
}
|
||
easing = animations.ease
|
||
}
|
||
|
||
var step = typeof options.step === 'function' ? options.step : noop
|
||
var done = typeof options.done === 'function' ? options.done : noop
|
||
|
||
var scheduler = getScheduler(options.scheduler)
|
||
|
||
var keys = Object.keys(target)
|
||
keys.forEach(function(key) {
|
||
start[key] = source[key]
|
||
diff[key] = target[key] - source[key]
|
||
})
|
||
|
||
var durationInMs = typeof options.duration === 'number' ? options.duration : 400
|
||
var durationInFrames = Math.max(1, durationInMs * 0.06) // 0.06 because 60 frames pers 1,000 ms
|
||
var previousAnimationId
|
||
var frame = 0
|
||
|
||
previousAnimationId = scheduler.next(loop)
|
||
|
||
return {
|
||
cancel: cancel
|
||
}
|
||
|
||
function cancel() {
|
||
scheduler.cancel(previousAnimationId)
|
||
previousAnimationId = 0
|
||
}
|
||
|
||
function loop() {
|
||
var t = easing(frame/durationInFrames)
|
||
frame += 1
|
||
setValues(t)
|
||
if (frame <= durationInFrames) {
|
||
previousAnimationId = scheduler.next(loop)
|
||
step(source)
|
||
} else {
|
||
previousAnimationId = 0
|
||
setTimeout(function() { done(source) }, 0)
|
||
}
|
||
}
|
||
|
||
function setValues(t) {
|
||
keys.forEach(function(key) {
|
||
source[key] = diff[key] * t + start[key]
|
||
})
|
||
}
|
||
}
|
||
|
||
function noop() { }
|
||
|
||
function getScheduler(scheduler) {
|
||
if (!scheduler) {
|
||
var canRaf = typeof window !== 'undefined' && window.requestAnimationFrame
|
||
return canRaf ? rafScheduler() : timeoutScheduler()
|
||
}
|
||
if (typeof scheduler.next !== 'function') throw new Error('Scheduler is supposed to have next(cb) function')
|
||
if (typeof scheduler.cancel !== 'function') throw new Error('Scheduler is supposed to have cancel(handle) function')
|
||
|
||
return scheduler
|
||
}
|
||
|
||
function rafScheduler() {
|
||
return {
|
||
next: window.requestAnimationFrame.bind(window),
|
||
cancel: window.cancelAnimationFrame.bind(window)
|
||
}
|
||
}
|
||
|
||
function timeoutScheduler() {
|
||
return {
|
||
next: function(cb) {
|
||
return setTimeout(cb, 1000/60)
|
||
},
|
||
cancel: function (id) {
|
||
return clearTimeout(id)
|
||
}
|
||
}
|
||
}
|
||
|
||
function makeAggregateRaf() {
|
||
var frontBuffer = new Set();
|
||
var backBuffer = new Set();
|
||
var frameToken = 0;
|
||
|
||
return {
|
||
next: next,
|
||
cancel: next,
|
||
clearAll: clearAll
|
||
}
|
||
|
||
function clearAll() {
|
||
frontBuffer.clear();
|
||
backBuffer.clear();
|
||
cancelAnimationFrame(frameToken);
|
||
frameToken = 0;
|
||
}
|
||
|
||
function next(callback) {
|
||
backBuffer.add(callback);
|
||
renderNextFrame();
|
||
}
|
||
|
||
function renderNextFrame() {
|
||
if (!frameToken) frameToken = requestAnimationFrame(renderFrame);
|
||
}
|
||
|
||
function renderFrame() {
|
||
frameToken = 0;
|
||
|
||
var t = backBuffer;
|
||
backBuffer = frontBuffer;
|
||
frontBuffer = t;
|
||
|
||
frontBuffer.forEach(function(callback) {
|
||
callback();
|
||
});
|
||
frontBuffer.clear();
|
||
}
|
||
|
||
function cancel(callback) {
|
||
backBuffer.delete(callback);
|
||
}
|
||
}
|
||
|
||
},{"bezier-easing":2}],2:[function(require,module,exports){
|
||
/**
|
||
* https://github.com/gre/bezier-easing
|
||
* BezierEasing - use bezier curve for transition easing function
|
||
* by Gaëtan Renaudeau 2014 - 2015 – MIT License
|
||
*/
|
||
|
||
// These values are established by empiricism with tests (tradeoff: performance VS precision)
|
||
var NEWTON_ITERATIONS = 4;
|
||
var NEWTON_MIN_SLOPE = 0.001;
|
||
var SUBDIVISION_PRECISION = 0.0000001;
|
||
var SUBDIVISION_MAX_ITERATIONS = 10;
|
||
|
||
var kSplineTableSize = 11;
|
||
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
|
||
|
||
var float32ArraySupported = typeof Float32Array === 'function';
|
||
|
||
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
|
||
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
|
||
function C (aA1) { return 3.0 * aA1; }
|
||
|
||
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
||
function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
|
||
|
||
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
|
||
function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
|
||
|
||
function binarySubdivide (aX, aA, aB, mX1, mX2) {
|
||
var currentX, currentT, i = 0;
|
||
do {
|
||
currentT = aA + (aB - aA) / 2.0;
|
||
currentX = calcBezier(currentT, mX1, mX2) - aX;
|
||
if (currentX > 0.0) {
|
||
aB = currentT;
|
||
} else {
|
||
aA = currentT;
|
||
}
|
||
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
|
||
return currentT;
|
||
}
|
||
|
||
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
|
||
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
|
||
var currentSlope = getSlope(aGuessT, mX1, mX2);
|
||
if (currentSlope === 0.0) {
|
||
return aGuessT;
|
||
}
|
||
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
|
||
aGuessT -= currentX / currentSlope;
|
||
}
|
||
return aGuessT;
|
||
}
|
||
|
||
module.exports = function bezier (mX1, mY1, mX2, mY2) {
|
||
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
|
||
throw new Error('bezier x values must be in [0, 1] range');
|
||
}
|
||
|
||
// Precompute samples table
|
||
var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
|
||
if (mX1 !== mY1 || mX2 !== mY2) {
|
||
for (var i = 0; i < kSplineTableSize; ++i) {
|
||
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
|
||
}
|
||
}
|
||
|
||
function getTForX (aX) {
|
||
var intervalStart = 0.0;
|
||
var currentSample = 1;
|
||
var lastSample = kSplineTableSize - 1;
|
||
|
||
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
|
||
intervalStart += kSampleStepSize;
|
||
}
|
||
--currentSample;
|
||
|
||
// Interpolate to provide an initial guess for t
|
||
var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
|
||
var guessForT = intervalStart + dist * kSampleStepSize;
|
||
|
||
var initialSlope = getSlope(guessForT, mX1, mX2);
|
||
if (initialSlope >= NEWTON_MIN_SLOPE) {
|
||
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
|
||
} else if (initialSlope === 0.0) {
|
||
return guessForT;
|
||
} else {
|
||
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
|
||
}
|
||
}
|
||
|
||
return function BezierEasing (x) {
|
||
if (mX1 === mY1 && mX2 === mY2) {
|
||
return x; // linear
|
||
}
|
||
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
|
||
if (x === 0) {
|
||
return 0;
|
||
}
|
||
if (x === 1) {
|
||
return 1;
|
||
}
|
||
return calcBezier(getTForX(x), mY1, mY2);
|
||
};
|
||
};
|
||
|
||
},{}]},{},[1])(1)
|
||
}); |