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

658 阅读3分钟

这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战

幸运抽奖

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

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

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

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

80901.gif

这是在canvas画布上的,有别于juejin的元素Flex布局(自己最近在对canvas温故而知新): 1630333360720_D0C2DCC6-89B0-473c-B762-52CB8ECFC94E.png




制作过程

圆角矩形

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

image.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颜色

image.png

九宫格奖励

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

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

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

image.png

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

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的幸运抽奖就可以逐步的出现了。(虽然调整各种颜色和位置也是花了一部分时间,毕竟要做的像还是有点麻烦的)

主体代码仓库:gitee.com/wzckongchen…