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;
} /* 元素 */
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();
};
/* 元素 */
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();
});
});
}

  

学习版本

<!DOCTYPE html>
<html lang="en" > <head> <meta charset="UTF-8">
<link rel="shortcut icon" type="image/x-icon" href="https://static.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" />
<link rel="mask-icon" type="" href="https://static.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" />
<title>CodePen - gwcpwx</title> <style>
#goods {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
border: 1px solid deeppink;
text-align: center;
color: deeppink;
}
#goods:hover {
color: #fff;
background-color: deeppink;
}
#cart {
position: fixed;
right: 0;
bottom: 100px;
color: deeppink;
border: 1px solid deeppink;
}
</style> <script> </script> </head> <body translate="no" >
y = ax² + bx + c
<div id="goods">
商品
</div> <br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<div id="cart">
购物车
</div> <script >
var goodsDom = document.querySelector("#goods");
var cartDom = document.querySelector("#cart");
goodsDom.onclick = function () {
var goodsXLeft = goodsDom.offsetLeft;
var goodsYTop = goodsDom.offsetTop;
var startX = goodsXLeft + 100;
var startY = goodsYTop - document.body.scrollTop + 12;
var endX = cartDom.offsetLeft;
var endY = cartDom.offsetTop;
var diffX = endX - startX;
var diffY = endY - startY;
// 假设中点(0, 0),也就是方程中的c为0
var c = 0;
var a = (endY/endX-startY/startX)/(endX - startX);
var b = endY/endX - a*endX;
// 创建一个移动的dom
var movingDom = document.createElement("div");
movingDom.style.position = 'fixed';
movingDom.style.left = startX + 'px';
movingDom.style.top = startY + 'px';
movingDom.style.height = '16px';
movingDom.style.width = '16px';
movingDom.style.borderRadius = '8px';
movingDom.style.background = 'red';
document.body.appendChild(movingDom)
// 定义移动的dom的x, y
var x = startX;
var y = startY;
var ax2 = 0;
var bx = 0;
var time = setInterval(function(){
if(x < endX) {
x = x + 2;
ax2 = a*x*x;
bx = b*x;
y = ax2 + bx;
console.log(ax2, bx, y)
movingDom.style.left = x + 'px';
movingDom.style.top = y + 'px';
} else {
movingDom.parentNode.removeChild(movingDom)
clearInterval(time);
}
},10)
}
//# sourceURL=pen.js
</script> </body> </html>

vue实现抛物线

<template>

      <div>
