canvas画环形图,canvas实现动画效果

  canvas画环形图,canvas实现动画效果

  最近笔者有个需求。需求的内容是:圆环周围显示一组字符,用户可以添加字符。字符环绕着圆环,每个单词对应着圆环周围的一个小蓝点。当用户将鼠标放在圆环上方的小蓝点上时,三角形会放射出来,然后显示字符。先来看看动画效果吧!

  如上图所示,当鼠标放在相应的蓝点上时,需要发出类似三角形的光线,在三角形的外侧显示相应的文字,小蓝点变成白点。

  当用户在顶部输入内容时,在底部的圆圈周围添加内容。如上图。

  本来作者最初的想法是用css来实现,就像下图的动态二级菜单。

  但是,考虑到环边的内容是可变的,并且需要定位在环的周围,css可能很难实现。所以,我决定用画布来实现。(作者最近刚学画布。如有不妥之处,请接受指正)。

  实现过程:

  首先:

  html代码的一部分如下:

  canvas style= margin-left:50px;padding-top:20px;显示:阻止;Id=canvas 当前版本的浏览器不支持canvas/canvas。具体实施步骤如下:

  1.画一个大圈。

  使用canvas方法:context.arc (x,y,radius,startangle,endpoint [,逆时针]);

  x,y:圆心坐标,radius:圆心半径,startAngle:画起始圆弧,endAngle:画终止圆弧,[,逆时针]:可选参数,是顺时针画圆弧还是逆时针画圆弧。

  为了绘图方便,作者把画布的原点从左上角移到了画布的中心。

  作者计算的圆的半径是r-80。

  canvas . width=500 canvas . height=500//计算画布中心半径let r=500/2//界面初始化时,将画布原点移动到画布中心ctx.translate(r,r) //将画笔移动到圆上。具体代码如下:

  //画布初始化let canvas=document . getelementbyid( canvas )let CTX=canvas . get context( 2D )let ratio=getPixelrato(CTX)canvas . width=500 canvas . height=500//计算画布中心半径let r=500/2//界面初始化时将画布原点移动到画布中心ctx.translate(r,r) //将画笔移动到圆形CTX . line width=3;//设置画笔的线宽CTX . begin path();//画笔开始//绘制环形边缘的渐变边缘颜色var arccolor=CTX。创建线性渐变(-170,-170,0,170) arccolor。AddColorstop (0, # 8ec1ff) arccolor。AddColorstop (0.2, 83 beff )arc color . AddColorstop(0.5, 75 B1 ff )arc color . AddColorstop(0.7, 5998 ff )arc color . AddColorstop(1, 2065 ff )CTX . stroke style=arc color;//设置画笔颜色ctx.arc (0,0,r-80,0,2 * math.pi,false)//画一个圆,坐标为0,0,半径为250-80,整圆(0-360度),false表示顺时针ctx.closepath () ctx.stroke。

  2.在圆圈中间绘制背景图片(当前画布原点是画布中心)

  Drawimage (image,dx,dy,dwidth,dheight)图像:画布图像资源,如img图像、SVG图像、画布元素本身等。

  Dx,dy:在画布上规划一个放置图片的区域。dx是这个区域左上角的横坐标和纵坐标。

  Width,dHeight:在画布上规划一个放置图片的区域,这个区域的宽度和高度。

  以下坐标是作者计算的。

  let=new image()image . src= image/quan . png image . onload=()={//原点移至中心CTX.drawimage (image,-140,-140,280,280)}绘制结果如下:

  3.在圆上画出单词和圆点(当前画布原点是画布中心)

  文本和点绘制目标:

  3.1小圆点均匀地显示在大圆上。

  3.2文字散在圆点外一点。

  解决思路:

  1.我使用一个数组来存储当前单词。

  TextArr=[海阔天空,技术能力,资金雄厚,维护控制,安居乐业,看花,点睛之笔,逆风而行]2 .因为点数和字数是一样的,它们

  3.一整圆的弧度是2。为了将圆点等分成圆圈,作者首先计算每个圆点的弧度。

  for(设I=0;ilengthsI ){ //计算弧度设rad=2 *数学。/长度*i}4。根据三角函数,可以计算出当前点在画布上的坐标(x,y)(当前画布的原点是画布的中心)。

  其中,弧度、圆点、圆、圆半径、画布原点关系,作者都画了图来描述它们。

  计算的文本坐标:

  //计算小圆圆心的坐标let x=(r-40)* math . cos(rad)let y=(r-40)* math . sin(rad)计算小圆的坐标:因为小圆的圆心会落在圆环上,所以它的横坐标和纵坐标是,

  //计算单词的坐标let x=(r-80)* math . cos(rad)let y=(r-80)* math . sin(rad)具体代码如下:

  //绘制文本CTX . font= 13px Arial CTX . textalign= center CTX . text baseline= middle CTX . fill style= # 000000 let lengths=textarr . length textarr . foreach(function(text,I){ //radian let rad=2*Math。PI/lengths*i //计算小中心的坐标let x=(r-40)* math . cos(rad)let y=(r-40)* math . sin(rad)CTX . fill text(text,x 0.5)//为(let I=0;ilengthsI){///让rad=2 * math.pi/lengths *我让x=(r-80) * math.cos (rad)让y=(r-80)* Math . sin(rad)///画一个灰色半透明的小点CTX . begin path(CTX . fill style= rgba(226,235,250,0.8) ctx.arc(x,y,8,0,2*Math。PI,False) ctx.closepath()CTX . fill()//画一个小蓝点CTX . begin path()CTX . fill style= # 208 Fe 5 CTX . arc(x,y,4,0,2 * math.pi,False)CTX . close path()

  4.在每个点的外面画一个三角形(当前画布原点是画布中心)

  4.1因为要画三角形的形状,画三角形的思路是以当前点的中心为起点在两边画一条线,然后用ctx.fill()封闭图形,用渐变填充里面。

  画一个三角形:坐标自己算。作者在横坐标上加减35,纵坐标上加减70(随便你,哈哈哈)

  //Brush starts CTX . begin path()CTX . move to(x,y) ctx.lineto (x-35,y 70) ctx.lineto (x 35,y 70) ctx.closepath()绘制三角形下方的文本:(我在这里为我的文本使用了红色以区别于之前的文本)

  CTX . fill style= # e 3211 c CTX . fill text(textarr[I],x,y75)具体代码如下:

  for(设I=0;ilengthsI){///设rad=2 * math.pi/lengths * I设x=(r-80) * math.cos (rad)设y=(r-80)* math . sin(rad)///画一个S三角形///ctx。Ctx.beginPath() //画笔开始Ctx。搬到(x,y) CTX。莱恩托(x-35,y 70) CTX。LINETO (x 35,Y 70)CTX . close path()/////设置颜色渐变-从中心向两边添加颜色var color=CTX . createlanegradient(x,Y,x18,y50) color。Addcolorstop (0, rgba (106,128,243,0.5)) sColor.addColorStop(0.6, rgba(83,183,243,0.5)) sColor.addColorStop(0.7, rgba(129,200,224,0.5)) sColor.addColorStop(0.8, rgba(130,219,251,0.5)) sColor.addColorStop

  4.2要求是每个三角形的方向都是向外的,但是现在三角形的方向都是向下的,所以现在需要使用画布的旋转方法。

  Ctx.save() ctx.translate(x,y) //旋转角度以每个点Ctx为中心。旋转(rad-Math。PI/2)//因为开头的点ctx.translate(-x,-y)。省略画三角形和单词的代码.ctx.restore()可以计算出来,以圆点的中心为旋转的起点,三角形旋转的弧度应该是当前圆点的弧度减去/2,因为旋转的起点位置是从X坐标轴的正方向开始,也就是弧度为0,但是现在三角形都在/2弧度处,所以:

  旋转弧度=圆点弧度-/2

  旋转时记得使用画布状态的存储方法save()。

  Restore(),依次从栈顶弹出存储的画布状态。如果没有存储画布状态,则执行此方法不会有任何变化。

  一定要记得在最后使用restore()方法。说到这里,作者留下了遗憾的泪水。

  特定代码:

  for(设I=0;ilengthsI){///设rad=2 * math.pi/lengths * I设x=(r-80) * math.cos (rad)设y=(r-80)* math . sin(rad)//画一个S三角形ctx.save() //旋转的角度以每个点为中心因为点ctx。平移(x,y) CTX。旋转(rad-Math.PI/2)CTX。Translate (-x,-Y)//Brush starts CTX . begin path()CTX . move to(x,Y) CTX。莱恩托(x-35,y 70) CTX。莱恩托(x 35,y 70) CTX。close path()//设置颜色渐变-add color varscolor=CTX。CreateLineargradient (x,y,x 18,y 50) sColor.addColorStop(0, rgba(106,128,243,0.5)) sColor.addColorStop(0.6, rgba(83,183,243,0.5)) sColor.addColorStop(0.7, rgba(129,200,224,0.5)) sColor.addColorStop(0.8, rgba(130

  定睛一看,什么?因为旋转问题,有些字符被颠倒了。通过观察发现,弧度大于时,字符上下颠倒。

  是时候写一波if判断了。

  旋转文本的方法:

  函数rotate context (CTX,x,y,度){//旋转文本ctx.translate (x,y)//ctx.rotate(度* math.pi/180)CTX . rotate(度)ctx.translate (-x,-y)}。

  如果(rad Math。PI) {//因为文本需要显示在三角形的边缘,所以文本要随着三角形旋转,以便始终保持在//三角形的边缘。因为旋转后弧度大于时文字会反转,那么旋转翻转文字ctx.save() ctx.beginPath() //旋转文字rotateContext(ctx,x,y 75,Math。PI)CTX . font= 13px Arial CTX . textalign= center CTX . fill style= # ff 2238 CTX . fill text(textArr[I],x,Y 75)CTX . restore()} else { CTX . fill style= # ff 2238 CTX . fill text(textArr[I],x,y 75)}绘制结果如下:

  再次希望胜利,马上就要成功了,至少总的布局已经做出来了,革命还没有成功,同志们还需要努力!

  5.以下是实现。鼠标在点的上面,这样边上的三角形和三角形边上的文字就显示出来了,而环边上的文字就不显示了。

  思路:

  1.将鼠标输入事件绑定到画布。

  2.判断当前鼠标所在画布的坐标是否等于一个点附近的坐标,如果是,则显示该点对应的三角形。

  5.1将mousemove事件绑定到画布:鼠标悬停事件

  画布。AddEventListener (mousemove ,clickevent) 5.2计算鼠标在画布上的当前坐标。

  计算方法是:用鼠标在dom上的当前坐标减去画布向左或向上的距离,计算出离画布的距离。

  下图中的drawOne方法是一种绘制方法,将在文章后面讨论。

  函数clickEvent() {//鼠标位置的坐标let x=event . clientx-canvas . getboundingclient()。left let y=event . clienty-canvas . getboundingclient()。top drawOne(x,y)}5.3,因为从顶部计算的画布上鼠标的坐标是从画布的左上角开始计算的,但是当前画布的原点已经移动到画布的中心(250,250),所以在用来判断一个点是否被点击时,需要从横坐标和纵坐标中减去250,才能与当前画布上的点的坐标进行比较。哦,是的,当我判断的时候,我发现

  代码如下:

  Cx,Cy为鼠标在画布上的坐标(画布左上角为原点),x,y为当前点的坐标。

  作者直接计算了15px在圆点中心附近的位置,都是三角形,圆点变白。

  最重要的是每次重绘都需要清空之前的画布:记得用clearRect方法清空画布。

  xx=CX-250 letyy=cy-260 letleftx=x-15 letrightx=x15 letopy=y-15 letbotomy=y15if(xx=left XXX=right xyy=bottom YY=topy){//也就是被点击了。//把画出来的代码写在中间}代码后面是链接:

  6.在接口上定义一个输入,并将更改事件绑定到输入。

  实现:每次输入中的值改变时重绘界面。

  Html代码:

  input type= text id= inpt style= margin-left:100px; Margin-top: 50px placeholder=请输入.js代码:

  let inpt=document . getelementbyid( inpt )inpt . addevent listener( change ,function () { if (inpt.value!== ){ textarr . push(inpt . value)drawall(2)//这个方法是一个绘制方法,后面会给出文章的源代码}})7 .有一个问题。每次点击界面重绘,都会闪烁。

  如下所示:

  每次滑动的时候,因为鼠标的坐标发生了变化,所以需要清除圆圈周围的内容,重新绘制。所以你需要清空画布来达到动态效果。

  ClearRect()在画布动画绘制中非常常用,它不断地清除画布的内容,然后进行绘制,形成动画效果。

  ClearRect()可以使canvas元素Canvas中的矩形区域透明。

  context.clearRect(x,y,width,height);

  X,Y:矩形左上角的X,Y坐标。

  Width,height:要清除的矩形区域的宽度和高度。

  由于clearRect()只能清除矩形区域的画布,所以每次清除时,中间的背景图像也会一起被清除。

  所以你每次都要重新加载背景图片,加载图片需要一定的时间,所以每次出现都会闪烁。

  解决方案:

  Drawimage (image,dx,dy,dwidth,dheight)其中参数image:画布图像资源,如img图像、SVG图像、画布元素本身等。

  然后你可以用其他画布的方式来缓存图片。

  使用额外的画布绘制背景图片,但对于该画布,在界面中不显示:display:none。然后在画布清空时,直接将缓存的canvals canvas对象渲染到画布中间进行显示,即不需要再次加载图片。加载图片非常耗时。

  Html代码:

  画布宽度=280 高度=280 样式= margin-left:50px;padding-top:20px;显示:无;Id=canvas2 /canvasjs代码:

  //使用缓存解决重绘图片的闪烁问题var temp canvas=document . getelementbyid( canvas 2 )const temp CTX=temp canvas . get context( 2d )temp canvas . width=280;temp canvas . height=280 letimage=new image()image . src= image/quan . png image . onload=()={//将原点移至中心tempctx.drawimage (image,0,0,280,280)}清空画布时,重绘画面时会直接缓存画布。

  //将缓存的画布直接绘制到接口(缓存的中间轮胎接口)ctx.drawimage (Tempcanvas,-140,-140)。好吧,成功了。下面是结果图:

  源代码如下:

  https://github.com/Linefate/Dynamic-effect-of-canvas-ring.git

  总结

  以上就是边肖给大家介绍的使用html5画布绘制戒指的动态效果。希望对你有帮助。如果您有任何问题,请给我留言,边肖将及时回复您。非常感谢您对网站的支持!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: