<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>抛物线</title> <link href="css/parabola.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="js/parabola.js" ></script> </head> <body> <div class="container" id="container"></div> <div class="obj" id="obj"></div> <i class="x">x轴</i> <i class="y">y轴</i> </body> </html> <script> var container=document.getElementById("container"); var obj=document.getElementById("obj"); obj.onclick=function(){ funparabola(obj,container).positions().move(); } </script>
function funparabola(obj,container,options){ //关于传参覆盖问题 涉及3个对象 defaults、options、params //option是否传入判断、option与defaults求并集,option优先 //参数处理 var defaults={ speed:3.2,//速度 100px/s 按60帧每秒换算 每帧(100/60)px/s curvature:0.001,//斜率 progress:function(){}, complete:function(){}//回调函数 }; options=options||{}; var params={}; for(var key in defaults){ params[key]=options[key]||defaults[key]; }; //关于链式调用 var exports={ positions:function(){return this}, mark:function(){return this}, move:function(){return this}, init:function(){return this} }; //css3math var moveStyle="margin"; var testDiv=document.createElement("div"); var transform=[]; //IE9及以上区分 div元素识别oninput属性 if("oninput" in testDiv ){ //forEach函数,调用数组每个元素,并将元素传递给回调函数 ["","ms","moz","webkit"].forEach(function (prefix){ transform.push(prefix + (prefix ? "T" : "t") + "ransform"); }); //alert(transform); //for in语句遍历数组或者对象属性 for(var key in transform){ if(transform[key] in testDiv.style){ moveStyle=transform[key]; } } //alert(moveStyle); } //获取元素坐标 //定义变量 var a=params.curvature,b=0; var objRec,containerRec,objRel,containerCenter; var rate=1; exports.positions=function(){ //通过getBoundingClientRect()方法可以获得元素元素相对于窗口位置 top/right/bottom/left 在现在浏览器中还能获取到元素宽度 objRec=obj.getBoundingClientRect(); containerRec=container.getBoundingClientRect(); //滚动条滚动值 存在兼容性 //可使用jquery $(window).scrollTop()方法代替 var scrollLeft=document.documentElement.scrollLeft || document.body.scrollLeft; var scrollTop=document.documentElement.scrollTop || document.body.scrollTop; //元素中心坐标 var objCenter={ //获取元素宽高:clientWidth,clientHeight x: objRec.left+obj.clientWidth/2+scrollLeft, y: objRec.top+obj.clientHeight/2+scrollTop }; var containerCenter={ x:containerRec.left+container.clientWidth/2+scrollLeft, y:containerRec.top+container.clientHeight/2+scrollTop }; //转换坐标中心 以移动对象为中心 objRel={ x:0, y:0 }; containerRel={ x:containerCenter.x-objCenter.x, y:objCenter.y-containerCenter.y }; //计算曲线 y=a*x^2+b*x+c b=(containerRel.y-a*containerRel.x*containerRel.x)/containerRel.x; return this; } //移动元素 exports.move=function(){ //计算每次重绘元素x、y方向的偏移 //沿二次曲线运动速度是speed,那么(speed.x)²+(speed.y)²=(speed)² var startx=0; var tangent = 2 * a * startx + b; if(containerRel.x<0){ rate=-1; } var step=function(){ if(Math.abs(containerRel.x-startx)>2){ startx = startx + rate*Math.sqrt(params.speed*params.speed / (tangent * tangent + 1)); var x=startx,y=(a*x*x+b*x); var timepath=setTimeout(step,17); }else{ x=containerRel.x; y=containerRel.y; } // x, y目前是坐标,需要转换成定位的像素值 if (moveStyle == "margin") { obj.style.marginLeft = x + "px"; obj.style.marginTop = rate*y + "px"; } else { obj.style[moveStyle] = "translate("+ [x + "px", rate*y + "px"].join() +")"; } } step(); } //初始化方法 exports.init=function(){ this.positions(); } return exports; }
*{margin:0;padding:0;} html,body{height:100%;} body{position:relative;} .container{position:absolute;top:200px;left:500px;100px;height:50px;border:1px solid #ccc;border-radius:20px;background:#f3f3f3;} .obj{position:absolute;top:400px;left:800px;30px;height:30px;border-radius:50%;background:#ccc;} .x{position:absolute;top:415px;left:0;100%;height:1px;background:#ccc;} .y{position:absolute;top:0;left:815px;1px;height:100%;background:#ccc;}