<ul class="lists">
<li>商品1商品1<i @click="ball_fly($event)">+</i></li>
<li>商品12商品1<i @click="ball_fly($event)">+</i></li>
<li>商品13商品1<i @click="ball_fly($event)">+</i></li> <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
<li>商品12商品1<i @click="ball_fly($event)">+</i></li>
<li>商品13商品1<i @click="ball_fly($event)">+</i></li> <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
<li>商品12商品1<i @click="ball_fly($event)">+</i></li>
<li>商品13商品1<i @click="ball_fly($event)">+</i></li> <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
<li>商品12商品1<i @click="ball_fly($event)">+</i></li>
<li>商品13商品1<i @click="ball_fly($event)">+</i></li>
</ul> <div class="targetbox"><div class="target car_icon" ref="carIcon">购物车</div> </div> </div> </template>
<script> export default {
name: 'business',
data () {
return {
showMe: false,
// 计算商品区域高度
computedContentHeight: window.innerHeight - (window.innerWidth / 10 * 4.2), };
}, methods: {
// 初始化
init () { // 给购物车添加animationend事件,动画结束后去掉有animation的class
this.$refs.carIcon.addEventListener('animationend', () => {
this.$refs.carIcon.classList.remove('tantantan');
}, false);
}, // 修改版抛球效果,使用css3中的贝塞尔曲线实现
ball_fly (e) {
// 被点元素位置
var bound = e.target.getBoundingClientRect();
var boundTop = bound.top;// 点击top值
var boundLeft = bound.left;// 点击left值
// 目标元素位置
var target = this.$refs.carIcon;
var targetData = target.getBoundingClientRect();
var targetTop = targetData.top;// 目标top值
var targetLeft = targetData.left;// 目标left值
// 创建父球(父球横向运动)
var father = document.createElement('div');
father.className = 'father flyball';
// 创建子球(子球垂直css3贝塞尔曲线运动,先上后下,得到抛球效果)
var child = document.createElement('div');
child.className = 'child inner';
father.appendChild(child);
// 设置父盒子生成的位置
// father.style.cssText = 'top:' + boundTop + 'px;left:' + boundLeft + 'px;';
father.style.top = boundTop + 'px';
father.style.left = boundLeft + 'px';
// append小球到页面中
document.body.appendChild(father);
setTimeout(() => {
// 目标left - 所点元素left + 目标元素宽度的一半(修正落点)
father.style.transform = 'translate3d(' + (targetLeft - boundLeft + targetData.width / 2) + 'px, 0px, 0px)';
child.style.cssText = 'transform: translate3d(0px, ' + (targetTop - boundTop) + 'px, 0px);';
// 运动结束后删掉小球
setTimeout(() => {
// 移除小球
father.parentNode.removeChild(father);
// 购物车添加弹弹弹的css
this.$refs.carIcon.classList.add('tantantan');
// 给购物车添加animationend事件,动画结束后去掉有animation的class
this.$refs.carIcon.addEventListener('animationend', () => {
this.$refs.carIcon.classList.remove('tantantan');
}, false); }, 500);
}, 10);
}
// 生成小球抛出 计算left top 生成动画 不流畅 (css3的没想好)
/* ball_fly (e) {
// 被点元素宽高
var bound = e.target.getBoundingClientRect(); // 被点元素位置
// 创造元素
var qiu = document.createElement('div');
qiu.className = 'qiu';
qiu.style.top = bound.top + 'px';
qiu.style.left = bound.left + 'px';
document.body.appendChild(qiu);
// 目标元素位置
var dsa = this.$refs.carIcon;
var mubiao = dsa.getBoundingClientRect();
var mubiaoT = mubiao.top;
var mubiaoL = mubiao.left;
var timer = null;
// top差值 left差值
var chaTop = mubiaoT - bound.top;
// 要减掉目标宽度一半 让落点对准目标中心
var chaLeft = bound.left - mubiaoL - dsa.offsetWidth / 2;
// 规定上抛初速度为 top 差值的55分之1
var g = chaTop / 55;
// 规定上抛初速度为 top 差值的15分之1
var vTop = chaTop / 15;
timer = setInterval(() => {
qiu.style.top = (qiu.getBoundingClientRect().top + (-vTop + g)) + 'px';
qiu.style.left = (qiu.getBoundingClientRect().left + (-chaLeft / 14)) + 'px';
// 每次 g 对速度的影响
vTop -= g;
if (qiu.getBoundingClientRect().top >= mubiaoT) {
clearInterval(timer);
qiu.parentNode.removeChild(qiu);
this.$refs.carIcon.classList.add('tantantan');
}
}, 1000 / 25);
} */
}
};
</script> <style lang="less">
.business_box{
width:100%;
height:100%; }
@keyframes mymove {
0% {
transform: scale(1);
}
25% {
transform: scale(0.8);
}
50% {
transform: scale(1.1);
}
75% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
/* 购物车弹弹弹 */
.tantantan {
animation: mymove 1s;
}
/* 修正版抛球效果所需CSS */
.flyball {
position:fixed;
top:0;
left:0;
-webkit-transition:-webkit-transform .5s linear;
transition:-webkit-transform .5s linear;
transition:transform .5s linear;
transition:transform .5s linear, -webkit-transform .5s linear
}
.flyball .inner {
position:absolute;
top:0;
left:0;
background-color:#3190e8;
border-radius:50%
}
.flyball, .flyball .inner {
will-change:transform;/* css3自带的开启GPU加速 */
-webkit-transform:translateZ(0);
transform:translateZ(0)
}
.flyball .inner {
-webkit-transition:-webkit-transform .5s cubic-bezier(.3, -.2, 1, 0);
transition:-webkit-transform .5s cubic-bezier(.3, -.2, 1, 0);
transition:transform .5s cubic-bezier(.3, -.2, 1, 0);
transition:transform .5s cubic-bezier(.3, -.2, 1, 0), -webkit-transform .5s cubic-bezier(.3, -.2, 1, 0)
} /* 父盒子的样式 */
.father{
width: 20px;;
height:20px;
position: fixed;
z-index: 999;
}
/* 子盒子(小球)的样式 */
.child{
width: 20px;;
height:20px;
background: #3190e8;
position: absolute;
top: 0;
left: 0;
} .lists{ width: 100%; height: auto;; overflow: hidden;} .lists li{ height: 44px; line-height: 40px; background: #f1f1f1; margin-bottom: 20px; position: relative; padding: 0 10px;}
.lists li i{ width: 20px; height: 20px; text-align: center;; line-height: 19px;; display: block; border-radius: 15px; overflow: hidden; position: absolute; right: 20px; top:10px;; background: #3190e8; color: #fff; ;}
.targetbox{ position: fixed; bottom: 54px; left: 0; width: 100%; height: 54px; background: #666;}
.target{ width: 50px; height: 50px; color: #fff; line-height: 50px; text-align: center;}
.car_icon { background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zd…48Y2lyY2xlIGN4PSIxMiIgY3k9IjUxIiByPSI0IiBmaWxsPSIjRkZGIi8+PC9nPjwvc3ZnPg==) #3190e8 center no-repeat; border-radius: 50%;
background-size: 60% auto;
}
</style>

css 实现抛物线

<!DOCTYPE html>
<html lang="en" style="width:100%;height:100%;">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<style>
* {
padding: 0;
margin: 0;
}
#ball {
width:12px;
height:12px;
background: #5EA345;
border-radius: 50%;
position: fixed;
transition: left 1s linear, top 1s ease-in;
}
</style>
<title>CSS3 水平抛物线动画</title>
</head>
<body style="width:100%;height:100%;">
<div id="ball"></div>
</body>
<script>
var $ball = document.getElementById('ball');
document.body.onclick = function (evt) {
console.log(evt.pageX,evt.pageY)
$ball.style.top = evt.pageY+'px';
$ball.style.left = evt.pageX+'px';
$ball.style.transition = 'left 0s, top 0s';
setTimeout(()=>{
$ball.style.top = window.innerHeight+'px';
$ball.style.left = '0px';
$ball.style.transition = 'left 1s linear, top 1s ease-in';
}, 20)
}
</script>
</html>

  

小程序

cartAnimation(x, y) { // x y 为手指点击的坐标,即球的起始坐标
let self = this,
cartY = app.globalData.winHeight - 50, // 结束位置(购物车图片)纵坐标
cartX = 50, // 结束位置(购物车图片)的横坐标
animationX = flyX(cartX, x), // 创建球的横向动画
animationY = flyY(cartY, y) // 创建球的纵向动画
this.setData({
ballX: x,
ballY: y,
showBall: true
})
setTimeoutES6(100).then(() => { // 100 ms 延时,确保球已经到位并显示
self.setData({
animationX: animationX.export(),
animationY: animationY.export(),
})
return setTimeoutES6(400) // 400 ms 是球的抛物线动画时长
}).then(() => { // 400 ms 延时后隐藏球
this.setData({
showBall: false,
})
})
} function setTimeoutES6(sec) { // Promise 化 setTimeout
return new Promise((resolve, reject) => {
setTimeout(() => {resolve()}, sec)
})
} function flyX(cartX, oriX) { // 水平动画
let animation = wx.createAnimation({
duration: 400,
timingFunction: 'linear',
})
animation.left(cartX).step()
return animation
} function flyY(cartY, oriY) { // 垂直动画
let animation = wx.createAnimation({
duration: 400,
timingFunction: 'ease-in',
})
animation.top(cartY).step()
return animation
}

  

222

    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;
} /* 元素 */
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();
};

333

<!doctype html >
<html>
<head>
<meta charset="utf-8"/>
<title>抛物线运动</title>
<style>
.pwx_rect{position:absolute;left:10px;top:300px;background-color:#888;height:50px;width:50px;}
.pwx_hr{border-top:2px solid #ddd;position:absolute;width:98%;left:0px;top:350px;}
</style>
<script>
test = function(){
var rect = document.getElementById("rect");
pwx(rect,60,5); //参数2:抛物线角度,参数3:横向速度每次增加5
}
function pwx(rect,radian,step){
var animate = function(opt){
var cos = Math.cos(opt.radian*Math.PI/180);//邻边比斜边,60度的话等于1/2
var sin = Math.sin(opt.radian*Math.PI/180);//对边比斜边,30度的话等于1/2
var left = opt.rect.offsetLeft;
var top = opt.rect.offsetTop;
if(opt.radian>0){
left+=opt.step;
opt.radian-=1; //角度递减1
var a = left - opt.initLeft;
var c = (a/cos);
var b = (sin*c);
opt.rect.style.left = opt.initLeft+a+"px";
opt.rect.style.top = opt.initTop-b+"px";
setTimeout(function(){
animate(opt);
},10);
}else{
opt.rect.style.left = left+opt.step+"px";
opt.rect.style.top = opt.initTop+"px";
}
}
animate({
step : step,
rect : rect,
radian : radian,
initTop : rect.offsetTop,
initLeft : rect.offsetLeft
});
}
</script>
</head>
<body> <input type="button" value="抛物线" onclick="test()"/>
<div class="pwx_rect" id="rect"></div>
<div class="pwx_hr"></div>
</body>
</html>

  

/*!
* parabola trajectory v1.0
*
* Contact: https://github.com/xiaolin3303
* 2016-09-30
*
* Designed and built with all the love of Web
*/
;(function (window, Math) {
/*
* @params Object opts
*/
function Parabola (opts) {
opts = opts || {};
// required `startPos`, `endPos` params in opts
if (!opts.startPos) {
throw new Error('`startPos` is required in init options');
} if (!opts.endPos) {
throw new Error('`endPos` is required in init options');
}
// opts.curvature = opts.curvature || 0.003;
opts.duration = opts.duration || 2000; this.opts = opts; this.calCurvature();
} Parabola.prototype.calCurvature = function () { this.opts.driftX = this.opts.endPos.left - this.opts.startPos.left;
this.opts.driftY = this.opts.endPos.top - this.opts.startPos.top; // 在不超出屏幕范围的前提下,尽量抛得更高,计算合适的曲率 (a)
var yMin = -1 * this.opts.startPos.top; var a = this.power(this.opts.driftX, 4);
var b = (4 * yMin - 2 * this.opts.driftY) * this.power(this.opts.driftX, 2);
var c = this.power(this.opts.driftY, 2); this.opts.curvature = (-1 * b + Math.sqrt((this.power(b, 2) - 4 * a * c))) / (2 * a); this.opts.b = (this.opts.driftY - this.opts.curvature * this.opts.driftX * this.opts.driftX) / this.opts.driftX;
} Parabola.prototype.power = function (v, n) {
if (n === 1) {
return v;
} else {
return v * arguments.callee(v, (n - 1));
}
} Parabola.prototype.calPosition = function (progress) {
// 当前进度下的X轴的位置
x = this.opts.driftX * progress;
// 当前进度下的Y轴的位置
// y = a*x*x + b*x + c, c = 0
y = this.opts.curvature * x * x + this.opts.b * x; return {
left: Math.round(x + this.opts.startPos.left),
top: Math.round(y + this.opts.startPos.top)
}
} Parabola.prototype.start = function () {
var opts = this.opts;
var me = this;
var startTimeStamp = +new Date();
var animationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) { window.setTimeout(callback, 1000 / 60); }; function step () {
var currentTimeStamp = +new Date(); var progress = Math.min((currentTimeStamp - startTimeStamp) / opts.duration, 1);
if (progress === 1) {
// 动画结束
return false;
} else {
var position = me.calPosition(progress);
opts.onStep && opts.onStep(position); return true;
}
} function progress () {
if (step()) {
animationFrame(progress);
} else {
if (typeof opts.onFinish === 'function') {
opts.onFinish(opts.endPos);
}
}
} animationFrame(progress);
} if ( typeof module !== 'undefined' && module.exports ) {
module.exports = Parabola;
} else if ( typeof define === 'function' && define.amd ) {
define( function () { return Parabola; } );
} else {
window.Parabola = Parabola;
} })(window, Math) window.onload = function () {
var btn = document.querySelector('button');
var target = document.querySelector('.dot');
var parabola = new Parabola({
startPos: {
left: 100,
top: 60
},
endPos: {
left: 500,
top: 200
},
duration: 1000,
onStep (pos) {
target.style.left = pos.left + 'px';
target.style.top = pos.top + 'px';
},
onFinish (pos) {
target.classList.add('scaleAnimation');
console.log('Animation Finished!');
}
}); // parabola.start();
btn.addEventListener('click', function () {
target.classList.remove('scaleAnimation');
parabola.start();
}, false);
}

fly.js

/*
* jquery.fly
*
* 抛物线动画
* @github https://github.com/amibug/fly
* Copyright (c) 2014 wuyuedong
* copy from tmall.com
*/
(function ($) {
$.fly = function (element, options) {
// 默认值
var defaults = {
version: '1.0.0',
autoPlay: true,
vertex_Rtop: 20, // 默认顶点高度top值
speed: 1.2,
start: {}, // top, left, width, height
end: {},
onEnd: $.noop
}; var self = this,
$element = $(element); /**
* 初始化组件,new的时候即调用
*/
self.init = function (options) {
this.setOptions(options);
!!this.settings.autoPlay && this.play();
}; /**
* 设置组件参数
*/
self.setOptions = function (options) {
this.settings = $.extend(true, {}, defaults, options);
var settings = this.settings,
start = settings.start,
end = settings.end; $element.css({marginTop: '0px', marginLeft: '0px', position: 'fixed'}).appendTo('body');
// 运动过程中有改变大小
if (end.width != null && end.height != null) {
$.extend(true, start, {
width: $element.width(),
height: $element.height()
});
}
// 运动轨迹最高点top值
var vertex_top = Math.min(start.top, end.top) - Math.abs(start.left - end.left) / 3;
if (vertex_top < settings.vertex_Rtop) {
// 可能出现起点或者终点就是运动曲线顶点的情况
vertex_top = Math.min(settings.vertex_Rtop, Math.min(start.top, end.top));
} /**
* ======================================================
* 运动轨迹在页面中的top值可以抽象成函数 y = a * x*x + b;
* a = curvature
* b = vertex_top
* ======================================================
*/ var distance = Math.sqrt(Math.pow(start.top - end.top, 2) + Math.pow(start.left - end.left, 2)),
// 元素移动次数
steps = Math.ceil(Math.min(Math.max(Math.log(distance) / 0.05 - 75, 30), 100) / settings.speed),
ratio = start.top == vertex_top ? 0 : -Math.sqrt((end.top - vertex_top) / (start.top - vertex_top)),
vertex_left = (ratio * start.left - end.left) / (ratio - 1),
// 特殊情况,出现顶点left==终点left,将曲率设置为0,做直线运动。
curvature = end.left == vertex_left ? 0 : (end.top - vertex_top) / Math.pow(end.left - vertex_left, 2); $.extend(true, settings, {
count: -1, // 每次重置为-1
steps: steps,
vertex_left: vertex_left,
vertex_top: vertex_top,
curvature: curvature
});
}; /**
* 开始运动,可自己调用
*/
self.play = function () {
this.move();
}; /**
* 按step运动
*/
self.move = function () {
var settings = this.settings,
start = settings.start,
count = settings.count,
steps = settings.steps,
end = settings.end;
// 计算left top值
var left = start.left + (end.left - start.left) * count / steps,
top = settings.curvature == 0 ? start.top + (end.top - start.top) * count / steps : settings.curvature * Math.pow(left - settings.vertex_left, 2) + settings.vertex_top;
// 运动过程中有改变大小
if (end.width != null && end.height != null) {
var i = steps / 2,
width = end.width - (end.width - start.width) * Math.cos(count < i ? 0 : (count - i) / (steps - i) * Math.PI / 2),
height = end.height - (end.height - start.height) * Math.cos(count < i ? 0 : (count - i) / (steps - i) * Math.PI / 2);
$element.css({width: width + "px", height: height + "px", "font-size": Math.min(width, height) + "px"});
}
$element.css({
left: left + "px",
top: top + "px"
});
settings.count++;
// 定时任务
var time = window.requestAnimationFrame($.proxy(this.move, this));
if (count == steps) {
window.cancelAnimationFrame(time);
// fire callback
settings.onEnd.apply(this);
}
}; /**
* 销毁
*/
self.destroy = function(){
$element.remove();
}; self.init(options);
}; // add the plugin to the jQuery.fn object
$.fn.fly = function (options) {
return this.each(function () {
if (undefined == $(this).data('fly')) {
$(this).data('fly', new $.fly(this, options));
}
});
};
})(jQuery);
<script>
$(function() {
var offset = $("#end").offset();
$(".addcar").click(function(event){
var addcar = $(this);
var img = addcar.parent().find('img').attr('src');
var flyer = $('<img class="u-flyer" src="'+img+'">');
flyer.fly({
start: {
left: event.pageX,
top: event.pageY
},
end: {
left: offset.left+10,
top: offset.top+10,
width: 0,
height: 0
},
onEnd: function(){
$("#msg").show().animate({width: '250px'}, 200).fadeOut(1000);
addcar.css("cursor","default").removeClass('orange').unbind('click');
this.destory();
}
});
});
});
</script>

  

js 抛物线 笔记备份的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. Vue.js学习笔记(2)vue-router

    vue中vue-router的使用:

  3. js读书笔记

    js读书笔记 基本类型的基本函数总结 1. Boolean() 数据类型 转换为true的值 转换为false的值 Boolean true false String 任何非空字符串 "&q ...

  4. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  5. JS 学习笔记--9---变量-作用域-内存相关

    JS 中变量和其它语言中变量最大的区别就是,JS 是松散型语言,决定了它只是在某一个特定时间保存某一特定的值的一个名字而已.由于在定义变量的时候不需要显示规定必须保存某种类型的值,故变量的值以及保存的 ...

  6. node.js系列笔记之node.js初识《一》

    node.js系列笔记之node.js初识<一> 一:环境说明 1.1 Linux系统CentOS 5.8 1.2 nodejs v0.10.15 1.3 nodejs源码下载地址 htt ...

  7. JS面向对象笔记二

    菜单导航,<JS面向对象笔记一>,  参考书籍:阮一峰之<JavaScript标准参考教程> 一.构造函数和new命令 二.this关键字 三.构造函数和new命令 四.构造函 ...

  8. WebGL three.js学习笔记 使用粒子系统模拟时空隧道(虫洞)

    WebGL three.js学习笔记 使用粒子系统模拟时空隧道 本例的运行结果如图: 时空隧道demo演示 Demo地址:https://nsytsqdtn.github.io/demo/sprite ...

  9. WebGL three.js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法

    WebGL学习----Three.js学习笔记(5) 点击查看demo演示 Demo地址:https://nsytsqdtn.github.io/demo/360/360 简单网格材质 MeshNor ...

随机推荐

  1. Hyperledger Fabric 1.0 从零开始(十二)——fabric-sdk-java应用【补充】

    在 Hyperledger Fabric 1.0 从零开始(十二)--fabric-sdk-java应用 中我已经把官方sdk具体改良办法,即使用办法发出来了,所有的类及文件都是完整的,在文章的结尾也 ...

  2. vs2008中xlslib与libxls库的编译及使用

    C++用来操作Excel的方法很多,但是涉及到跨平台,同时又要对Excel的读写操作兼顾,而且免费的库,那应该是要用xlslib和libxls了.由于技术比较菜,折腾这个折腾了一个星期了.最开始是使用 ...

  3. TextView 的新特性,Autosizing 到底是如何实现的? | 源码分析

    一.前言 Hi,大家好,我是承香墨影! 前两天聊了一下 Autosizing 的使用,反映还不错.毕竟是这种能解决实际问题的新 Api,确实在需要的时候,用起来会很顺手. 简单回顾一下,Autosiz ...

  4. css写的常见图形

    .aly-tooltip { display: inline-block; padding: 5px; padding-left: 15px; padding-right: 15px; backgro ...

  5. Kubernetes 架构(下)- 每天5分钟玩转 Docker 容器技术(121)

    上一节我们讨论了 Kubernetes 架构 Master 上运行的服务,本节讨论 Node 节点. Node 是 Pod 运行的地方,Kubernetes 支持 Docker.rkt 等容器 Run ...

  6. RNN的简单的推导演算公式(BPTT)

    附上y=2x-b拟合的简单的代码. import numpy as np x = np.asarray([2,1,3,5,6]); y = np.zeros((1,5)); learning_rate ...

  7. Codeforces 915E Physical Education Lessons

    原题传送门 我承认,比赛的时候在C题上卡了好久(最后也不会),15min水掉D后(最后还FST了..),看到E时已经只剩15min了.尽管一眼看出是离散化+线段树的裸题,但是没有时间写,实在尴尬. 赛 ...

  8. 我们编写 React 组件的最佳实践

    刚接触 React 的时候,在一个又一个的教程上面看到很多种编写组件的方法,尽管那时候 React 框架已经相当成熟,但是并没有一个固定的规则去规范我们去写代码. 在过去的一年里,我们在不断的完善我们 ...

  9. bzoj:1457: 棋盘游戏

    原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1457 看了网上dalao的题解,好像解释得并不是很清楚,就按照那种思路,自己YY了一个想法 ...

  10. bzoj:1575: [Usaco2009 Jan]气象牛Baric

    Description 为了研究农场的气候,Betsy帮助农夫John做了N(1 <= N <= 100)次气压测量并按顺序记录了结果M_1...M_N(1 <= M_i <= ...