之前做过的项目中,有需要抽奖转盘功能的。项目已经完工一段时间了,也没出现什么严重的bug,所以现在拎出来分享给大家。

功能需求

1、转盘要美观,转动效果流畅。
2、转盘上需要显示奖品图片,并且奖品是后台读取的照片和名字。
3、转动动画完成后要有相应提示。
4、获取的奖品具体算法在数据库里操作,前端只提供最后的效果展示。 

知识要点

1、引用了一个jq插件:awardRotate,用来实现更智能化的转动。

2、使用canvas标签和对应的html5 api 进行操作。

正文

引用大转盘样式

.lunck_draw_wrap{display:block;width:95%;margin-right:auto;}
 .lunck_draw_wrap .turnplate{display:block;width:106%; position:relative;}
 .lunck_draw_wrap .turnplate canvas.item{left:1px;
 position: relative;
 top:9px;
 width:100%;}
 .lunck_draw_wrap .turnplate img.pointer{ height:37.5%;
 left:34.6%;
 position: absolute;
 top:30%;
 width:31.5%;}

转盘插件所需参数:

var turnplate ={
 restaraunts:[],//大转盘奖品名称
 lucky:[],//奖品内容
 colors:[],//大转盘奖品区块对应背景颜色
 goodsimgArr:[],//奖品图片页面标签
 outsideRadius:175,//大转盘外圆的半径
 textRadius:140,//大转盘奖品位置距离圆心的距离
 insideRadius:65,//大转盘内圆的半径
 startAngle:0,//开始角度
 bRotate:false//false:停止;ture:旋转
 };

由参数可知,我们需要从服务端获取相应的奖品名称,奖品内容,奖品图片页面标签等信息,再对大转盘进行渲染。
所以我们的第一步操作就是向服务端发送请求获取对应的奖品信息,并且遍历到生成大转盘所需的数组参数里:

$.each(data.list,function(key, value){
 turnplate.restaraunts.push(value.data0);
 turnplate.lucky.push(value.data1);
 turnplate.goodsimgArr.push(getLuckyImg + value.data4);
 if(key %2==0)
 turnplate.colors.push("#fff");
 else
 turnplate.colors.push("#5fcbd4");
 })

data.list是我获取来的奖品json数据:

[
 {
 "data0":"一等奖",
 "data1":"iphone6s",
 "data2":"0",
 "data3":"0",
 "data4":"201510161406303384.png",
 "data5":"XXXX网络科技",
 "data6":"浙江省衢州市柯城区XXXXX",
 "data7":"0570-XXXXXX"
 },......
 ]

由于客户要求奖品没有“谢谢参与”,所以最低奖品也为“优胜奖”,所以在遍历奖品之后,插入有关“优胜奖”的渲染描述即可:

turnplate.goodsimgArr.push('../images/hongbao.png')
 turnplate.restaraunts.push("优胜奖");
 turnplate.colors.push("#5fcbd4");
 //页面所有元素加载完毕后执行drawRouletteWheel()方法对转盘进行渲染
 preloadimages(turnplate.goodsimgArr).done(function(images){
 drawRouletteWheel();
 });

因为图片加载需要时间,而使用canvas复制图片需要图片加载完成后才能绘制,所以我使用了preloadimages,让所有奖品图片都加载完毕后进行大转盘的渲染工作:

