我画了一个自欺欺人的幸运抽奖
幸运抽奖
序
总所周知,抽奖是不可能抽中的🌋,只有攒攒矿石安慰一下自己。
目前在掘金已经攒了三万多矿,到下个月一号开抽,希望各路欧皇运气转来给我。
当然为了提前安抚自己的有效心灵,我用canvas制作了一个“幸运”抽奖的转盘,给自己一波预知未来的鼓励 👍,虽然switch奖励很不错,不过我要乐高就够了
下面是制作好的成品效果:
这是在canvas画布上的,有别于juejin的元素Flex布局(自己最近在对canvas温故而知新):
制作过程
圆角矩形
首先分析一下抽奖界面中存在最多的图形元素,会发现是圆角的矩形,不管是抽奖转盘的背景还是内部奖品存放的九宫格都是圆角的矩形。
如果一个个进行编写就会很冗余,所以可以封装一个编写圆角矩形的方法。
可以先定义一个坐标轴的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
绘制圆点的方法
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来分时循环, 可能写的代码有精简的地方,不过写的有些快了。
做到以上这些地方,一款canvas的幸运抽奖就可以逐步的出现了。(虽然调整各种颜色和位置也是花了一部分时间,毕竟要做的像还是有点麻烦的)
主体代码仓库:https://gitee.com/wzckongchengji/node_study/blob/master/pianoDemo/TS/ExImplicit.ts
- 点赞
- 收藏
- 关注作者
评论(0)