js抽奖转盘实现方法分析


Posted in Javascript onMay 16, 2020

本文实例讲述了js抽奖转盘实现方法。分享给大家供大家参考,具体如下:

 HTML  这里.left 固定了圆的宽度和高度,还有canvas也设置了固定宽高 绘制圆心的坐标也就出来了 (203,203)

抽奖转盘是由一个大圆和一个内圆完成 ;大圆负责绘制上奖品 ,内圆负责确定指针的位置,指针直接使用图片,决定位置确定

<div class="left">

<div class="turnplate" style="background:#1bacff;border-radius: 50%">
<canvas class="item" id="wheelcanvas" width="406px" height="406px"></canvas>
<img class="pointer" src="sp2/point.png"/>
</div>

</div>

js抽奖转盘实现方法分析

外圆留空多少的问题

PS里查看间距是多少,此处圆心(203,203) 大圆的半径就是203-10 =193

js抽奖转盘实现方法分析

这个数值在下图里设置

js抽奖转盘实现方法分析

JS

<script type="text/javascript">
    var turnplate={
      restaraunts:[],				//大转盘奖品名称
      colors:[],					//大转盘奖品区块对应背景颜色
      outsideRadius:193,			//大转盘外圆的半径 192
      textRadius:155,				//大转盘奖品位置距离圆心的距离
      insideRadius:68,			//大转盘内圆的半径
      startAngle:0,				//开始角度

      bRotate:false				//false:停止;ture:旋转
    };

    $(document).ready(function(){
      //动态添加大转盘的奖品与奖品区域背景颜色
      turnplate.restaraunts = ["50元代金券", "升职加薪", "100元代金券", "财源滚滚", "200元代金券", "爱情甜蜜 ", "500元代金券", "变美变帅"];
      turnplate.colors = ["#1b62ca", "#1bacff", "#1b62ca", "#1bacff","#1b62ca", "#1bacff", "#1b62ca", "#1bacff"];


      var rotateTimeOut = function (){
        $('#wheelcanvas').rotate({
          angle:0,
          animateTo:2160,
          duration:8000,
          callback:function (){
            alert('网络超时,请检查您的网络设置!');
          }
        });
      };

      //旋转转盘 item:奖品位置; txt:提示语;
      var rotateFn = function (item, txt){
        var angles = item * (360 / turnplate.restaraunts.length) - (360 / (turnplate.restaraunts.length*2));
        if(angles<270){
          angles = 270 - angles;
        }else{
          angles = 360 - angles + 270;
        }
        $('#wheelcanvas').stopRotate();
        $('#wheelcanvas').rotate({
          angle:0,
          animateTo:angles+1800,
          duration:8000,
          callback:function (){
            alert(txt);
            turnplate.bRotate = !turnplate.bRotate;
          }
        });
      };

      $('.pointer').click(function (){
        if(turnplate.bRotate)return;
        turnplate.bRotate = !turnplate.bRotate;
        //获取随机数(奖品个数范围内)
        var item = rnd(1,turnplate.restaraunts.length);
        //奖品数量等于10,指针落在对应奖品区域的中心角度[252, 216, 180, 144, 108, 72, 36, 360, 324, 288]
        rotateFn(item, turnplate.restaraunts[item-1]);
        /* switch (item) {
         case 1:
         rotateFn(252, turnplate.restaraunts[0]);
         break;
         case 2:
         rotateFn(216, turnplate.restaraunts[1]);
         break;
         case 3:
         rotateFn(180, turnplate.restaraunts[2]);
         break;
         case 4:
         rotateFn(144, turnplate.restaraunts[3]);
         break;
         case 5:
         rotateFn(108, turnplate.restaraunts[4]);
         break;
         case 6:
         rotateFn(72, turnplate.restaraunts[5]);
         break;
         case 7:
         rotateFn(36, turnplate.restaraunts[6]);
         break;
         case 8:
         rotateFn(360, turnplate.restaraunts[7]);
         break;
         case 9:
         rotateFn(324, turnplate.restaraunts[8]);
         break;
         case 10:
         rotateFn(288, turnplate.restaraunts[9]);
         break;
         } */
        console.log(item);
      });
    });

    function rnd(n, m){
      var random = Math.floor(Math.random()*(m-n+1)+n);
      return random;

    }


    //页面所有元素加载完毕后执行drawRouletteWheel()方法对转盘进行渲染
    window.onload=function(){
      drawRouletteWheel();
    };

    function drawRouletteWheel() {
      var canvas = document.getElementById("wheelcanvas");
      if (canvas.getContext) {
        //根据奖品个数计算圆周角度
        var arc = Math.PI / (turnplate.restaraunts.length/2);//圆周率/ 奖品数量除以2
        var ctx = canvas.getContext("2d");
        //在给定矩形内清空一个矩形
        ctx.clearRect(0,0,422,422);
        //strokeStyle 属性设置或返回用于笔触的颜色、渐变或模式
        ctx.strokeStyle = "#FFBE04";
        //font 属性设置或返回画布上文本内容的当前字体属性
        ctx.font = '16px Microsoft YaHei';
        // 绘制圆 (弧形)
        for(var i = 0; i < turnplate.restaraunts.length; i++) {
          var angle = turnplate.startAngle + i * arc;
          ctx.fillStyle = turnplate.colors[i];
          ctx.beginPath();
          //arc(x,y,r,起始角,结束角,绘制方向) 方法创建弧/曲线(用于创建圆或部分圆)
          ctx.arc(203, 203, turnplate.outsideRadius, angle, angle + arc, false);//绘制外圆
          ctx.arc(203, 203, turnplate.insideRadius, angle + arc, angle, true);//绘制内圆
          ctx.stroke();
          ctx.fill();
          //锁画布(为了保存之前的画布状态)
          ctx.save();

          //----绘制奖品开始----
          ctx.fillStyle = "#FFF";/*奖品文字颜色*/
          var text = turnplate.restaraunts[i];
          var line_height = 17;
          //translate方法重新映射画布上的 (0,0) 位置
          ctx.translate(211 + Math.cos(angle + arc / 2) * turnplate.textRadius, 211 + Math.sin(angle + arc / 2) * turnplate.textRadius);

          //rotate方法旋转当前的绘图
          ctx.rotate(angle + arc / 2 + Math.PI / 2);

          /** 下面代码根据奖品类型、奖品名称长度渲染不同效果,如字体、颜色、图片效果。(具体根据实际情况改变) **/
          if(text.indexOf("M")>0){//流量包
            var texts = text.split("M");
            for(var j = 0; j<texts.length; j++){
              ctx.font = j == 0?'bold 20px Microsoft YaHei':'16px Microsoft YaHei';
              if(j == 0){
                ctx.fillText(texts[j]+"M", -ctx.measureText(texts[j]+"M").width / 2, j * line_height);
              }else{
                ctx.fillText(texts[j], -ctx.measureText(texts[j]).width / 2, j * line_height);
              }
            }
          }else if(text.indexOf("M") == -1 && text.length>6){//奖品名称长度超过一定范围
            text = text.substring(0,6)+"||"+text.substring(6);
            var texts = text.split("||");
            for(var j = 0; j<texts.length; j++){
              ctx.fillText(texts[j], -ctx.measureText(texts[j]).width / 2, j * line_height);
            }
          }else{
            //在画布上绘制填色的文本。文本的默认颜色是黑色
            //measureText()方法返回包含一个对象,该对象包含以像素计的指定字体宽度
            ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
          }

          //添加对应图标
          if(text.indexOf("闪币")>0){
            var img= document.getElementById("shan-img");
            img.onload=function(){
              ctx.drawImage(img,-15,10);
            };
            ctx.drawImage(img,-15,10);
          }else if(text.indexOf("谢谢参与")>=0){
            var img= document.getElementById("sorry-img");
            img.onload=function(){
              ctx.drawImage(img,-15,10);
            };
            ctx.drawImage(img,-15,10);
          }
          //把当前画布返回(调整)到上一个save()状态之前
          ctx.restore();
          //----绘制奖品结束----
        }
      }
    }

  </script>

