PHPIN.NET

 找回密码
 立即注册
查看: 10477|回复: 0

[HTML5/CSS3] 模仿淘宝移动端撒金币效果

[复制链接]

469

主题

31

回帖

5569

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5569
发表于 2015-5-22 09:28:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
模仿淘宝移动端撒金币效果
可在手机上摇一摇试试,不过目前手机上金币多的话渲染就会很卡
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>摇一摇撒金币</title>
  6. <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui" />
  7. <style>
  8.         body{margin:0;padding:0;}
  9.         input{position:absolute;z-index:1000}
  10.         canvas{position:absolute;top:0;left:0;}
  11. </style>
  12. <script>
  13.         function Coin(opts){
  14.                 //默认参数
  15.                 this.defaults={
  16.                         coinSrc:"http://gw.alicdn.com/tps/i3/TB1QJ5DGpXXXXaBXXXXuv2kGFXX-39-39.png_40x40Q50s150.jpg",     //金币图片地址
  17.                         audioSrc:"http://download.taobaocdn.com/freedom/26370/media/shake.mp3",        //金币音频地址
  18.                         coinWidth:20,           //金币宽度
  19.                         coinHeight:20,          //金币高度
  20.                         density:30
  21.                 };
  22.                 this.settings=this._extendDeep(this.defaults,opts);   //深拷贝
  23.                 this.density=this.settings.density;                   //密度,即金币个数
  24.                 this.timeLag=1000;                                    //金币散落的事件间隔,数字越大表示间隔越大
  25.                 this.coinWidth=this.settings.coinWidth;               //金币宽度
  26.                 this.coinHeight=this.settings.coinHeight;             //金币高度
  27.                 this.wrapWidth=0;
  28.                 this.wrapHeight=0;
  29.                 this._init();
  30.         }
  31.         Coin.prototype={
  32.                 constructor:Coin,
  33.                
  34.                 /**
  35.                  * 动画初始化方法
  36.                  * @method _init
  37.                 **/
  38.                 _init:function(){
  39.                         //初始化包括尺寸大小
  40.                         this.wrapWidth=document.documentElement.clientWidth;
  41.                         this.wrapHeight=document.documentElement.clientHeight;
  42.                        
  43.                         this._requestAnimationFrame();
  44.                         this._createCanvas();
  45.                         this._createAudio();
  46.                        
  47.                 },
  48.                
  49.                 /**
  50.                  * 对象深拷贝方法
  51.                  * @method _extendDeep
  52.                  * @param  {object} parent 父对象
  53.                                    {object} child  子对象
  54.                    @return {object} child  父对象继承给子对象
  55.                 **/
  56.                 _extendDeep:function(child,parent){
  57.                         var i,
  58.                         toStr = Object.prototype.toString,
  59.                         astr = "[object Array]";
  60.                         child = child || {};
  61.                         for (i in parent) {
  62.                                 if (parent.hasOwnProperty(i)) {
  63.                                         if (typeof parent[i] === "object") {
  64.                                                 child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
  65.                                                 extendDeep(parent[i], child[i]);
  66.                                         } else {
  67.                                                 child[i] = parent[i];
  68.                                         }
  69.                                 }
  70.                         }
  71.                         return child;
  72.                 },
  73.                
  74.                 /**
  75.                  * requestAnimationFrame做兼容
  76.                  * @method _requestAnimationFrame
  77.                 **/
  78.                 _requestAnimationFrame:function(){
  79.                         var lastTime = 0;
  80.                         var vendors = ['webkit', 'moz'];
  81.                         for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  82.                                 window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
  83.                                 window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||    // name has changed in Webkit
  84.                                                                                           window[vendors[x] + 'CancelRequestAnimationFrame'];
  85.                         }
  86.                
  87.                         if (!window.requestAnimationFrame) {
  88.                                 window.requestAnimationFrame = function(callback, element) {
  89.                                         var currTime = new Date().getTime();
  90.                                         var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
  91.                                         var id = window.setTimeout(function() {
  92.                                                 callback(currTime + timeToCall);
  93.                                         }, timeToCall);
  94.                                         lastTime = currTime + timeToCall;
  95.                                         return id;
  96.                                 };
  97.                         }
  98.                         if (!window.cancelAnimationFrame) {
  99.                                 window.cancelAnimationFrame = function(id) {
  100.                                         clearTimeout(id);
  101.                                 };
  102.                         }
  103.                 },
  104.                
  105.                 /**
  106.                  * 创建canvas画布
  107.                  * @method _createCanvas
  108.                 **/
  109.                 _createCanvas:function(){
  110.                         var _self=this;
  111.                         this.canvas=document.createElement('canvas');
  112.                         this.canvas.setAttribute("data-id",Date.now());
  113.                         if(!this.canvas.getContext){
  114.                                 alert("您的浏览器不支持canvas");
  115.                                 return;
  116.                         }
  117.                         this.context=this.canvas.getContext('2d');
  118.                         this.canvas.width=this.wrapWidth;
  119.                         this.canvas.height=this.wrapHeight;
  120.                         var oBody=document.getElementsByTagName('body')[0];
  121.                         oBody.appendChild(this.canvas);
  122.                         this._createCacheCanvas();
  123.                 },
  124.                
  125.                 _createCacheCanvas:function(){
  126.                         var _self=this;
  127.                         this.cacheCanvas=document.createElement('canvas');
  128.                         this.cacheContext=this.cacheCanvas.getContext('2d');
  129.                         this.cacheCanvas.width=this.wrapWidth;
  130.                         this.cacheCanvas.height=this.wrapHeight;
  131.                         this.coinImg=new Image();
  132.                         this.coinImg.src=this.settings.coinSrc;
  133.                         this.coinImg.onload=function(){
  134.                                 _self._startCacheCanvasAnim();
  135.                         }
  136.                 },
  137.                
  138.                
  139.                 /**
  140.                  * 执行金币绘制动画
  141.                  * @method _startCanvasAnim
  142.                 **/
  143.                 _startCacheCanvasAnim:function(){
  144.                         var _self=this;
  145.                         var availWidth=this.cacheCanvas.width-this.coinWidth;
  146.                         var availHeight=this.cacheCanvas.height-this.coinHeight;
  147.                         //var disX=availWidth/this.density;  //每个硬币X轴的间距
  148.                         var coinRange=availWidth*this.density/(this.density+15);
  149.                         var rangeStart=(availWidth-coinRange)/2;
  150.                         var g=9.8*280;   //重力加速度
  151.                         var bPlayAudio=false;
  152.                          
  153.                         var coinAttrArr=[];  //存储金币下落过程中的一些属性参数
  154.                         for(var i=0;i<_self.density;i++){
  155.                                 coinAttrArr[i]={
  156.                                         rndX:Math.random(),                                    //存储金币开始降落x轴随机值
  157.                                         rndOrder:Math.round(Math.random()*_self.timeLag/17),   //存储金币撒落顺序的一个数组
  158.                                         time:0,                                                                                       //存储金币绘制的具体时间
  159.                                         top:0,                                                 //存储金币绘制距离顶部的距离
  160.                                         left:0,                                                //存储金币弹起后距离左边的距离
  161.                                         endSpeed:0,                                            //存储金币第一次接触地面的速度
  162.                                         bEnd:false,                                                                               //存储金币是否触碰到地面
  163.                                         reDownSpeed:0,                                         //存储金币弹起后重新降落的速度
  164.                                         reDownHDelta:Math.random()*100+250,                    //存储金币弹起的高度参数,随机值250~350之间
  165.                                         rndOffsetX:Math.random()*0.06+0.97                     //存储金币x轴的偏移量,随机值0.97~1.03之间
  166.                                 }
  167.                         }
  168.                        
  169.                         var startTime =  Date.now();  //开始绘制前的时间  
  170.                         function draw(){
  171.                                
  172.                                 var drawStart = Date.now();  //记录重绘的结束事件
  173.                                 var diff = (drawStart - startTime)/1000;  //计算每次重绘所需要的事件,单位为秒
  174.                                 startTime = drawStart;   //结束事件传给开始事件
  175.                                 _self.context.clearRect(0,0,_self.canvas.width,_self.canvas.height);  //清除画布,方便重绘
  176.                                 _self.cacheContext.clearRect(0,0,_self.cacheCanvas.width,_self.cacheCanvas.height);  //清除画布,方便重绘
  177.                                 _self.cacheContext.save();
  178.                                
  179.                                 //根据金币个数循环绘制金币
  180.                                 for(var i=0;i<_self.density;i++){
  181.                                         if((coinAttrArr[i].rndOrder==0&&coinAttrArr[i].time==0)){   //如果顺序为0,表示开始下落,同时下落的初始时间为0时,赋值初始时间
  182.                                                 coinAttrArr[i].time=diff;
  183.                                         }
  184.                                         if(coinAttrArr[i].time>0){     //如果初始事件大于0,表示已经在下落过程中,则每次的初始时间递增
  185.                                                 coinAttrArr[i].time=coinAttrArr[i].time+diff;
  186.                                         }
  187.                                         if(coinAttrArr[i].rndOrder==0){  //如果顺序为0,开始下落,则开始绘制金币
  188.                                                 if(!coinAttrArr[i].bEnd){   //金币下落(过程一),自由落体运动
  189.                                                         coinAttrArr[i].top=g*Math.pow(coinAttrArr[i].time,2)/2-_self.coinHeight;   //自由落体加速度运动,求下落的高度
  190.                                                         //coinAttrArr[i].left=disX*coinAttrArr[i].rndX+i*disX;
  191.                                                         coinAttrArr[i].left=coinRange*coinAttrArr[i].rndX+rangeStart;
  192.                                                 }else if(coinAttrArr[i].endSpeed==0){   //金币弹起后在空中重新下落(过程三)
  193.                                                         coinAttrArr[i].reDownSpeed=coinAttrArr[i].reDownSpeed*1.1;
  194.                                                         coinAttrArr[i].top=coinAttrArr[i].top+coinAttrArr[i].reDownSpeed;
  195.                                                         coinAttrArr[i].left=coinAttrArr[i].left*coinAttrArr[i].rndOffsetX;
  196.                                                 }else{   //金币弹起(过程二)
  197.                                                         coinAttrArr[i].endSpeed=-Math.abs(coinAttrArr[i].endSpeed*0.96);
  198.                                                         if(Math.abs(coinAttrArr[i].endSpeed)<1) coinAttrArr[i].endSpeed=0;
  199.                                                         coinAttrArr[i].top=coinAttrArr[i].top+coinAttrArr[i].endSpeed;
  200.                                                         coinAttrArr[i].left=coinAttrArr[i].left*coinAttrArr[i].rndOffsetX;
  201.                                                 }
  202.                                                
  203.                                                 //金币第一次降落超过地面时,将其高度设置和地面齐平
  204.                                                 if(coinAttrArr[i].top>_self.cacheCanvas.height-_self.coinHeight&&!coinAttrArr[i].bEnd){
  205.                                                         coinAttrArr[i].top=_self.cacheCanvas.height-_self.coinHeight;
  206.                                                 }
  207.                                                
  208.                                                 //金币落地时,计算落地的速度
  209.                                                 if(coinAttrArr[i].top==_self.cacheCanvas.height-_self.coinHeight){
  210.                                                         coinAttrArr[i].endSpeed=g*coinAttrArr[i].time/coinAttrArr[i].reDownHDelta;
  211.                                                         coinAttrArr[i].reDownSpeed=coinAttrArr[i].endSpeed/10;
  212.                                                         coinAttrArr[i].bEnd=true;
  213.                                                 }
  214.                                                
  215.                                                 //绘制金币
  216.                                                 _self.cacheContext.drawImage(_self.coinImg,coinAttrArr[i].left,coinAttrArr[i].top,_self.coinWidth,_self.coinHeight);
  217.                                         }
  218.                                         coinAttrArr[i].rndOrder=coinAttrArr[i].rndOrder==0?0:coinAttrArr[i].rndOrder-1;//顺序每一次重绘则递减一次,直到为0时,代表开始下落
  219.                                 }
  220.                                 _self.cacheContext.restore();
  221.                                
  222.                                 _self.context.drawImage(_self.cacheCanvas,0,0,_self.canvas.width,_self.canvas.height);
  223.                                
  224.                                 var firstH=_self._maxNum(coinAttrArr,"top");//求降落过程中高度最大的金币高度
  225.                                 if(firstH>=_self.cacheCanvas.height-_self.coinHeight&&!bPlayAudio){
  226.                                         _self._playAudio();
  227.                                         bPlayAudio=true;
  228.                                 }
  229.                                
  230.                                 var lastH=_self._minNum(coinAttrArr,"top");//求降落过程中高度最小的金币高度
  231.                                 if(lastH<=_self.cacheCanvas.height+_self.coinHeight){ //最后一个金币高度超出canvas的高度停止重绘
  232.                                         window.requestAnimationFrame(draw);  //重绘,递回调用绘制方法
  233.                                 }else{
  234.                                         console.log("金币都撒完了");
  235.                                         _self._destory();
  236.                                 }
  237.                                
  238.                                
  239.                         }
  240.                        
  241.                         window.requestAnimationFrame(draw);  //第一次绘制
  242.                 },
  243.                
  244.                
  245.                 /**
  246.                  * 求最小值
  247.                  * @method _minNum
  248.                  * @param   {arr}    arr  属性数组
  249.                                         {string} attr 数组下的属性名称
  250.                  * @return  {number}      返回数组下属性值最小的值
  251.                 **/
  252.                 _minNum:function(arr,attr){
  253.                         var tempArr=[];
  254.                         for(var i=0;i<arr.length;i++){
  255.                                 tempArr.push(arr[i][attr]);       
  256.                         }
  257.                         return tempArr.sort(function(a,b){return a-b})[0];
  258.                 },
  259.                
  260.                 /**
  261.                  * 求最大值
  262.                  * @method _minNum
  263.                  * @param   {arr}    arr  属性数组
  264.                                         {string} attr 数组下的属性名称
  265.                  * @return  {number}      返回数组下属性值最大的值
  266.                 **/
  267.                 _maxNum:function(arr,attr){
  268.                         var tempArr=[];
  269.                         for(var i=0;i<arr.length;i++){
  270.                                 tempArr.push(arr[i][attr]);       
  271.                         }
  272.                         return tempArr.sort(function(a,b){return b-a})[0];
  273.                 },
  274.                
  275.                 /**
  276.                  * 创建音频对象
  277.                  * @method _createAudio
  278.                 **/
  279.                 _createAudio:function(){
  280.                         this.audio=document.createElement('audio');
  281.                         this.audio.setAttribute("preload","load");
  282.                         var oSource=document.createElement('source');
  283.                         oSource.setAttribute("src",this.settings.audioSrc);
  284.                         oSource.setAttribute("type","audio/mp3");
  285.                         this.audio.appendChild(oSource);
  286.                         var oBody=document.getElementsByTagName('body')[0];
  287.                         oBody.appendChild(this.audio);
  288.                 },
  289.                
  290.                 /**
  291.                  * 播放音频
  292.                  * @method _playAudio
  293.                 **/
  294.                 _playAudio:function(){
  295.                         this.audio.play();
  296.                 },
  297.                
  298.                 /**
  299.                  * 销毁canvas和audio
  300.                  * @method _destory
  301.                 **/
  302.                 _destory:function(){
  303.                         var oBody=document.getElementsByTagName('body')[0];
  304.                         oBody.removeChild(this.canvas);
  305.                         oBody.removeChild(this.audio);       
  306.                 }
  307.         }
  308. </script>
  309. <script>
  310.         window.onload=function(){
  311.                 var oBtn=document.getElementById('btn1');
  312.                 init();
  313.                 oBtn.onclick=function(){
  314.                         var coin=new Coin();       
  315.                 }
  316.                
  317.                 var SHAKE_THRESHOLD = 400;
  318.         var last_update = 0;
  319.                 var index=0;
  320.         var x = y = z = last_x = last_y = last_z = 0;
  321.                 var w_curTime=0;
  322.         function init() {
  323.             if (window.DeviceMotionEvent) {
  324.                 window.addEventListener('devicemotion', deviceMotionHandler, false);
  325.             } else {
  326.                 alert('not support mobile event');
  327.             }
  328.         }
  329.         function deviceMotionHandler(eventData) {
  330.             var acceleration = eventData.accelerationIncludingGravity;
  331.             var curTime = new Date().getTime();
  332.             if ((curTime - last_update) > 100) {
  333.                 var diffTime = curTime - last_update;
  334.                 last_update = curTime;
  335.                 x = acceleration.x;
  336.                 y = acceleration.y;
  337.                 z = acceleration.z;
  338.                 var speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
  339.                                 var delta=Math.abs(x + y + z - last_x - last_y - last_z);
  340.                                
  341.                 if (speed > SHAKE_THRESHOLD) {
  342.                                         if((curTime-w_curTime)>2000){       
  343.                                                 w_curTime!=0 && new Coin({density:Math.round(delta)});
  344.                                                  w_curTime=curTime;                                                                                               
  345.                                         }
  346.                 }
  347.                 last_x = x;
  348.                 last_y = y;
  349.                 last_z = z;
  350.             }
  351.         }
  352.        
  353.         }
  354. </script>
  355. </head>
  356. <body>
  357. <input type="button" value="撒金币" id="btn1" />
  358. </body>
  359. </html>
复制代码


仿手机支付宝撒金币.zip (36.9 KB, 下载次数: 540)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|PHPIN.NET ( 冀ICP备12000898号-14 )|网站地图

GMT+8, 2024-11-21 21:20

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表