公司要做個活動蛙卤,然后要做撒金幣效果炒考,網(wǎng)上找了好多資料效果不是很好拂蝎,這個是網(wǎng)上找的一個比較滿意的效果把代碼分享出來穴墅,僅做個人代碼分享。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>搖一搖撒金幣</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui" />
<style>
body{margin:0;padding:0;}
input{position:absolute;z-index:1000}
canvas{position:absolute;top:0;left:0;}
</style>
<script>
function Coin(opts){
//默認參數(shù)
this.defaults={
coinSrc:"http://ohpg7uygp.bkt.clouddn.com/jinbi.png", //金幣圖片地址
audioSrc:"http://ohpg7uygp.bkt.clouddn.com/shake.mp3", //金幣音頻地址
coinWidth:20, //金幣寬度
coinHeight:20, //金幣高度
density:30
};
this.settings=this._extendDeep(this.defaults,opts); //深拷貝
this.density=this.settings.density; //密度温自,即金幣個數(shù)
this.timeLag=1000; //金幣散落的事件間隔玄货,數(shù)字越大表示間隔越大
this.coinWidth=this.settings.coinWidth; //金幣寬度
this.coinHeight=this.settings.coinHeight; //金幣高度
this.wrapWidth=0;
this.wrapHeight=0;
this._init();
}
Coin.prototype={
constructor:Coin,
/**
* 動畫初始化方法
* @method _init
**/
_init:function(){
//初始化包括尺寸大小
this.wrapWidth=document.documentElement.clientWidth;
this.wrapHeight=document.documentElement.clientHeight;
this._requestAnimationFrame();
this._createCanvas();
this._createAudio();
},
/**
* 對象深拷貝方法
* @method _extendDeep
* @param {object} parent 父對象
{object} child 子對象
@return {object} child 父對象繼承給子對象
**/
_extendDeep:function(child,parent){
var i,
toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === "object") {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
},
/**
* requestAnimationFrame做兼容
* @method _requestAnimationFrame
**/
_requestAnimationFrame: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);
};
}
},
/**
* 創(chuàng)建canvas畫布
* @method _createCanvas
**/
_createCanvas:function(){
var _self=this;
this.canvas=document.createElement('canvas');
this.canvas.setAttribute("data-id",Date.now());
if(!this.canvas.getContext){
alert("您的瀏覽器不支持canvas");
return;
}
this.context=this.canvas.getContext('2d');
this.canvas.width=this.wrapWidth;
this.canvas.height=this.wrapHeight;
var oBody=document.getElementsByTagName('body')[0];
oBody.appendChild(this.canvas);
this._createCacheCanvas();
},
_createCacheCanvas:function(){
var _self=this;
this.cacheCanvas=document.createElement('canvas');
this.cacheContext=this.cacheCanvas.getContext('2d');
this.cacheCanvas.width=this.wrapWidth;
this.cacheCanvas.height=this.wrapHeight;
this.coinImg=new Image();
this.coinImg.src=this.settings.coinSrc;
this.coinImg.onload=function(){
_self._startCacheCanvasAnim();
};
},
/**
* 執(zhí)行金幣繪制動畫
* @method _startCanvasAnim
**/
_startCacheCanvasAnim:function(){
var _self=this;
var availWidth=this.cacheCanvas.width-this.coinWidth;
var availHeight=this.cacheCanvas.height-this.coinHeight;
//var disX=availWidth/this.density; //每個硬幣X軸的間距
var coinRange=availWidth*this.density/(this.density+15);
var rangeStart=(availWidth-coinRange)/2;
var g=9.8*280; //重力加速度
var bPlayAudio=false;
var coinAttrArr=[]; //存儲金幣下落過程中的一些屬性參數(shù)
for(var i=0;i<_self.density;i++){
coinAttrArr[i]={
rndX:Math.random(), //存儲金幣開始降落x軸隨機值
rndOrder:Math.round(Math.random()*_self.timeLag/17), //存儲金幣撒落順序的一個數(shù)組
time:0, //存儲金幣繪制的具體時間
top:0, //存儲金幣繪制距離頂部的距離
left:0, //存儲金幣彈起后距離左邊的距離
endSpeed:0, //存儲金幣第一次接觸地面的速度
bEnd:false, //存儲金幣是否觸碰到地面
reDownSpeed:0, //存儲金幣彈起后重新降落的速度
reDownHDelta:Math.random()*100+250, //存儲金幣彈起的高度參數(shù),隨機值250~350之間
rndOffsetX:Math.random()*0.06+0.97 //存儲金幣x軸的偏移量悼泌,隨機值0.97~1.03之間
};
}
var startTime = Date.now(); //開始繪制前的時間
function draw(){
var drawStart = Date.now(); //記錄重繪的結(jié)束事件
var diff = (drawStart - startTime)/1000; //計算每次重繪所需要的事件松捉,單位為秒
startTime = drawStart; //結(jié)束事件傳給開始事件
_self.context.clearRect(0,0,_self.canvas.width,_self.canvas.height); //清除畫布,方便重繪
_self.cacheContext.clearRect(0,0,_self.cacheCanvas.width,_self.cacheCanvas.height); //清除畫布馆里,方便重繪
_self.cacheContext.save();
//根據(jù)金幣個數(shù)循環(huán)繪制金幣
for(var i=0;i<_self.density;i++){
if((coinAttrArr[i].rndOrder==0&&coinAttrArr[i].time==0)){ //如果順序為0惩坑,表示開始下落,同時下落的初始時間為0時也拜,賦值初始時間
coinAttrArr[i].time=diff;
}
if(coinAttrArr[i].time>0){ //如果初始事件大于0以舒,表示已經(jīng)在下落過程中,則每次的初始時間遞增
coinAttrArr[i].time=coinAttrArr[i].time+diff;
}
if(coinAttrArr[i].rndOrder==0){ //如果順序為0,開始下落慢哈,則開始繪制金幣
if(!coinAttrArr[i].bEnd){ //金幣下落(過程一)蔓钟,自由落體運動
coinAttrArr[i].top=g*Math.pow(coinAttrArr[i].time,2)/2-_self.coinHeight; //自由落體加速度運動,求下落的高度
//coinAttrArr[i].left=disX*coinAttrArr[i].rndX+i*disX;
coinAttrArr[i].left=coinRange*coinAttrArr[i].rndX+rangeStart;
}else if(coinAttrArr[i].endSpeed==0){ //金幣彈起后在空中重新下落(過程三)
coinAttrArr[i].reDownSpeed=coinAttrArr[i].reDownSpeed*1.1;
coinAttrArr[i].top=coinAttrArr[i].top+coinAttrArr[i].reDownSpeed;
coinAttrArr[i].left=coinAttrArr[i].left*coinAttrArr[i].rndOffsetX;
}else{ //金幣彈起(過程二)
coinAttrArr[i].endSpeed=-Math.abs(coinAttrArr[i].endSpeed*0.96);
if(Math.abs(coinAttrArr[i].endSpeed)<1) coinAttrArr[i].endSpeed=0;
coinAttrArr[i].top=coinAttrArr[i].top+coinAttrArr[i].endSpeed;
coinAttrArr[i].left=coinAttrArr[i].left*coinAttrArr[i].rndOffsetX;
}
//金幣第一次降落超過地面時卵贱,將其高度設(shè)置和地面齊平
if(coinAttrArr[i].top>_self.cacheCanvas.height-_self.coinHeight&&!coinAttrArr[i].bEnd){
coinAttrArr[i].top=_self.cacheCanvas.height-_self.coinHeight;
}
//金幣落地時滥沫,計算落地的速度
if(coinAttrArr[i].top==_self.cacheCanvas.height-_self.coinHeight){
coinAttrArr[i].endSpeed=g*coinAttrArr[i].time/coinAttrArr[i].reDownHDelta;
coinAttrArr[i].reDownSpeed=coinAttrArr[i].endSpeed/10;
coinAttrArr[i].bEnd=true;
}
//繪制金幣
_self.cacheContext.drawImage(_self.coinImg,coinAttrArr[i].left,coinAttrArr[i].top,_self.coinWidth,_self.coinHeight);
}
coinAttrArr[i].rndOrder=coinAttrArr[i].rndOrder==0?0:coinAttrArr[i].rndOrder-1;//順序每一次重繪則遞減一次侣集,直到為0時,代表開始下落
}
_self.cacheContext.restore();
_self.context.drawImage(_self.cacheCanvas,0,0,_self.canvas.width,_self.canvas.height);
var firstH=_self._maxNum(coinAttrArr,"top");//求降落過程中高度最大的金幣高度
if(firstH>=_self.cacheCanvas.height-_self.coinHeight&&!bPlayAudio){
_self._playAudio();
bPlayAudio=true;
}
var lastH=_self._minNum(coinAttrArr,"top");//求降落過程中高度最小的金幣高度
if(lastH<=_self.cacheCanvas.height+_self.coinHeight){ //最后一個金幣高度超出canvas的高度停止重繪
window.requestAnimationFrame(draw); //重繪兰绣,遞回調(diào)用繪制方法
}else{
console.log("金幣都撒完了");
_self._destory();
}
}
window.requestAnimationFrame(draw); //第一次繪制
},
/**
* 求最小值
* @method _minNum
* @param {arr} arr 屬性數(shù)組
{string} attr 數(shù)組下的屬性名稱
* @return {number} 返回數(shù)組下屬性值最小的值
**/
_minNum:function(arr,attr){
var tempArr=[];
for(var i=0;i<arr.length;i++){
tempArr.push(arr[i][attr]);
}
return tempArr.sort(function(a,b){return a-b})[0];
},
/**
* 求最大值
* @method _minNum
* @param {arr} arr 屬性數(shù)組
{string} attr 數(shù)組下的屬性名稱
* @return {number} 返回數(shù)組下屬性值最大的值
**/
_maxNum:function(arr,attr){
var tempArr=[];
for(var i=0;i<arr.length;i++){
tempArr.push(arr[i][attr]);
}
return tempArr.sort(function(a,b){return b-a})[0];
},
/**
* 創(chuàng)建音頻對象
* @method _createAudio
**/
_createAudio:function(){
this.audio=document.createElement('audio');
this.audio.setAttribute("preload","load");
var oSource=document.createElement('source');
oSource.setAttribute("src",this.settings.audioSrc);
oSource.setAttribute("type","audio/mp3");
this.audio.appendChild(oSource);
var oBody=document.getElementsByTagName('body')[0];
oBody.appendChild(this.audio);
},
/**
* 播放音頻
* @method _playAudio
**/
_playAudio:function(){
this.audio.play();
},
/**
* 銷毀canvas和audio
* @method _destory
**/
_destory:function(){
var oBody=document.getElementsByTagName('body')[0];
oBody.removeChild(this.canvas);
oBody.removeChild(this.audio);
}
};
</script>
<script>
window.onload=function(){
var oBtn=document.getElementById('btn1');
init();
initClick();
function initClick(){
var coin=new Coin();
}
var SHAKE_THRESHOLD = 400;
var last_update = 0;
var index=0;
var x = y = z = last_x = last_y = last_z = 0;
var w_curTime=0;
function init() {
if (window.DeviceMotionEvent) {
window.addEventListener('devicemotion', deviceMotionHandler, false);
} else {
alert('not support mobile event');
}
}
function deviceMotionHandler(eventData) {
var acceleration = eventData.accelerationIncludingGravity;
var curTime = new Date().getTime();
if ((curTime - last_update) > 100) {
var diffTime = curTime - last_update;
last_update = curTime;
x = acceleration.x;
y = acceleration.y;
z = acceleration.z;
var speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
var delta=Math.abs(x + y + z - last_x - last_y - last_z);
if (speed > SHAKE_THRESHOLD) {
if((curTime-w_curTime)>2000){
w_curTime!=0 && new Coin({density:Math.round(delta)});
w_curTime=curTime;
}
}
last_x = x;
last_y = y;
last_z = z;
}
}
};
</script>
</head>
<body>
<input type="button" value="撒金幣" id="btn1" />
</body>
</html>