Code Monkey home page Code Monkey logo

Comments (2)

xjArea avatar xjArea commented on September 19, 2024

I tried writing a test and found that bezier-easing is indeed "faster", using bezier.css.methond() is faster, but using bezier(a,b,c,d) directly is slower than jQuery.easing.method(), is this a browser caching factor ?

I'm not sure if my test like this is actually possible, am I missing some parameters? I hope someone can help me to answer, the following is the specific code and test results.

Test Code
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/jquery.easing.min.js"></script>
<script>
$(function(){
	
	var start;
	
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ jQuery.easing.linear(i) };
	console.log('jQuery.easing.linear ' + (Date.now() - start));
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ jQuery.easing.swing(i) };
	console.log('jQuery.easing.swing ' + (Date.now() - start));
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ jQuery.easing.easeOutCirc(i) };
	console.log('jQuery.easing.easeOutCirc ' + (Date.now() - start));
	
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ bezier.css.linear() };
	console.log('bezier-easing linear ' + (Date.now() - start));
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ bezier( 0.00,  0.00,  1.00,  1.00) };
	console.log('bezier-easing linear ' + (Date.now() - start));
	
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ bezier.css.swing() };
	console.log('bezier-easing swing ' + (Date.now() - start));
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ bezier( 0.02,  0.01,  0.47,  1.00) };
	console.log('bezier-easing swing ' + (Date.now() - start));
	
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ bezier.css.easeOutCirc() };
	console.log('bezier-easing easeOutCirc ' + (Date.now() - start));
	
	start = Date.now();
	for(var i=0,l=1000000; i<l; i++){ bezier( 0.00,  0.55,  0.45,  1.00) };
	console.log('bezier-easing easeOutCirc ' + (Date.now() - start));
	
	
	// Here are the test results
	// jQuery.easing.linear 19
	// jQuery.easing.swing 55
	// jQuery.easing.easeOutCirc 25
	// bezier-easing linear 4
	// bezier-easing linear 5
	// bezier-easing swing 18
	// bezier-easing swing 99
	// bezier-easing easeOutCirc 12
	// bezier-easing easeOutCirc 90
	
});



/**
 * https://github.com/gre/bezier-easing
 * BezierEasing - use bezier curve for transition easing function
 * by Gaëtan Renaudeau 2014 - 2015 – MIT License
 */
var bezier = null;
(function(){

// 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;
}

function LinearEasing (x) {
	return x;
}

bezier = function(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');
	}
	
	if (mX1 === mY1 && mX2 === mY2) {
		return LinearEasing;
	}
	
	// Precompute samples table
	var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
	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) {
		// Because JavaScript number are imprecise, we should guarantee the extremes are right.
		if (x === 0 || x === 1) {
			return x;
		}
		return calcBezier(getTForX(x), mY1, mY2);
	};
};
	
// CSS mapping
bezier.css = {
	"ease":					bezier( 0.25,  0.10,  0.25,  1.00),
	"swing":				bezier( 0.02,  0.01,  0.47,  1.00),
	"linear":				bezier( 0.00,  0.00,  1.00,  1.00),
	"ease-in":				bezier( 0.42,  0.00,  1.00,  1.00),
	"ease-out":				bezier( 0.00,  0.00,  0.58,  1.00),
	"ease-in-out":			bezier( 0.42,  0.00,  0.58,  1.00),
	"easeInSine":			bezier( 0.12,  0.00,  0.39,  0.00),
	"easeOutSine":			bezier( 0.61,  1.00,  0.88,  1.00),
	"easeInOutSine":		bezier( 0.37,  0.00,  0.63,  1.00),
	"easeInQuad":			bezier( 0.11,  0.00,  0.50,  0.00),
	"easeOutQuad":			bezier( 0.50,  1.00,  0.89,  1.00),
	"easeInOutQuad":		bezier( 0.45,  0.00,  0.55,  1.00),
	"easeInCubic":			bezier( 0.32,  0.00,  0.67,  0.00),
	"easeOutCubic":			bezier( 0.33,  1.00,  0.68,  1.00),
	"easeInOutCubic":		bezier( 0.65,  0.00,  0.35,  1.00),
	"easeInQuart":			bezier( 0.50,  0.00,  0.75,  0.00),
	"easeOutQuart":			bezier( 0.25,  1.00,  0.50,  1.00),
	"easeInOutQuart":		bezier( 0.76,  0.00,  0.24,  1.00),
	"easeInQuint":			bezier( 0.64,  0.00,  0.78,  0.00),
	"easeOutQuint":			bezier( 0.22,  1.00,  0.36,  1.00),
	"easeInOutQuint":		bezier( 0.83,  0.00,  0.17,  1.00),
	"easeInExpo":			bezier( 0.70,  0.00,  0.84,  0.00),
	"easeOutExpo":			bezier( 0.16,  1.00,  0.30,  1.00),
	"easeInOutExpo":		bezier( 0.87,  0.00,  0.13,  1.00),
	"easeInCirc":			bezier( 0.55,  0.00,  1.00,  0.45),
	"easeOutCirc":			bezier( 0.00,  0.55,  0.45,  1.00),
	"easeInOutCirc":		bezier( 0.85,  0.00,  0.15,  1.00),
	"easeInBack":			bezier( 0.36,  0.00,  0.66, -0.56),
	"easeOutBack":			bezier( 0.34,  1.56,  0.64,  1.00),
	"easeInOutBack":		bezier( 0.68, -0.60,  0.32,  1.60),
	// "easeInElastic":		it can't use bezier() to come true,
	// "easeOutElastic":	it can't use bezier() to come true,
	// "easeInOutElastic":	it can't use bezier() to come true,
	// "easeInBounce":		it can't use bezier() to come true,
	// "easeOutBounce":		it can't use bezier() to come true,
	// "easeInOutBounce":	it can't use bezier() to come true,
};

})();
</script>

from bezier-easing.

gre avatar gre commented on September 19, 2024

easing functions that are directly written in a simple math formula without using bezier lookup are always going to be faster.

see article https://greweb.me/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation

bezier implementation is a generalization of all these curves tho, so there is the freedom to express many kind of easing functions, feature that come with the price of being a bit less performant, but it's still very performant and depending on your usecase may not really matter.

hope this answers it.

from bezier-easing.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.