我画了一个自欺欺人的幸运抽奖

举报
空城机 发表于 2021/09/22 15:37:50 2021/09/22
【摘要】 Canvas制作的幸运抽奖,绝不落空,每次必中

幸运抽奖

总所周知,抽奖是不可能抽中的🌋,只有攒攒矿石安慰一下自己。

目前在掘金已经攒了三万多矿,到下个月一号开抽,希望各路欧皇运气转来给我。

当然为了提前安抚自己的有效心灵,我用canvas制作了一个“幸运”抽奖的转盘,给自己一波预知未来的鼓励 👍,虽然switch奖励很不错,不过我要乐高就够了

下面是制作好的成品效果:

这是在canvas画布上的,有别于juejin的元素Flex布局(自己最近在对canvas温故而知新):
image.png




制作过程

圆角矩形

首先分析一下抽奖界面中存在最多的图形元素,会发现是圆角的矩形,不管是抽奖转盘的背景还是内部奖品存放的九宫格都是圆角的矩形。

lALPD2sQwfGH8E7NAa3NAiA_544_429.png

如果一个个进行编写就会很冗余,所以可以封装一个编写圆角矩形的方法。

可以先定义一个坐标轴的xy类型:

type xy = {
    x: number,
    y: number
}

封装方法时需要考虑圆角矩形需要的参数:

参数名 作用
startPos 起点位置
width 矩形宽度
height 矩形高度
border 圆角弧度
color 颜色(不是必选项,不过如果不传,会默认使用黑色填充)

在方法内可以使用beginPath(),save(),restore()等方法来使得绘制圆角矩形后不影响之后的绘制

// 绘制圆角矩形的方法  参数:startPos 起点位置, width 矩形宽度  height 矩形高度  border 圆角弧度  color 颜色 
function drawCRect(startPos: xy, width:number, height:number, border: number, color?: string) {
    ctx.beginPath();
    ctx.save();
    
    if (color) {
        ctx.strokeStyle = color;
        ctx.fillStyle = color;
    }
    ctx.moveTo(startPos.x + border, startPos.y);
    ctx.lineTo(startPos.x + width - border, startPos.y);
    ctx.arcTo(startPos.x + width, startPos.y, startPos.x + width, startPos.y + border, border);
    ctx.lineTo(startPos.x + width, startPos.y + height - border);
    ctx.arcTo(startPos.x + width, startPos.y + height, startPos.x + width - border, startPos.y + height, border);
    ctx.lineTo(startPos.x + border, startPos.y + height);
    ctx.arcTo(startPos.x, startPos.y + height, startPos.x, startPos.y - border, border);
    ctx.lineTo(startPos.x, startPos.y + border);
    ctx.arcTo(startPos.x, startPos.y, startPos.x + border, startPos.y, border);
    ctx.fill();
    ctx.stroke();
    ctx.restore();
}

圆点

之后有了圆角矩形后,会发现在界面上有环绕的小圆点,这些圆点有各自的样式。不过总体的大小是不变的,所以我创造了一个Circular类,在类中编写一个drawCir绘制圆点的方法

image.png

drawCir方法 (这个类写的有点早了,其实left和top可以使用之后的xy来代替的)

参数名 作用
left 初始左边距
top 初始顶边距
fillFlag 是否填充内部颜色
color 颜色
// 绘制圆角矩形的方法  参数:startPos 起点位置, width 矩形宽度  height 矩形高度  border 圆角弧度  color 颜色 
function drawCRect(startPos: xy, width:number, height:number, border: number, color?: string) {
    ctx.beginPath();
    ctx.save();
    if (color) {
        ctx.strokeStyle = color;
        ctx.fillStyle = color;
    }
    ctx.moveTo(startPos.x + border, startPos.y);
    ctx.lineTo(startPos.x + width - border, startPos.y);
    ctx.arcTo(startPos.x + width, startPos.y, startPos.x + width, startPos.y + border, border);
    ctx.lineTo(startPos.x + width, startPos.y + height - border);
    ctx.arcTo(startPos.x + width, startPos.y + height, startPos.x + width - border, startPos.y + height, border);
    ctx.lineTo(startPos.x + border, startPos.y + height);
    ctx.arcTo(startPos.x, startPos.y + height, startPos.x, startPos.y - border, border);
    ctx.lineTo(startPos.x, startPos.y + border);
    ctx.arcTo(startPos.x, startPos.y, startPos.x + border, startPos.y, border);
    ctx.fill();
    ctx.stroke();
    ctx.restore();
}

九宫格奖励

为了中间的奖励,我也专门创建了一个Reward

在这个类中,会绘制每一格的奖励,其中比较重要的一点就是将图片绘制到各自当中。

这里会使用drawImage方法,这是向画布上面绘制图片的方法。

// 不同的奖励
class Reward {
    left:number = 128;
    top:number = 98;
    content: string = '';
    bgColor:string = '#FDF3F3';
    constructor() {}
    drawReward(content:string, left: number, top: number, bgColor:string = '#fdf3f3') {
        ctx.beginPath();
        this.left = left;
        this.top = top;
        this.content = content;
        this.bgColor = bgColor;
        // console.log(reImg[0]);
        drawCRect({ x: left, y: top }, 128, 98, 4, bgColor);
        ctx.drawImage(reImg[0], left + 44, top + 20, 40, 40);

        ctx.fillStyle = "#d25f00"
        ctx.font = "14px Microsoft YaHei";
        ctx.fillText(content, left + 24, top + 80);
    }
}

为了之后的抽奖旋转起来,我会将奖励生成的实例存放到统一的数组当中去,这样方便之后的奖励选中后颜色改变的重绘

let rewardArr:Reward[] = [];
let pos:xy[] = [
    { x: 40, y:40 },
    { x: 179, y: 40 },
    { x: 318, y: 40 },
    { x: 318, y: 148 },
    { x: 318, y: 256 },
    { x: 179, y: 256 },
    { x: 40, y: 256 },
    { x: 40, y: 148 },
];
// 绘制八个奖励
function setReward() {
    for(let i = 0; i < 8; i++) {
        let rewardCon = new Reward();
        rewardCon.drawReward('乐高海洋巨轮', pos[i].x, pos[i].y);
        rewardArr.push(rewardCon);
    }
}

抽奖点击

抽奖点击功能使用setInterval来分时循环, 可能写的代码有精简的地方,不过写的有些快了。

image.png

做到以上这些地方,一款canvas的幸运抽奖就可以逐步的出现了。(虽然调整各种颜色和位置也是花了一部分时间,毕竟要做的像还是有点麻烦的)

主体代码仓库:https://gitee.com/wzckongchengji/node_study/blob/master/pianoDemo/TS/ExImplicit.ts

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。