canvas画抽奖转盘
HTML部分
<div class="round"> <div class="wheel_bg"> <div class="bg"> <img v-show="bg" class="bg1" src="@/assets/image/bg1.png" alt /> <img v-show="!bg" class="bg2" src="@/assets/image/bg2.png" alt /> </div> <canvas id="wheelCanvas" width="400px" height="400px" class="lottery_bg" :style="`transform: rotate(${wheelDeg}deg)`" ></canvas> <img @click="lottery" class="center" src="@/assets/image/center.png" alt /> </div> </div>
JS部分
getLottery() { this.list = []; let tag = JSON.parse(localStorage.getItem("country_i") || 1); draw_get_list(res => { console.log(res); if (res.code == 0) { this.num_rule.rule = tag == 1 ? res.data.list.data.en_rule : res.data.list.data.sa_rule; if (res.data.list.list) { res.data.list.list.forEach(ite => { let list = { id: ite.id, name: "", ratio: ite.ratio, img: { resource_url: ite.image, horizontal_resolution: 300, //水平分辨率 vertical_resolution: 300 //垂直分辨率 }, lucky_image: ite.lucky_image }; this.list.push(list); }); } // 循环一下,将图片渲染到页面上 this.list.forEach(function(item) { if (item.img) { var img = new Image(); img.src = item.img.resource_url; // console.log(img); item.imgEl = img; } }); } else { Toast({ message: res.msg, time: 2000, i: 1 }); } console.log(this.list); // 请求会数据后,就可以开始将奖品之类的,画到转盘上了 this.draw(); }); }, checkImgComplete() { let complete = true; this.list.forEach(function(item) { if (item.imgEl && !item.imgEl.complete) { complete = false; } }); return complete; }, draw() { const _this = this; // 先判断,图片是否加载完成 if (!_this.checkImgComplete()) { setTimeout(function() { _this.draw(); }, 50); return; } //获取canvas画布 // this.list 是通过后台获取回来的奖品列表 let len = this.list.length; let canvas = document.getElementById("wheelCanvas"); let ctx = canvas.getContext("2d"); let canvasW = canvas.width; // 画板的高度 let canvasH = canvas.height; // 画板的宽度 //计算每个奖项所占角度数 let baseAngle = (Math.PI * 2) / len; // ctx.clearRect(0, 0, canvasW, canvasH); //去掉背景默认的黑色 ctx.strokeStyle = "#FEA801"; //设置画图线的颜色 console.log(ctx); // 开始循环绘制每个奖品 for (let i = 0; i < len; i++) { // 每个扇形的起始角度 let angle = i * baseAngle; ctx.font = "16px Microsoft YaHei"; //设置字号字体 let bgc = i % 2 === 0 ? "#FEA801" : "#FBDF74"; //设置每个扇形区域的颜色 let bgc1 = i % 2 === 0 ? "#FBDF74" : "#FEA801"; console.log(canvasW, canvasH); let grd = ctx.createRadialGradient( canvasW * 0.5, canvasW * 0.5, 100, canvasW * 0.5, canvasW * 0.5, 200 ); grd.addColorStop(0.83, bgc); grd.addColorStop(0.84, bgc1); grd.addColorStop(0.97, bgc1); grd.addColorStop(1, "#F2BB41"); ctx.fillStyle = grd; ctx.beginPath(); //开始绘制 ctx.arc( canvasW * 0.5, canvasH * 0.5, 200, angle, angle + baseAngle, false ); // 中心点的小圆,这样会形成一个环形图案 ctx.arc( canvasW * 0.5, canvasH * 0.5, 10, angle + baseAngle, angle, true ); ctx.stroke(); //开始链线 ctx.fill(); //填充颜色 ctx.save(); //保存当前环境的状态 ctx.fillStyle = "#017ec2"; // 设置文字颜色 let item = this.list[i]; // 计算文字的偏移量 let translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * 260; let translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * 260; // 如果奖品无图,则文字相应改大,并且偏移变小 if (!item.img) { ctx.font = "20px Microsoft YaHei"; //设置字号字体 translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * 220; translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * 220; } ctx.translate(translateX, translateY); // rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的! // angle,当前扇形自身旋转的角度 + baseAngle / 2 中心线多旋转的角度 + 垂直的角度90° ctx.rotate(angle + baseAngle / 2 + Math.PI / 2); //设置文本位置,居中显示 ctx.fillText(item.name, -ctx.measureText(item.name).width / 2, 100); //添加对应缩略图 let triangleEdge = canvasH * 0.25; // 根据角度不同,计算图片最大宽度 let imgMaxWidth = Math.sqrt( 2 * triangleEdge * triangleEdge * (1 - Math.cos(baseAngle)) ); if (item.imgEl) { ctx.drawImage( item.imgEl, -imgMaxWidth * 0.5, canvasH * 0.23, imgMaxWidth, (item.img.vertical_resolution * imgMaxWidth) / item.img.horizontal_resolution ); } ctx.restore(); //很关键,还原画板的状态到上一个save()状态之前 } }, lottery() { if (this.showResult) { this.showResult = false; this.$router.go(-1); return; } if (this.rolling) { return; } if (!this.$store.state.status.token) this.$router.push({ path: "/account/login" }); let data = this.$store.state.status.token ? this.$store.state.status.token : ""; lucky_draw({ token: data }, res => { console.log(res); if (res.code == 0) { this.lucky_d(res.data.id); } }); }, lucky_d(id) { if (this.num_rule.num > 0) { this.num_rule.num--; } this.rolling = true; // 这里应该从后台获取中奖结果,我们随便模拟一下中奖结果 let winIndex = 0; this.list.some((item, i) => { if (item.id == id) { this.result = item; winIndex = i; return true; } }); console.log(winIndex, this.result); let prize_angle = 360 - (360 / this.list.length) * winIndex; //转动到每个奖项的偏移的角度 let area_angle = 180 - 360 / this.list.length; //初始指针角度 console.log(prize_angle, area_angle, this.wheelDeg, this.wheelDeg % 360); // 计算中奖的旋转角度 this.wheelDeg = this.wheelDeg - (this.wheelDeg % 360) + 3600 + prize_angle - area_angle; console.log(this.wheelDeg); // 关闭中奖结果 setTimeout(() => { this.showResult = true; this.rolling = false; window.history.pushState(null, null, "#"); }, 5500); },
CSS部分
.round { width: 100vw; position: relative; .wheel_bg { margin: 0 0.35rem; position: absolute; top: 0rem; left: 0%; width: calc(100vw - 0.7rem); height: calc(100vw - 0.7rem); background-color: #fbdf74; border-radius: 50%; overflow: hidden; transition: transform 8s ease-in-out; z-index: 1; border: 2px solid #ffeea5; box-sizing: border-box; } .lottery_bg { position: absolute; top: 0.4rem; left: 0.4rem; width: calc(100% - 0.8rem); height: calc(100% - 0.8rem); background-color: #fea801; border-radius: 50%; overflow: hidden; transition: transform 5s ease-in-out; z-index: 2; } .center { position: absolute; top: 51%; left: 50%; width: 1.4rem; transform: translate(-50%, -50%); margin-top: -0.2rem; z-index: 4; } .bg { position: absolute; top: 0rem; left: 0rem; width: 100%; height: 100%; z-index: 3; .bg1, .bg2 { width: 100%; height: 100%; } } }
浙公网安备 33010602011771号