canvas实现转盘抽奖

用canvas写了一个简单的转盘抽奖插件,

给大家参考下下。。。


做的时候的想法是,通过传进来的标签以及属性,直接可以new出一个转盘

如:var a = new createRound(obj,{...}) ;

因为是用canvas来写,所以肯定会用到角度,弧度了什么的,所以做好准备工作:

1,角度转弧度 

说明:因为2π弧度等于360度,所以通过这个封装成以下函数

function d2a(n){

       return n * Math.PI / 180;

};


2,n - m 区间获取随机数,一会后面会用到

function rnd(n,m){

      return parseInt(Math.random()*(m-n))+n;

};


3,因为要重复使用,所以想着用面向对象,现在编辑构造函数。根据我们开始定义的使用方法来传值:

说明:

传进obj后,我们在obj里面添加创建一个canvas,并且给他赋值宽高,(canvas宽度以及高度,必须用属性来写,写在样式里会进行拉伸哦),所以我直接写的是 this.oC.width = this.config.width ; 来定义属性值;

this.init() 里面放的时直接调用的一些函数,之所以都放到this.config 的 json 里,是因为这样更灵活,不用担心顺序而出现错误,里面有一些在绘制时需要用到的值 和一些默认值 ;


4,this.init() 里的内容

说明:因为如果没有抽奖信息的话,转盘是不成立的,所以做了初始判断,this.config.data ,如果没有数据就 return 出去;


5,画弧,也可以说是画圆

说明:

this.gd.save() : 保存画布坐标系统的状态

this.gd.beginPath() : 重新画(清除之前的路径)

this.gd.closePath() : 闭合路径(自动连接到起始点)

this.gd.restore() : 恢复save之后设置的状态

可以简单理解为调用restore之后,restore方法前调用的rotate/translate/scale方法全部就还原了,画布的坐标系统恢复到save方法之前,但是这里要注意的是,restore方法的调用只影响restore之后绘制的内容,对restore之前已经绘制到屏幕上的图形不会产生任何影响。(这段话是从网上找的,我自己总结不了这么清楚。。。) ;

接下来要开始绘制圆了

this.gd.moveTo( 起点x , 起点y ) ; 通过这连接其他地方

this.gd.arc(圆心x,圆心y,半径,起始角度,结束角度)  ,因为里面需要 的是弧度,所以我们刚才封装的d2a(n) 用到了。

this.gd.fillStyle = 填充颜色;

如上图所示,我们将它封装好,因为一会转盘内部分块的时候还需要用到;


我们要根据传进来的 data 来确定分成多少块,所以在上面 第 4 步的时候,我们把数据传进去调用,

c 是数据 传进来的颜色 。

a 是起始角度,从 0度 开始 减去偏移量,因为画弧度是默认开始角度 是90度(如图1所示),所以需要减90(得到图2) 想让第一块内容在中心位置(如图3),所以需要减去当前块的一半角度 360 / arr.length / 2,找了个变量将要减的值存储下来 this.config.pyl 。

b 是结束角度,值是(i + 1),也同样需要减去偏移量。

数据下新增 start 和 end 将起始角度和结束角度存储下来 ,  因为这个需要填写的是正确的角度 ,所以需要将刚才减去的 90度 加上,后面的 90/arr.length 是在随机区域内的角度的时候 ,不到于太靠边上。

调用刚才封装好的 drow 函数,并将值 传进去 循环创建多块内容


图1
图2 
图3


6,绘制指针

说明:画箭头,用数组存储位置,这个箭头稍微有点长,不过如果圆盘小的时候可以根据需要进行适当调整

this.gd.moveTo() : 起始位置定义为中心靠左 5 像素 ;

循环数组 连接 里点的点 ,接着做了一个阴影的处理,设置了箭头的颜色 ;

找了半天没有找到怎么移动自己划出来的图形的方法,因为图形是由点连成线绘制,所以也没法使用 translate 或者 rotate ,所以将它转换成图片,然后对图片进行操作,当图片加载完成后,调用 _this.clearOther(0) 函数,下面会对该函数说明。


