parapola.js
/*! * by zhangxinxu(.com) 2012-12-27 * you can visit http://www.zhangxinxu.com/wordpress/?p=3855 to get more infomation * under mit license*/var funparabola = function(element, target, options) { /* * 网页模拟现实需要一个比例尺 * 如果按照1像素就是1米来算,显然不合适,因为页面动不动就几百像素 * 页面上,我们放两个物体,200~800像素之间,我们可以映射为现实世界的2米到8米,也就是100:1 * 不过,本方法没有对此有所体现,因此不必在意 */ var defaults = { speed: 166.67, // 每帧移动的像素大小,每帧(对于大部分显示屏)大约16~17毫秒 curvature: 0.001, // 实际指焦点到准线的距离,你可以抽象成曲率,这里模拟扔物体的抛物线,因此是开口向下的 progress: function() {}, complete: function() {} }; var params = {}; options = options || {}; for (var key in defaults) { params[key] = options[key] || defaults[key]; } var exports = { mark: function() { return this; }, position: function() { return this; }, move: function() { return this; }, init: function() { return this; } }; /* 确定移动的方式 * ie6-ie8 是margin位移 * ie9+使用transform */ var movestyle = margin, testdiv = document.createelement(div); if (oninput in testdiv) { [, ms, webkit].foreach(function(prefix) { var transform = prefix + (prefix? t: t) + ransform; if (transform in testdiv.style) { movestyle = transform; } }); } // 根据两点坐标以及曲率确定运动曲线函数(也就是确定a, b的值) /* 公式: y = a*x*x + b*x + c; */ var a = params.curvature, b = 0, c = 0; // 是否执行运动的标志量 var flagmove = true; if (element && target && element.nodetype == 1 && target.nodetype == 1) { var rectelement = {}, recttarget = {}; // 移动元素的中心点位置,目标元素的中心点位置 var centerelement = {}, centertarget = {}; // 目标元素的坐标位置 var coordelement = {}, coordtarget = {}; // 标注当前元素的坐标 exports.mark = function() { if (flagmove == false) return this; if (typeof coordelement.x == undefined) this.position(); element.setattribute(data-center, [coordelement.x, coordelement.y].join()); target.setattribute(data-center, [coordtarget.x, coordtarget.y].join()); return this; } exports.position = function() { if (flagmove == false) return this; var scrollleft = document.documentelement.scrollleft || document.body.scrollleft, scrolltop = document.documentelement.scrolltop || document.body.scrolltop; // 初始位置 if (movestyle == margin) { element.style.marginleft = element.style.margintop = 0px; } else { element.style[movestyle] = translate(0, 0); } // 四边缘的坐标 rectelement = element.getboundingclientrect(); recttarget = target.getboundingclientrect(); // 移动元素的中心点坐标 centerelement = { x: rectelement.left + (rectelement.right - rectelement.left) / 2 + scrollleft, y: rectelement.top + (rectelement.bottom - rectelement.top) / 2 + scrolltop }; // 目标元素的中心点位置 centertarget = { x: recttarget.left + (recttarget.right - recttarget.left) / 2 + scrollleft, y: recttarget.top + (recttarget.bottom - recttarget.top) / 2 + scrolltop }; // 转换成相对坐标位置 coordelement = { x: 0, y: 0 }; coordtarget = { x: -1 * (centerelement.x - centertarget.x), y: -1 * (centerelement.y - centertarget.y) }; /* * 因为经过(0, 0), 因此c = 0 * 于是: * y = a * x*x + b*x; * y1 = a * x1*x1 + b*x1; * y2 = a * x2*x2 + b*x2; * 利用第二个坐标: * b = (y2+ a*x2*x2) / x2 */ // 于是 b = (coordtarget.y - a * coordtarget.x * coordtarget.x) / coordtarget.x; return this; }; // 按照这个曲线运动 exports.move = function() { // 如果曲线运动还没有结束,不再执行新的运动 if (flagmove == false) return this; var startx = 0, rate = coordtarget.x > 0? 1: -1; var step = function() { // 切线 y'=2ax+b var tangent = 2 * a * startx + b; // = y / x // y*y + x*x = speed // (tangent * x)^2 + x*x = speed // x = math.sqr(speed / (tangent * tangent + 1)); startx = startx + rate * math.sqrt(params.speed / (tangent * tangent + 1)); // 防止过界 if ((rate == 1 && startx > coordtarget.x) || (rate == -1 && startx < coordtarget.x)) { startx = coordtarget.x; } var x = startx, y = a * x * x + b * x; // 标记当前位置,这里有测试使用的嫌疑,实际使用可以将这一行注释 element.setattribute(data-center, [math.round(x), math.round(y)].join()); // x, y目前是坐标,需要转换成定位的像素值 if (movestyle == margin) { element.style.marginleft = x + px; element.style.margintop = y + px; } else { element.style[movestyle] = translate(+ [x + px, y + px].join() +); } if (startx !== coordtarget.x) { params.progress(x, y); window.requestanimationframe(step); } else { // 运动结束,回调执行 params.complete(); flagmove = true; } }; window.requestanimationframe(step); flagmove = false; return this; }; // 初始化方法 exports.init = function() { this.position().mark().move(); }; } return exports;};/*! requestanimationframe.js * by zhangxinxu 2013-09-30*/(function() { var lasttime = 0; var vendors = ['webkit', 'moz']; for(var x = 0; x < vendors.length && !window.requestanimationframe; ++x) { window.requestanimationframe = window[vendors[x] + 'requestanimationframe']; window.cancelanimationframe = window[vendors[x] + 'cancelanimationframe'] || // name has changed in webkit window[vendors[x] + 'cancelrequestanimationframe']; } if (!window.requestanimationframe) { window.requestanimationframe = function(callback, element) { var currtime = new date().gettime(); var timetocall = math.max(0, 16.7 - (currtime - lasttime)); var id = window.settimeout(function() { callback(currtime + timetocall); }, timetocall); lasttime = currtime + timetocall; return id; }; } if (!window.cancelanimationframe) { window.cancelanimationframe = function(id) { cleartimeout(id); }; }}());
使用:
/* 元素 */var element = document.getelementbyid(element), target = document.getelementbyid(target);// 抛物线元素的的位置标记var parabola = funparabola(element, target).mark();// 抛物线运动的触发document.body.onclick = function() { element.style.marginleft = 0px; element.style.margintop = 0px; parabola.init();};
加入购物车实战:
/* 本demo演示脚本基于iebetter.js, 项目地址:https://github.com/zhangxinxu/iebetter.js */// 元素以及其他一些变量var eleflyelement = document.queryselector(#flyitem), eleshopcart = document.queryselector(#shopcart);var numberitem = 0;// 抛物线运动var myparabola = funparabola(eleflyelement, eleshopcart, { speed: 400, curvature: 0.002, complete: function() { eleflyelement.style.visibility = hidden; eleshopcart.queryselector(span).innerhtml = ++numberitem; }});// 绑定点击事件if (eleflyelement && eleshopcart) { [].slice.call(document.getelementsbyclassname(btncart)).foreach(function(button) { button.addeventlistener(click, function() { // 滚动大小 var scrollleft = document.documentelement.scrollleft || document.body.scrollleft || 0, scrolltop = document.documentelement.scrolltop || document.body.scrolltop || 0; eleflyelement.style.left = event.clientx + scrollleft + px; eleflyelement.style.top = event.clienty + scrolltop + px; eleflyelement.style.visibility = visible; // 需要重定位 myparabola.position().move(); }); });}
以上就是本文的全部内容,希望对大家的学习有所帮助。