//对奖品图片预加载
 function preloadimages(arr){
 var newimages =[], loadedimages =0
 var postaction =function(){}//此处增加了一个postaction函数
 var arr =(typeof arr !="object")"htmlcode">
function drawRouletteWheel(){
 var canvas = document.getElementById("wheelcanvas");
 if(canvas.getContext){
 //根据奖品个数计算圆周角度
 var arc =Math.PI /(turnplate.restaraunts.length /2);
 var ctx = canvas.getContext("2d");
 //在给定矩形内清空一个矩形
 ctx.clearRect(0,0,422,422);
 //strokeStyle 属性设置或返回用于笔触的颜色、渐变或模式
 ctx.strokeStyle ="rgba(0,0,0,0)";
 //font 属性设置或返回画布上文本内容的当前字体属性
 ctx.font ='bold 18px 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(212,212, turnplate.outsideRadius, angle, angle + arc,false);
 //绘制小圆
 ctx.arc(212,212, turnplate.insideRadius, angle + arc, angle,true);
 ctx.stroke();
 ctx.fill();
 //锁画布(为了保存之前的画布状态)
 ctx.save();
 //----绘制奖品开始----
 //奖品默认字体颜色
 ctx.fillStyle ="#fff";
 var text = turnplate.restaraunts[i];
 var lukyname = turnplate.lucky[i];
 var line_height =17;
 //translate方法重新映射画布上的 (0,0) 位置
 ctx.translate(212+Math.cos(angle + arc /2)* turnplate.textRadius,212+Math.sin(angle + arc /2)* turnplate.textRadius);
 //rotate方法旋转当前的绘图
 ctx.rotate(angle + arc /2+Math.PI /2);
 //绘制奖品图片
 var img =newImage();
 img.src = turnplate.goodsimgArr[i];
 ctx.drawImage(img,-17,35);
 //由于设计的转盘色块是交错的,所以这样可以实现相邻奖品区域字体颜色不同
 if(i %2==0){
 ctx.fillStyle ="#f7452f";
 }
 //将字体绘制在对应坐标
 ctx.fillText(text,-ctx.measureText(text).width /2,0);
 //设置字体
 ctx.font =' 14px Microsoft YaHei';
 //绘制奖品名称
 if(text !="优胜奖"){
 ctx.fillText(lukyname,-ctx.measureText(lukyname).width /2,25);
 }else{
 ctx.fillText("优麦币",-ctx.measureText("优麦币").width /2,25);
 }
 //把当前画布返回(插入)到上一个save()状态之前
 ctx.restore();
 ctx.save();
 //----绘制奖品结束----
 }
 }
 }

每一步基本上都有注释,对于canvas方法有不理解的可以百度,或者查询我上面分享的中文手册。
html代码为:

<divclass="lunck_draw_wrap">
 <divclass="turnplate"style=" background-size:100%100%;">
 <canvasclass="item"id="wheelcanvas"width="422px"height="422px"></canvas>
 <imgclass="pointer"style="top:0px; left:0px; width:100%; height:100%;"src="/UploadFiles/2021-04-02/chouzhang12.png">

效果图:

javascript+HTML5 Canvas绘制转盘抽奖

点击事件执行代码:

$('.lunck_draw_wrap').delegate("img.pointer","click",function(){
 if(turnplate.bRotate)return;
 turnplate.bRotate =!turnplate.bRotate;
 $.getJSON("../AJAX/lottery.ashx","",function(data){
 //1090系统配置错误,1091用户未登陆或用户数据异常,1092用户剩余积分不足,1093未中奖
 hideInput("code",data.code)
 if(data.code.toString()=="1090"){
 iosalert("系统配置错误")
 }elseif(data.code.toString()=="1091"){
 iosalert("用户未登陆或用户数据异常")
 }elseif(data.code.toString()=="1092"){
 iosalert("用户剩余积分不足")
 }elseif(data.code.toString()=="1094"){
 iosalert("超过每日抽奖次数")
 }
 else{
 var upoint =0;
 upoint = parseInt($("#uPoint").html())- parseInt($("#sPoint").html());
 $("#uPoint").html(upoint);
 if(data.isWin =='true'){
 item = getArrayIndex(turnplate.restaraunts, data.name);
 rotateFn(item +1,"恭喜获得,"+ turnplate.restaraunts[item]);
 }
 else{
 rotateFn(0,"恭喜获得优胜奖!");
 }
 }
 })
 });

上面的代码实现了基本上的逻辑,还需要一个转动转盘的方法来响应服务端传过来的结果:

//旋转转盘 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,
 //转动角度 +1800是为了多转几圈
 animateTo: angles +1800,
 duration:8000,
 callback:function(){
 iosSuccess(txt);
 turnplate.bRotate =!turnplate.bRotate;
 if($("#code").val()!="1093"){
 delayLoad(getHttpPrefix +"graphicdetails.html"+ $("#code").val())
 }
 }
 });
 };

好了 主要的功能代码都已分享完毕了,还有些工具方法不理解的,可以留言 我会补充进去的。

总结

canvas是html5很强大的一张王牌,可以实现许多绚丽的效果,希望本文可以帮到一些正在学习使用canvas的朋友们。

广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!

RTX 5090要首发 性能要翻倍!三星展示GDDR7显存

三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。

首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。

据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。