canvas只能用id吗 怎么设置只能抽奖一次

canvas 基础系列(三)之实现九宫格抽奖
上一章讲解了如何使用 canvas 实现大转盘抽奖;但有些地方并没有讲清楚,比如上一章实现的大转盘,奖品选项只能填文字,而不能放图片上去。这一次,我们用 canvas 来实现九宫格抽奖(我已沉迷抽奖无法自拔~),顺便将渲染图片功能也给大家过一遍。本章涉及到的知识点,主要有:
context.drawImage() 方法渲染图片
context.isPointInPath() 方法,在画布中制作按钮
setTimeout() 方法,来做逐帧动画
九宫格的绘制算法
扫描二维码预览demo
因为本章代码比较繁杂,我不会全部贴出来;建议进入我的 ,找到 test 文件下的 sudoku文件夹下载,本章讲解的代码都在里面啦。
|--- | --- variable.js
|--- | --- global.js
|--- | --- index.js
|--- index.html
首先,我们需要绘制出一个九宫格,大家都知道九宫格长什么样子哈,简单的排9个方块,不就搞定了么?
不不不,作为一名合格的搬砖工,我们需要严于律己,写代码要抽象,要能重用,要...假如哪天产品大大说,我要12宫格儿的,15的,20的,你咋办,一个个重新算额~所以,我们得做成图1这样的:
敲敲数字,鸟枪变大炮。不管你9宫还是12宫还是自宫,哥都不怕。
以下是我的实现方法,如果大家有更简单的方法,请告诉我,请告诉我,请告诉我,学美术出生的我数学真的很烂~
九宫格的四个顶点
我们将九宫格看做一个完整的矩形,矩形有四个顶点;假设每一行每一列,我们只显示3个小方块(也就是传统的九宫格),那么四个顶点上的小方块序号分别是,0, 2, 4, 6 ;假设每一行每一列,我们显示4个小方块,那么四个顶点上的小方块序号分别是,0, 3, 6, 9;以此类推,每行每列显示5个小方块,就是 0, 4, 8, 12;
每行每列小方块数量
聪明的小伙伴们应该已经发现规律了,在图1中,我们使用的神秘变量 AWARDS_ROW_LEN ,它的作用就是指定九宫格每行每列显示多少个小方块;
接着,我们绘制的原理是:分成四步,从每一个顶点开始绘制小方块,直到碰到下一个顶点为止;
我们会发现,当 AWARDS_ROW_LEN = 3 时,我们从 0 ~ 1,从 2 ~ 3... ,每一次绘制两个小方块;
当 AWARDS_ROW_LEN = 4 时,我们从0 ~ 2,从 3 ~ 5,每一次绘制三个小方块,绘制的步数刚好是 AWARDS_ROW_LEN - 1;如图3:
图3所以我们得出一个变量 AWARDS_TOP_DRAW_LEN,来表示不同情况下,每个顶点绘制的步数;
我们通过 AWARDS_TOP_DRAW_LEN 这个变量,又可以推算出,任何情况下,矩形四个顶点所在的小方块的下标:
你可以列举多种情况,来验证该公式的正确性
LETF_TOP_POINT =
RIGHT_TOP_POINT =
AWARDS_TOP_DRAW_LEN,
RIGHT_BOTTOM_POINT = AWARDS_TOP_DRAW_LEN * 2,
LEFT_BOTTOM_POINT =
AWARDS_TOP_DRAW_LEN * 2 + AWARDS_TOP_DRAW_LEN,
通过四个顶点,绘制九宫格
得到了每个顶点的下标,那就意味着我们知道了一个顶点距离另一个顶点之间,有多少个小方块,那么接下来就非常好办了,
我们可以通过 AWARDS_TOP_DRAW_LEN 乘以4,来获取总的奖品个数,作为循环条件(AWARDS_LEN);
我们可以获取整个矩形的宽度,默认就让它等于 canvas 的宽度(SUDOKU_SIZE);
自定义每个小方块之间的间距(SUDOKU_ITEM_MARGIN);
通过矩形的宽度除以一排绘制的小方块的数量,再减去小方块之间的间距,得到每个小方块的尺寸(SUDOKU_ITEM_SIZE)。
变量有点多·如果你感觉有点懵逼,请仔细查阅源码 variable.js 中的变量,搞懂每个变量的代表的意义。
我们已经拿到所有绘制的条件,接下来只需要写个循环,轻松搞定!
function drawSudoku() {
context.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i & AWARDS_LEN; i ++) {
let max_position = AWARDS_TOP_DRAW_LEN * SUDOKU_ITEM_SIZE + AWARDS_TOP_DRAW_LEN * SUDOKU_ITEM_MARGIN;
if (i &= LETF_TOP_POINT && i & RIGHT_TOP_POINT) {
let row = i,
x = row * SUDOKU_ITEM_SIZE + row * SUDOKU_ITEM_MARGIN,
positions.push({x, y});
drawSudokuItem(
x, y, SUDOKU_ITEM_SIZE, SUDOKU_ITEM_RADIUS,
awards[i], SUDOKU_ITEM_TXT_SIZE, SUDOKU_ITEM_UNACTIVE_TXT_COLOR,
SUDOKU_ITEM_UNACTIVE_COLOR,
SUDOKU_ITEM_SHADOW_COLOR
if (i &= RIGHT_TOP_POINT && i & RIGHT_BOTTOM_POINT) {
if (i &= RIGHT_BOTTOM_POINT && i & LEFT_BOTTOM_POINT) {
if (i &= LEFT_BOTTOM_POINT) {
drawSudokuItem() 函数方法
在绘制九宫格的 drawSudoku() 函数方法中,你会发现,我们每一步绘制,都将当前小方块的坐标推到了一个 positions 的全局变量中;
这个变量会记录所有小方块的坐标,以及他们的下标;
之后我们在绘制轮跳的小方块时,就能够通过 setTimeout() 定时器,规定每隔一段时间,通过下标值 jump_index 取出 positions 变量中的某一组坐标信息,并通过该信息中的坐标绘制一个新的小方块,覆盖到原来的小方块上,结束绘制后,jump_index的值递增;
这便实现了九宫格的轮跳效果。
而绘制这些小方块,我们封装了一个公共的方法:drawSudokuItem();
function drawSudokuItem(x, y, size, radius, text, txtSize, txtColor, bgColor, shadowColor) {
context.save();
context.fillStyle = bgC
context.shadowOffsetX = 0;
context.shadowOffsetY = 4;
context.shadowBlur = 0;
context.shadowColor = shadowC
context.beginPath();
roundedRect(
size, size,
context.fill();
context.restore();
if (text) {
if (text.substr(0, 3) === 'img') {
let textFormat = text.replace('img-', ''),
image = new Image();
image.src = textF
function drawImage() {
context.drawImage(
x + (size * .2 / 2), y + (size * .2 / 2),
size * .8, size * .8
if (!image.complete) {
image.onload = function (e) {
drawImage();
drawImage();
context.save();
context.fillStyle = txtC
context.font = txtS
context.translate(
x + SUDOKU_ITEM_SIZE / 2 - context.measureText(text).width / 2,
y + SUDOKU_ITEM_SIZE / 2 + 6
context.fillText(text, 0, 0);
context.restore();
}该方法是一个公共的绘制小方块的方法,它能在初始化时绘制所有“底层”小方块,在动画轮跳是,绘制那个移动中的小方块。
drawSudokuItem() 实现了哪些功能?
通过 global.js 中的一个 roundedRect() 方法,绘制了一个圆角矩形;(本章暂不讨论圆角矩形的绘制方法,如果你感兴趣,可以查看源码,或者 GG 一下)
我们定义了一个全局变量 awards 数组来存储奖品信息,如果值是普通的字符串,则在小方块的正中绘制该字符串文字,如果值带有前缀 img- 我们就将该字符串中的 url 地址,作为图片的地址,渲染到小方块上。
绘制方块没啥好讲的,如果你不想用 roudedRect() 方法,你可以直接把它替换成 context.rect(),除了不是圆角,效果完全一样。
先清楚一个概念:
所绘制的图像,叫做 源图像 source image;
绘制到的地方叫做 目标canvas destination canvas。
context.drawImage(
HTMLImageElement $image,
int $sourceX, int $sourceY [ , int $sourceW, int $sourceH,
int $destinationX, int $destinationY, int $destinationW, int $destinationH ]
参数有点多哈,但本章用到的也就前五个,其中前三个是必选,后两个是可选参数:
$sourceX / Y
$sourceW / H
? 这个方法有两个坑:
由于图片地址跨域的?问题,在本地跑是会报错的,所以我们必须建立一个本地服务器来做测试;
如果调用该方法时,图片未被加载,则什么错都不报,就是不显示(任性吧?),解决方法,在 image.onload = function(e) {...} 回调中调用 context.drawImage()。
如果你不知道怎么建立本地服务器的话,我...,愤怒的我当场百度了一篇最简单搭建服务器的教程,童叟无欺!
我们来看以下代码:
if (text.substr(0, 3) === 'img') {
let textFormat = text.replace('img-', ''),
image = new Image();
image.src = textF
function drawImage() {
context.drawImage(
x + (size * .2 / 2), y + (size * .2 / 2),
size * .8, size * .8
if (!image.complete) {
image.onload = function (e) {
drawImage();
drawImage();
先检测获取的文本字符串是否含有前缀 img,如果有,便开始绘制图片;
将文本的前缀去除,格式化后保留完整的链接地址;新建一个 image 对象,将该对象的 src 属性赋值;
定义一个 drawImage() 函数方法,在该方法里面,使用 context.drawImage() 方法渲染刚刚定义的 image 对象,并指定相应的图片大小,和尺寸;
通过 image.complete 来判断图片是否已加载完成,如果未加载,则先初始化,在 image.onload = function(e) {...} 的回调中调用 drawImage() 方法;如果已经加载完毕,则直接调用 drawImage() 方法。
以上,图片就这样渲染完成了,渲染普通文本就不用说了哈,就是普通的 context.fillText() 方法。
我们已经将外围的小方块绘制完成了,接下来来制作中间的按钮。
按钮的绘制很简单,大家看看源码, 就能轻松理解;
但是这个按钮在 canvas 中,只不过就是一堆像素组成的色块,它不能像 html 中定义的按钮那样,具有点击,鼠标移动等交互功能;
如果我们想在 canvas 中实现一个按钮,那我们只能规定当我们点击 canvas 画布中的某一个区域时,给予用户反馈;
? 这里引入一个新的方法,context.isPointInPath();人如其名,该方法会判断:当前坐标点,是否在当前路径中,如果在,返回 true,否则返回 false。
context.isPointInPath(int $currentX, int $currentY)两个参数就代表需要进行判断的坐标点。
通过这个方法,我们可以判断:当前用户点击的位置的坐标,是否位于按钮的路径中,如果返回 true,则执行抽奖动画。
? 值得注意的是,判断的路径,必须是当前路径,也就是说,我们在执行判断之前需要重新绘制一遍按钮的路径;源码中的 createButtonPath() 就是为了做这件事情存在的。
我们来做一个简单的小测试,测试效果如图4:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
function windowToCanvas(e) {
var bbox = canvas.getBoundingClientRect(),
x = e.clientX,
y = e.clientY;
x: x - bbox.left,
y: y - bbox.top
context.beginPath();
context.rect(100, 100, 100, 100);
context.stroke();
canvas.addEventListener('click', function (e) {
var loc = windowToCanvas(e);
if (context.isPointInPath(loc.x, loc.y)) {
alert('?')
怎么样?炒鸡简单对吧?在我们这个项目中也是一样的:
我们在绘制按钮的时候,将按钮的坐标信息已经推送到了 button_position 这个变量中;
我们只需要通过这些信息创建一个一样的按钮路径;(只要你不填充路径,路径是不会显示的);
创建的路径成为了 当前路径,我们将点击事件 click 中获取的坐标信息传给 context.isPointInPath() 方法,就可以判断,当前的位置,是否在按钮的路径中。
['mousedown', 'touchstart'].forEach((event) =& {
canvas.addEventListener(event, (e) =& {
let loc = windowToCanvas(e);
createButtonPath();
if (context.isPointInPath(loc.x, loc.y) && !is_animate) {
});我们将通过点击按钮,来调用 animate() 方法,该方法实现了九宫格抽奖的动画效果。
在点击按钮时,我们会初始化三个全局变量,jumping_time, jumping_total_time, jumping_change;
它们分别表示:动画当前时间计时;动画花费的时间总长;动画速率改变的峰值(使用 easeOut 函数方法,单位时间内会将速率由0提升到峰值);
最后我们将调用 animate() 函数方法,以下是该方法的代码:
function animate() {
is_animate = true;
if (jump_index & AWARDS_LEN - 1)
jump_index ++;
else if (jump_index &= AWARDS_LEN -1 ) jump_index = 0;
jumping_time += 100;
if (jumping_time &= jumping_total_time) {
is_animate = false;
if (jump_index != 0)
alert(`?恭喜您中得:${awards[jump_index - 1]}`)
else if (jump_index === 0) alert(`?恭喜您中得:${awards[AWARDS_LEN - 1]}`);
drawSudoku();
drawSudokuItem(
positions[jump_index].x, positions[jump_index].y,
SUDOKU_ITEM_SIZE, SUDOKU_ITEM_RADIUS,
awards[jump_index], SUDOKU_ITEM_TXT_SIZE, SUDOKU_ITEM_ACTIVE_TXT_COLOR,
SUDOKU_ITEM_ACTIVE_COLOR,
SUDOKU_ITEM_SHADOW_COLOR
setTimeout(animate, easeOut(jumping_time, 0, jumping_change, jumping_total_time))
animate() 函数方法:
我们定义了一个全局变量 is_animate,该变量用来阻止用户在动画进行时反复点击按钮,使动画不断被调用;该变量初始值为 false,仅当该变量为 false 时,点击按钮才会进入 animate() 函数;当进入 animate() 函数后,该变量被设置为 true,结束动画时,又被重置为 false;
jump_index 全局变量的初始值是一个小于等于奖品总数的随机正整数;随着每一帧动画的执行递增,但当他等于奖品总数时,又会被重置为 0,以此循环;我们使用该变量,来绘制轮跳的小方块;
jumping_time 全局变量初始值为0,随着每一帧动画的执行递增,以此来记录动画当前时间点,当这个值大于等于时间总量 jumping_total_time 时,就可以结束动画,并将当前的 jump_index 取出,作为抽中的奖品了;
drawSudoku() 方法中第一句代码就是:context.clearRect(0, 0 , canvas.width, canvas.height);它用于清理整个画板,并将九宫格重绘出来;
drawSudokuItem() 我们使用这个函数方法,来绘制轮跳的小方块;前面说过,我们将 jump_index 做为下标,那么我们就可以在 positions 变量中找到坐标信息,从 awards 变量中,找到奖品信息;
最后,我们使用定时器 setTimeout() 方法,来实现小方块的动画;该方法调用 animate() 方法本身,它的第二个参数,我们使用了介绍过的缓动函数来定义,这会使动画看上去由快到慢;缓动函数的源码可以在 global.js 中找到。
O 啦~所有代码讲解完毕,你的九宫格是否也动起来了??
canvas 实现动画的方式不外乎就是清除画板,再重新绘制一个 动作 ,理解了它,无论你是用 window.requestAnimateFrame() 还是 setTimeout() 和 setInterval() 来做动画,都是一样的原理;
九宫格的实现很简单,唯一复杂点的,就需要一系列计算,来绘制一个灵活的九宫格;
九宫格不仅可以用来抽奖,也可以用来做一些小游戏,还记得小时候玩过的老虎机么?如图5:
改改样式,找点图片,把值取出来做下分数规则判断,分分钟搞定呢!
打开新标签页发现好内容,掘金、GitHub、Dribbble、ProductHunt 等站点内容轻松获取。快来安装掘金浏览器插件获取高质量内容吧!分享主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
CSDN &《程序员》研发主编,投稿&纠错等事宜请致邮
你只管努力,剩下的交给时光!
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:www.xttblog.com。个人QQ群:、
个人大数据技术博客:https://www.iteblog.com他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)脚本简介HTML5 Canvas指针大转盘抽奖代码是一款基于canvas实现的转盘及指针,各奖项和分区颜色可随意设置。
特别说明:
本站所有资源仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您自己承担!
各线路极速下载器通过p2p加速功能,帮助用户对于大文件能更好的加速下载。
其他普通下载点限制多线程,仅允许直接点击或另存为下载等单线程下载的软件,较适合小的文件下载!
如有侵犯您的版权,请及时联系#qq.com(#换@),我们将尽快处理。
& CopyRight , , Inc.All Rights Reserved.当前位置: >
HTML5+Canvas指针大转盘抽奖代码
特效说明:
一款HTML5+Canvas指针大转盘抽奖代码下载,该HTML5特效是一款基于canvas实现的转盘及指针,各奖项和分区颜色可随意设置。请用支持HTML5+CSS3主流浏览器预览效果。(兼容测试:IE10、Firefox、Chrome、Opera、Safari、360等支持HTML5+CSS3主流浏览器)
使用方法:
1、调用CSS样式:
&link rel=&stylesheet& type=&text/css& href=&css/main.css&&
2、调用JS插件代码:
&script type=&text/javascript& src=&js/jquery-1.11.3.min.js&&&/script&
&script type=&text/javascript& src=&js/main.js&&
3、添加HTML代码:
将&!--效果html开始--&......&!--效果html结束--&之间的html和js代码;放在&body&&/body&之间。
一款Canvas制作圆形进度条Loading效果,该网页特效基于canvas画布绘制,循环执行的圆形百分比效果 注:不支持低版本浏览器。……
一款HTML5音乐录音播放动画网页特效,该HTML5动画是一款背景音乐符号动画,以及麦克风录音动画实例教程。……
HTML5+svg手机图标菜单动画切换特效下载,该HTML5特效代码是一款适合移动端、手机端展开/收缩导航菜单特效。……
一款HTML5带音乐手机摇一摇抽奖特特效代码下载,APP摇一摇抽奖、微信摇一摇抽奖、移动端网页抽奖活动JS代码素材。……
4款HTML5+CSS3制作input元素滑块特效下载,该HTML5+CSS3特效是一款使用CSS3来渲染UI样式,使用JavaScript来处理滑块的鼠标拖动事件。……
一款HTML5电子杂志(相册)翻书动画特效下载,该图文相册特效是一款基于HTML5+Canvas实现的鼠标点击拖动翻页图片特效代码。……
赣极方旗,有多种棋子模式;可以是象棋棋子模式,军旗棋子模式,动物棋子模式,自定义棋子模式;棋子分7个级别,级别最高棋子实力最大,最小实力棋子可以克制最大实力棋子;赣极方旗……
一款HTML5触屏滑动侧边栏导航菜单特效下载,该Bootstrap导航菜单特效是一款基于jquery+html5实现的兼容手机和PC端动画导航菜单插件,响应式网站建设必备代码素材。……
本文作者王安,DCloud 公司 CEO,W3C 会员、HTML5 中国产业联盟发起人,HTML5 开发工具 HBuilder 设计师,十几年 web 和手机开发经验。 我们第一次谈论 HTML5 要改变世界大概是因为乔布斯,他坚持在……
4款响应式全屏动画背景插件网页特效免费下载,该JS特效代码采用Canvas+JavaScript制作自适应头部全屏背景、动态元素修饰元素使得页面更加生动、活泼、增强用户体验。……
最新更新特效
本站关键词
科e互联版权所有
京ICP备号-1

我要回帖

更多关于 canvas设置字体颜色 的文章

 

随机推荐