最近,在网上看到一篇博文,主要讲解网页中抛物线运动,应用数学公式y=a*x*x+b*x+c;通过3个点确定a,b,c三个参数的值。他的思路是物体经过原点[0,0],则可以得到c=0,手工设置a的值,则只需要根据一个起始点得到b的值。
[我的思路]:a,b,c三个参数都是计算出来的,而不是硬生生地赋值;
起始点由物体的在网页中的位置决定,所以在生成页面时已经确定[startLeft,startTop];
终止点由开发动画的人员决定,决定物体最后落在网页的什么位置[endLeft,endTop];
起始点和终止点确定以后,还差一点,在此的约定就是起始点和终止点之间的任意一点,
我的约定是:x轴方向起始点和终止点中间的位置,
y轴方向起始点和终止点距离网页顶部最小值-200,
在此得到约定的位置[x,y],以此为坐标原点,重新计算起始和终止点相对此点的相对坐标;
把相对坐标代入公式得到a,b,c=0
物体的运动则是以step的步长在x方向移动。每次把实际位置换算成相对坐标代入公式,得到x,y的相对坐标值,然后给运行物体赋值时再把相对坐标换算成实际坐标值,从而实现了抛物线动画。
[场景]:最初此动画被用在购物网站,在用户点击购买时,在购买按钮的位置会跳出一个小球划过一条美丽的抛物线落在购物车里,购物车的数量同时+1。
炮打犀牛应用:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>抛物线测试</title> <style type="text/css"> #div1{ width: 220px; height: 220px; background: url('pao.jpg'); background-size: cover; position: absolute; left: 0; bottom:0; cursor: pointer; z-index: 3; } #div2{ width: 220px; height: 220px; background: url('niu.jpg'); background-size: cover; position: absolute; right: 0; bottom: 0; z-index: 3; } #div3{ width: 50px; height: 50px; background-image: -webkit-radial-gradient(circle,#000,#fff,#000); border-radius: 30px; position: absolute; left: 174px; bottom: 140px; z-index: 2; } </style> </head> <body> <div id="div2"></div> <div id="div3"></div> <div id="div1"></div> <script src="../js/jquery-2.1.1.js" type="text/javascript" charset="utf-8"></script> <script src="jquery.paracurve.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> $('#div1').click(function(){ $('#div3').paracurve({ end:[$('#div2').position().left+50,$('#div2').position().top+50], step:10, movecb:function(){ $('#div3').clone().appendTo(document.body); }, moveendcb:function(){ //牛动作 $('#div2').animate({ width:'+=100', height:'+=100' }).animate({ width:'-=100', height:'-=100' }).animate({ opacity:0 },'fast').animate({ opacity:1 },'fast').animate({ opacity:0 },'fast').animate({ opacity:1 },'fast'); //子弹复位 $(this).css({ left:'174px', top:$('#div1').position().top+30+'px' }); } }); }); </script> </body> </html>
jquery.paracurve.js源码:
/* * @start[] 起始位置,索引0为left的值,索引1为top值 * @end[] 终止位置,索引0为left的值,索引1为top值 * @step 步长 每次x轴方向移动的距离 * @movecb 移动中的回调函数 * @moveendcb 移动结束的回调函数 */ (function($) { var old = $.fn.paracurve; $.fn.paracurve = function(option) { //默认的起点为物体的当前位置,终点为页面的右下角 var opt = { start: [this.position().left, this.position().top], end: [$(window).width()-this.width(), $(window).height()-this.height()], step:1, movecb:$.noop, moveendcb:$.noop }, that = this; $.extend(opt, option); //计算抛物线需要三点,起始和终止位置+未知 //未知位置:取起始和终止位置的x轴中间位置x=start.x+(end.x-start.x)/2 //y轴方向:取起始和终止点距离页面顶部最小的值-200,y=Math.max(start.y,end.y)-200,如果y<0,则=0 //未知位置的x,y确定后,则把该点视为原点,即网页的坐标原点由原来的左上角转移到该点,意念上转移 //重新计算起始点相对新原点的坐标,起始点:[x-start.x,y-start.y],终止点:[x-end.x,y-end.y],原点:[0,0] //根据抛物线公式y=a*x*x+b*x+c,把三点坐标代入公式,得到a,b,c=0的值 //三点实际坐标值 var x1 = opt.start[0], y1 = opt.start[1], x2 = opt.end[0], y2 = opt.end[1], x = x1 + (x2 - x1) / 2, y = Math.min(y1, y2) - 200; //防止移出页面,x,y作为原点 x = x > 0 ? Math.ceil(x) : Math.floor(x); y = y < 0 ? 0 : Math.ceil(y); //三点相对坐标值 var X1 = x - x1, Y1 = y - y1, X2 = x - x2, Y2 = y - y2, X = 0, Y = 0; //根据三点相对坐标计算公式中的a,b,c=0不用计算 var a = (Y2 - Y1 * X2 / X1) / (X2 * X2 - X1 * X2), b = (Y1 - a * X1 * X1) / X1; return that.each(function(index, ele) { //获得物体起始位置 var startPos = $(ele).data('startPos'); startPos=!!startPos?startPos:$(ele).position(); //检查当前物体是否正在运动中并且当前位置是否已在终点 if ($(ele).data('running') || startPos.left == x2) { end(); //复位 $(ele).css({ left: startPos.left + 'px', top: startPos.top + 'px' }); } else { //记忆物体起始位置 $(ele).data('startPos',$(ele).position()); var timer = setInterval(function() { var pos = $(ele).position(); //如果物体已到达终点 if (pos.left >= x2) { end(); } else { //left,top实际位置,Left,Top相对位置 var left = pos.left + opt.step, Left = x - left, Top = a * Left * Left + b * Left, top = y - Top; that.css({ left: left + 'px', top: top + 'px' }); $(ele).data('running', true); if(opt.movecb&&$.isFunction(opt.movecb)){ opt.movecb.call(ele); } } }, 30); $(ele).data('timer', timer); } //动画完成 function end(){ //标识是否正在运动中 $(ele).data('running', false).css({ left:x2+'px', top:y2+'px' }); clearInterval(timer); //执行完执行回调函数 if(opt.moveendcb&&$.isFunction(opt.moveendcb)){ opt.moveendcb.call(ele); } } }); }; $.fn.paracurve.noConflict = function() { $.fn.paracurve = old; return this; }; })(jQuery);到此,你完全可以把此插件应用到你所想到的任何场景,比如射击游戏,引导页面等,充分发挥,充分利用,有不足之处,请留言,方便改进优化。