引用jquery

在加载以下JS

/* ????????????? www.datouwang.com */
(function($) {
var supportedCSS,styles=document.getElementsByTagName("head")[0].style,toCheck="transformProperty WebkitTransform OTransform msTransform MozTransform".split(" ");
for (var a=0;a<toCheck.length;a++) if (styles[toCheck[a]] !== undefined) supportedCSS = toCheck[a];
// Bad eval to preven google closure to remove it from code o_O
// After compresion replace it back to var IE = 'v' == '\v'
var IE = eval('"v"=="\v"');

jQuery.fn.extend({
  rotate:function(parameters)
  {
    if (this.length===0||typeof parameters=="undefined") return;
      if (typeof parameters=="number") parameters={angle:parameters};
    var returned=[];
    for (var i=0,i0=this.length;i<i0;i++)
      {
        var element=this.get(i);	
        if (!element.Wilq32 || !element.Wilq32.PhotoEffect) {

          var paramClone = $.extend(true, {}, parameters); 
          var newRotObject = new Wilq32.PhotoEffect(element,paramClone)._rootObj;

          returned.push($(newRotObject));
        }
        else {
          element.Wilq32.PhotoEffect._handleRotation(parameters);
        }
      }
      return returned;
  },
  getRotateAngle: function(){
    var ret = [];
    for (var i=0,i0=this.length;i<i0;i++)
      {
        var element=this.get(i);	
        if (element.Wilq32 && element.Wilq32.PhotoEffect) {
          ret[i] = element.Wilq32.PhotoEffect._angle;
        }
      }
      return ret;
  },
  stopRotate: function(){
    for (var i=0,i0=this.length;i<i0;i++)
      {
        var element=this.get(i);	
        if (element.Wilq32 && element.Wilq32.PhotoEffect) {
          clearTimeout(element.Wilq32.PhotoEffect._timer);
        }
      }
  }
});

// Library agnostic interface

Wilq32=window.Wilq32||{};
Wilq32.PhotoEffect=(function(){

	if (supportedCSS) {
		return function(img,parameters){
			img.Wilq32 = {
				PhotoEffect: this
			};
      
      this._img = this._rootObj = this._eventObj = img;
      this._handleRotation(parameters);
		}
	} else {
		return function(img,parameters) {
			// Make sure that class and id are also copied - just in case you would like to refeer to an newly created object
      this._img = img;

			this._rootObj=document.createElement('span');
			this._rootObj.style.display="inline-block";
			this._rootObj.Wilq32 = 
				{
					PhotoEffect: this
				};
			img.parentNode.insertBefore(this._rootObj,img);
			
			if (img.complete) {
				this._Loader(parameters);
			} else {
				var self=this;
				// TODO: Remove jQuery dependency
				jQuery(this._img).bind("load", function()
				{
					self._Loader(parameters);
				});
			}
		}
	}
})();

Wilq32.PhotoEffect.prototype={
  _setupParameters : function (parameters){
		this._parameters = this._parameters || {};
    if (typeof this._angle !== "number") this._angle = 0 ;
    if (typeof parameters.angle==="number") this._angle = parameters.angle;
    this._parameters.animateTo = (typeof parameters.animateTo==="number") ? (parameters.animateTo) : (this._angle); 

    this._parameters.step = parameters.step || this._parameters.step || null;
		this._parameters.easing = parameters.easing || this._parameters.easing || function (x, t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b; }
		this._parameters.duration = parameters.duration || this._parameters.duration || 1000;
    this._parameters.callback = parameters.callback || this._parameters.callback || function(){};
    if (parameters.bind && parameters.bind != this._parameters.bind) this._BindEvents(parameters.bind); 
	},
	_handleRotation : function(parameters){
     this._setupParameters(parameters);
     if (this._angle==this._parameters.animateTo) {
       this._rotate(this._angle);
     }
     else { 
       this._animateStart();     
     }
	},

	_BindEvents:function(events){
		if (events && this._eventObj) 
		{
      // Unbinding previous Events
      if (this._parameters.bind){
        var oldEvents = this._parameters.bind;
        for (var a in oldEvents) if (oldEvents.hasOwnProperty(a)) 
            // TODO: Remove jQuery dependency
            jQuery(this._eventObj).unbind(a,oldEvents[a]);
      }

      this._parameters.bind = events;
			for (var a in events) if (events.hasOwnProperty(a)) 
				// TODO: Remove jQuery dependency
					jQuery(this._eventObj).bind(a,events[a]);
		}
	},

	_Loader:(function()
	{
		if (IE)
		return function(parameters)
		{
			var width=this._img.width;
			var height=this._img.height;
			this._img.parentNode.removeChild(this._img);
							
			this._vimage = this.createVMLNode('image');
			this._vimage.src=this._img.src;
			this._vimage.style.height=height+"px";
			this._vimage.style.width=width+"px";
			this._vimage.style.position="absolute"; // FIXES IE PROBLEM - its only rendered if its on absolute position!
			this._vimage.style.top = "0px";
			this._vimage.style.left = "0px";

			/* Group minifying a small 1px precision problem when rotating object */
			this._container = this.createVMLNode('group');
			this._container.style.width=width;
			this._container.style.height=height;
			this._container.style.position="absolute";
			this._container.setAttribute('coordsize',width-1+','+(height-1)); // This -1, -1 trying to fix ugly problem with small displacement on IE
			this._container.appendChild(this._vimage);
			
			this._rootObj.appendChild(this._container);
			this._rootObj.style.position="relative"; // FIXES IE PROBLEM
			this._rootObj.style.width=width+"px";
			this._rootObj.style.height=height+"px";
			this._rootObj.setAttribute('id',this._img.getAttribute('id'));
			this._rootObj.className=this._img.className;			
		  this._eventObj = this._rootObj;	
		  this._handleRotation(parameters);	
		}
		else
		return function (parameters)
		{
			this._rootObj.setAttribute('id',this._img.getAttribute('id'));
			this._rootObj.className=this._img.className;
			
			this._width=this._img.width;
			this._height=this._img.height;
			this._widthHalf=this._width/2; // used for optimisation
			this._heightHalf=this._height/2;// used for optimisation
			
			var _widthMax=Math.sqrt((this._height)*(this._height) + (this._width) * (this._width));

			this._widthAdd = _widthMax - this._width;
			this._heightAdd = _widthMax - this._height;	// widthMax because maxWidth=maxHeight
			this._widthAddHalf=this._widthAdd/2; // used for optimisation
			this._heightAddHalf=this._heightAdd/2;// used for optimisation
			
			this._img.parentNode.removeChild(this._img);	
			
			this._aspectW = ((parseInt(this._img.style.width,10)) || this._width)/this._img.width;
			this._aspectH = ((parseInt(this._img.style.height,10)) || this._height)/this._img.height;
			
			this._canvas=document.createElement('canvas');
			this._canvas.setAttribute('width',this._width);
			this._canvas.style.position="relative";
			this._canvas.style.left = -this._widthAddHalf + "px";
			this._canvas.style.top = -this._heightAddHalf + "px";
			this._canvas.Wilq32 = this._rootObj.Wilq32;
			
			this._rootObj.appendChild(this._canvas);
			this._rootObj.style.width=this._width+"px";
			this._rootObj.style.height=this._height+"px";
      this._eventObj = this._canvas;
			
			this._cnv=this._canvas.getContext('2d');
      this._handleRotation(parameters);
		}
	})(),

	_animateStart:function()
	{	
		if (this._timer) {
			clearTimeout(this._timer);
		}
		this._animateStartTime = +new Date;
		this._animateStartAngle = this._angle;
		this._animate();
	},
  _animate:function()
  {
     var actualTime = +new Date;
     var checkEnd = actualTime - this._animateStartTime > this._parameters.duration;

     // TODO: Bug for animatedGif for static rotation ? (to test)
     if (checkEnd && !this._parameters.animatedGif) 
     {
       clearTimeout(this._timer);
     }
     else 
     {
       if (this._canvas||this._vimage||this._img) {
         var angle = this._parameters.easing(0, actualTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration);
         this._rotate((~~(angle*10))/10);
       }
       if (this._parameters.step) {
        this._parameters.step(this._angle);
       }
       var self = this;
       this._timer = setTimeout(function()
           {
           self._animate.call(self);
           }, 10);
     }

     // To fix Bug that prevents using recursive function in callback I moved this function to back
     if (this._parameters.callback && checkEnd){
       this._angle = this._parameters.animateTo;
       this._rotate(this._angle);
       this._parameters.callback.call(this._rootObj);
     }
   },

	_rotate : (function()
	{
		var rad = Math.PI/180;
		if (IE)
		return function(angle)
		{
      this._angle = angle;
			this._container.style.rotation=(angle%360)+"deg";
		}
		else if (supportedCSS)
		return function(angle){
      this._angle = angle;
			this._img.style[supportedCSS]="rotate("+(angle%360)+"deg)";
		}
		else 
		return function(angle)
		{
      this._angle = angle;
			angle=(angle%360)* rad;
			// clear canvas	
			this._canvas.width = this._width+this._widthAdd;
			this._canvas.height = this._height+this._heightAdd;
						
			// REMEMBER: all drawings are read from backwards.. so first function is translate, then rotate, then translate, translate..
			this._cnv.translate(this._widthAddHalf,this._heightAddHalf);	// at least center image on screen
			this._cnv.translate(this._widthHalf,this._heightHalf);			// we move image back to its orginal 
			this._cnv.rotate(angle);										// rotate image
			this._cnv.translate(-this._widthHalf,-this._heightHalf);		// move image to its center, so we can rotate around its center
			this._cnv.scale(this._aspectW,this._aspectH); // SCALE - if needed ;)
			this._cnv.drawImage(this._img, 0, 0);							// First - we draw image
		}

	})()
}

if (IE)
{
Wilq32.PhotoEffect.prototype.createVMLNode=(function(){
document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
		try {
			!document.namespaces.rvml && document.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
			return function (tagName) {
				return document.createElement('<rvml:' + tagName + ' class="rvml">');
			};
		} catch (e) {
			return function (tagName) {
				return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
			};
		}
})();
}
})(jQuery);

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun 测试上述代码运行效果。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
抽出www.templatemonster.com的鼠标悬停加载大图模板的代码
Jul 11 Javascript
封装html的select标签的js操作实例
Jul 02 Javascript
javascript中返回顶部按钮的实现
May 05 Javascript
使用纯JS代码判断字符串中有多少汉字的实现方法(超简单实用)
Nov 12 Javascript
详解Vue监听数据变化原理
Mar 08 Javascript
JavaScript 中Date对象的格式化代码方法汇总
Sep 06 Javascript
Chrome调试折腾记之JS断点调试技巧
Sep 11 Javascript
微信小程序支付之c#后台实现方法
Oct 19 Javascript
Webpack 4.x搭建react开发环境的方法步骤
Aug 15 Javascript
微信小程序整合使用富文本编辑器的方法详解
Apr 25 Javascript
js实现随机圆与矩形功能
Oct 29 Javascript
JS前端使用Canvas快速实现手势解锁特效
Sep 23 Javascript
JSONP 的原理、理解 与 实例分析
May 16 #Javascript
JavaScript随机数的组合问题案例分析
May 16 #Javascript
Taro UI框架开发小程序实现左滑喜欢右滑不喜欢效果的示例代码
May 18 #Javascript
vue el-tree 默认展开第一个节点的实现代码
May 15 #Javascript
基于leaflet.js实现修改地图主题样式的流程分析
May 15 #Javascript
uni-app从安装到卸载的入门教程
May 15 #Javascript
Vue数据双向绑定原理实例解析
May 15 #Javascript
You might like
详细介绍:Apache+PHP+MySQL配置攻略
2006/09/05 PHP
利用PHP动态生成VRML网页
2006/10/09 PHP
PHP内核探索之解释器的执行过程
2015/12/22 PHP
yii2 在控制器中验证请求参数的使用方法
2019/06/19 PHP
基于Laravel 多个中间件的执行顺序详解
2019/10/21 PHP
IE之动态添加DOM节点触发window.resize事件
2010/07/27 Javascript
Knockoutjs的环境搭建教程
2012/11/26 Javascript
JS动态添加与删除select中的Option对象(示例代码)
2013/12/25 Javascript
什么是MEAN?JavaScript编程中的MEAN是什么意思?
2014/12/18 Javascript
jquery.qtip提示信息插件用法简单实例
2016/06/17 Javascript
jquery属性,遍历,HTML操作方法详解
2016/09/17 Javascript
jQuery grep()方法详解及实例代码
2016/10/30 Javascript
详解Vue学习笔记进阶篇之列表过渡及其他
2017/07/17 Javascript
jQuery+HTML5实现WebGL高性能烟花绽放动画效果【附demo源码下载】
2017/08/18 jQuery
解决IE7中使用jQuery动态操作name问题
2017/08/28 jQuery
Node.js中Bootstrap-table的两种分页的实现方法
2017/09/18 Javascript
webpack external模块的具体使用
2018/03/10 Javascript
浅谈Vue组件及组件的注册方法
2018/08/24 Javascript
微信小程序系列之自定义顶部导航功能
2019/05/21 Javascript
vue获取验证码倒计时组件
2019/08/26 Javascript
Vue 实现一个命令式弹窗组件功能
2019/09/25 Javascript
使用python Django做网页
2013/11/04 Python
python对字典进行排序实例
2014/09/25 Python
在Python中使用模块的教程
2015/04/27 Python
python列表的增删改查实例代码
2018/01/30 Python
python3 cvs将数据读取为字典的方法
2018/12/22 Python
搞清楚 Python traceback的具体使用方法
2019/05/13 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
2019/11/11 Python
Python进阶之迭代器与迭代器切片教程
2020/01/29 Python
澳大利亚电子产品购物网站:Dick Smith
2017/02/02 全球购物
村官学习十八大感想
2014/01/15 职场文书
人事主管岗位职责说明书
2014/07/30 职场文书
2015年党日活动总结范文
2015/03/25 职场文书
可可西里观后感
2015/06/08 职场文书
关于 Python json中load和loads区别
2021/11/07 Python
Python first-order-model实现让照片动起来
2022/06/25 Python