7,为指针转动做准备工作

说明:当指针旋转的时候必须清空画布,要不然会连续绘制,达不到我们想要的效果,所以里面的好多内容需要重新绘制,上面对代码有备注,大家可以看一下

旋转箭头时,rotate,默认以画布左上角为支点,箭头生成的图片与画布大小一样,我们要以画布的中心对箭头进行旋转,所以我们需要先将箭头 移到 中心位置,translate 后,与刚才不同的是 支点 移动到中心位置,但是整体位置已经偏移,所以在 rotate 后 我们需要将 图片自身 的位置 定义为 负值,让图片回到自己最初的位置


8,指针转动到指定位置

说明:因为一张图无法截取完整代码,所以分两张图。

因为是当用户触发时开启定时器,所以为了防止用户在连续开启定时器,所以,首先定义一个开关,当用户点击时 判断 是否在进行,如果在 进行,就 return 出来,如果没有进行,定义值,现在开始进行,当运动结束后,改变值,记录运动已经结束。

因为当将方法是在用户触发时调用,所以当用户调用时需要将中奖id传参进去,循环数据,将每个数据索引存储起来,进行判断,如果当前索引下数据的 id 等于 传参进来的 id 则将该中奖索引记录下来,然后获取到数据该索引下的内容,将之前存储的 起始角度(start)和 结束角度 (end ) 取出来,通过随机数,找到其区域内的角度 为 目标角度(t)。

n 为当前进行的角度 ,默认快速旋转3圈后,开始慢慢减速,所以当 n > 360*3 ( 3 圈分界线 ) 的角度后,开始慢慢减速,(可能大家有疑问,为什么要给 t 加上 360 ,是因为如果 t 等于 10度 或者特别小的度数的时候,由慢变慢的过程不明显,所以又加了360,让它有个慢慢减速的过程)。当进行的角度 减去 分割线后 大于 等于 目标角度(t)后,证明已经到达角度终点,停止定时器,将进行角度 归 0。


用户点击时调用该方法


9,绘制奖品信息,展示数据提供的文字信息,进行封装

this.gd.textBaseline = ' top ' ;  字体位置,如下图所示:

this.gd.textAlign = ' center ' ;   如下图所示:

this.gd.translate(this.config.cx,this.config.cy); 将字体默认定义在画布中心,本来的算用 rotate 来处理文字的角度,但是用了之后,文字位置角度是正确了,可是文字本身角度也进行了调整,所以没办法,只好通过文字自身的 x , y 来调整所处的正确位置。

var x = Math.sin(d2a(i*360/l)) * (this.config.r - 50);   因为角度和斜线的位置我们是已知的(因为我们定义所有文字据中心的位置都是相等的 相当于半径 ,所以我们知道斜线位置,角度就是 360 除以 份数后 乘以 i 得出来的值),然后通过下图公式去求出 x 值,y 值也是同样方法。(学好数理化,走遍天下都不怕,骄傲脸 ^_^ )

this.gd.fillText(str,x,-y); 将设置好的值传进去,就可以定义好文字的位置了,因为 y 值 的 0 位置在画布中心,所以当位置在上面时自然就成了负值 (大家不要用 x轴y轴的想法去想哦)。


10,循环数据,给数据中的不同文字定义不同位置

说明:循环数据,使用之前封装好的方法将数据下的每一份的文字定义位置。


11,封装成功,开始调用

说明:这个是自己弄的假数据 ,大家可根据后台提供的不同数据来对代码进行,适当的调整


写到这,转盘抽奖就差不多完了,第一次总结自己写的小demo,有不对的地方欢迎大家多多指教,在写的时候 是按照 自己封装好后的代码顺序 一块一块进行的,大家看着可能有些乱,可以去 github 上下载代码进行参考,看起来会更直观一点。

地址:https://github.com/juanjuanGit/rotary-draw.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容