/** * jQuery.crSpline v0.0.1 * http://github.com/MmmCurry/jquery.crSpline * * Supports animation along Catmull-Rom splines based on a series of waypoints. * Usage: See demo.js, demo.html * * Copyright 2010, M. Ian Graham * MIT License * */ (function($){ $.crSpline = {}; // Catmull-Rom interpolation between p0 and p1 for previous point p_1 and later point p2 // http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline var interpolate = function (t, p_1, p0, p1, p2) { return Math.floor((t * ((2 - t) * t - 1) * p_1 + (t * t * (3 * t - 5) + 2) * p0 + t * ((4 - 3 * t) * t + 1) * p1 + (t - 1) * t * t * p2 ) / 2); }; // Extend this p1,p2 sequence linearly to a new p3 var generateExtension = function (p1, p2) { return [ p2[0] + (p2[0] - p1[0]), p2[1] + (p2[1] - p1[1]) ]; }; // Return an animation object based on a sequence of points // pointList must be an array of [x,y] pairs $.crSpline.buildSequence = function(pointList) { var res = {}; var seq = []; var numSegments; if (pointList.length < 2) { throw "crSpline.buildSequence requires at least two points"; } // Generate the first p_1 so the caller doesn't need to provide it seq.push(generateExtension(pointList[1], pointList[0])); // Throw provided points on the list for (var i = 0; i < pointList.length; i++) { seq.push(pointList[i]); } // Generate the last p2 so the caller doesn't need to provide it seq.push(generateExtension(seq[seq.length-2], seq[seq.length-1])); numSegments = seq.length - 3; res.getPos = function (t) { // XXX For now, assume all segments take equal time var segNum = Math.floor(t * numSegments); if (segNum === numSegments) { return { left: seq[seq.length-2][0], top: seq[seq.length-2][1] }; } var microT = (t - segNum/numSegments) * numSegments; var result = { left: interpolate(microT, seq[segNum][0], seq[segNum+1][0], seq[segNum+2][0], seq[segNum+3][0]) + "px", top: interpolate(microT, seq[segNum][1], seq[segNum+1][1], seq[segNum+2][1], seq[segNum+3][1]) + "px" }; return result; }; return res; }; $.fx.step.crSpline = function (fx) { var css = fx.end.getPos(fx.pos); for (var i in css) { fx.elem.style[i] = css[i]; } }; })(jQuery);