canvas教程

一个例子带你入门canvas(4)

字号+ 作者:H5之家 来源:H5之家 2017-08-12 11:00 我要评论( )

这样就可以正常显示了: canvas进行图像裁剪 绘制文字fillText(text,x,y):绘制实心文字strokeText():绘制文字描边(空心)textAlign:设置或返回文本内容的当前对齐方式textBaseline:设置或返回在绘制文本时使用

这样就可以正常显示了:

canvas进行图像裁剪 绘制文字 fillText(text,x,y):绘制实心文字 strokeText():绘制文字描边(空心) textAlign:设置或返回文本内容的当前对齐方式 textBaseline:设置或返回在绘制文本时使用的当前文本基线 font:设置或返回文本内容的当前字体属性

例如:

context.font="40px Arial"; context.fillText("Hello world",200,200); context.strokeText("Hello world",200,300)

效果如下:

canvas绘制文字 准备工作

好的开始是成功的一半

简单介绍了下 canvas 的常用 api,大家发现是不是也没有那么难呢~( ̄▽ ̄)~*,那么让我们回到标题,一起来看一下这个少女心满满的例子是怎样实现的~

canvas 其实写一个炫酷的特效在技术上并不难,难的是你的创意,因为 canvas 实现粒子的效果还是比较惊艳的,但其实代码都是比较简单的,无非就是随机的创建图形或者路径,当然图形也是闭合的路径。在加上一定的位移就可以了。但是你要设计出一个好的特效是非常不容易的。

所以我们就先来分析一下这个效果由那几部分构成,将其拆分开来。

特效pc端演示地址: sunshine940326.github.io/canvasStar/ (当然,可以直接查看我的博客,背景暂时就是这个,不知道什么时候会变,捂脸ing:cherryblog.site/)

分析 star 的表现和行为

我们可以将其一直位移向上的粒子称为 star,我们观察 star 的特点:

  • 开始创建时位置随机(坐标随机)
  • 透明度随机
  • 创建时的大小在一定范围内(半径在一定范围内)
  • 匀速上升
  • 总数不变
  • 所以我们就可以总结出 star 的特点就是总数固定,创建时坐标和半径还有透明度随机,匀速上升。是不是很简单了呢~[]~( ̄▽ ̄)~*

    分析 dot 的表现和行为

    再让我们来看一下随着鼠标移入产生的粒子,我们称为 dot,同理,我们观察得到 dot 的特点

  • 列表内容
  • 鼠标移动时产生
  • 新产生的 dot 和之前的 3 个 dot 产生连线
  • 向四周移动
  • 达到一定条件消失
  • 这样,我们就完成了一半了呢~将事件屡清楚之后我们就可以开始着手撸代码了!

    背景的 HTML 和 CSS

    其实需要的 HTML 代码和 CSS 代码很简答的,HTML 只需要一行就可以了呢,设置一个渐变的背景蒙层和一个 canvas 标签。

    <div class="filter"></div> <canvas id="canvas"></canvas>

    CSS 如下:

    html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: black; background: linear-gradient(to bottom, #dcdcdc 0%, palevioletred 100%); } #main-canvas { width: 100%; height: 100%; } .filter { width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: #fe5757; animation: colorChange 30s ease-in-out infinite; animation-fill-mode: both; mix-blend-mode: overlay; } @keyframes colorChange { 0%, 100% { opacity: 0; } 50% { opacity: .7; } }

    是的,我使用的是一个渐变的背景,不仅是从上到下的渐变,并且颜色也是会渐变的,效果如下:

    渐变背景 设置参数以及获取 dom 对象 /* * @var star_r:star半径系数,系数越大,半径越大 * @var star_alpha:生成star的透明度,star_alpha越大,透明度越低 * @var initStarsPopulation:初始化stars的个数 * @var move_distance:star位移的距离,数值越大,位移越大 * @var dot_r : dot半径系数,系数越大,半径越大 * @var dot_speeds : dots运动的速度 * @var dot_alpha : dots的透明度 * @var aReduction:dot消失条件,透明度小于aReduction时消失 * @var dotsMinDist:dot最小距离 * @var maxDistFromCursor:dot最大距离 * */ var config = { star_r : 3, star_alpha : 5, initStarsPopulation : 150, move_distance : 0.25, dot_r : 5, dot_speeds : 0.5, dot_alpha : 0.5, dot_aReduction : 0.01, dotsMinDist : 5, maxDistFromCursor : 50, }; var stars = [], dots = [], canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), WIDTH, HEIGHT, mouseMoving = false, mouseMoveChecker, mouseX, mouseY; 绘制单个 star /* 设置单个 star * @param id:id * @param x:x坐标 * @param y:y坐标 * @param useCache:是否使用缓存 * */ function Star(id, x, y) { this.id = id; this.x = x; this.y = y; this.cacheCanvas = document.createElement("canvas"); this.cacheCtx = this.cacheCanvas.getContext("2d"); this.r = Math.floor(Math.random() * star_r) + 1; this.cacheCtx.width = 6 * this.r; this.cacheCtx.height = 6 * this.r; var alpha = ( Math.floor(Math.random() * 10) + 1) / star_alpha; this.color = "rgba(255,255,255," + alpha + ")"; if (useCache) { this.cache() } } 让每一个 star 动起来

    这里我使用的是原型的方式,将 draw 、 cache 、 move 和 die 方法都设置在 Star 的原型上,这样在使用 new 创建对象的时候,每一个 star 都可以继承这些方法。

    Star.prototype = { draw : function () { if (!this.useCacha) { ctx.save(); ctx.fillStyle = this.color; ctx.shadowBlur = this.r * 2; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false); ctx.closePath(); ctx.fill(); ctx.restore(); } else { ctx.drawImage(this.cacheCanvas, this.x - this.r, this.y - this.r); } }, cache : function () { this.cacheCtx.save(); this.cacheCtx.fillStyle = this.color; this.cacheCtx.shadowColor = "white"; this.cacheCtx.shadowBlur = this.r * 2; this.cacheCtx.beginPath(); this.cacheCtx.arc(this.r * 3, this.r * 3, this.r, 0, 2 * Math.PI); this.cacheCtx.closePath(); this.cacheCtx.fill(); this.cacheCtx.restore(); }, move : function () { this.y -= move_distance; if (this.y <= -10) { this.y += HEIGHT + 10; } this.draw(); }, die : function () { stars[this.id] = null; delete stars[this.id] } }; 绘制 dot function Dot(id, x, y, useCache) { this.id = id; this.x = x; this.y = y; this.r = Math.floor(Math.random() * dot_r)+1; this.speed = dot_speeds; this.a = dot_alpha; this.aReduction = dot_aReduction; this.useCache = useCache; this.dotCanvas = document.createElement("canvas"); this.dotCtx = this.dotCanvas.getContext("2d"); this.dotCtx.width = 6 * this.r; this.dotCtx.height = 6 * this.r; this.dotCtx.a = 0.5; this.color = "rgba(255,255,255," + this.a +")"; this.dotCtx.color = "rgba(255,255,255," + this.dotCtx.a + ")"; this.linkColor = "rgba(255,255,255," + this.a/4 + ")"; this.dir = Math.floor(Math.random()*140)+200; if( useCache){ this.cache() } } 让每一个 dot 动起来 Dot.prototype = { draw : function () { if( !this.useCache){ ctx.save(); ctx.fillStyle = this.color; ctx.shadowColor = "white"; ctx.shadowBlur = this.r * 2; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false); ctx.closePath(); ctx.fill(); ctx.restore(); }else{ ctx.drawImage(this.dotCanvas, this.x - this.r * 3, this.y - this.r *3); } }, cache : function () { this.dotCtx.save(); this.dotCtx.a -= this.aReduction; this.dotCtx.color = "rgba(255,255,255," + this.dotCtx.a + ")"; this.dotCtx.fillStyle = this.dotCtx.color; this.dotCtx.shadowColor = "white"; this.dotCtx.shadowBlur = this.r * 2; this.dotCtx.beginPath(); this.dotCtx.arc(this.r * 3, this.r * 3, this.r, 0, 2 * Math.PI, false); this.dotCtx.closePath(); this.dotCtx.fill(); this.dotCtx.restore(); }, link : function () { if (this.id == 0) return; var previousDot1 = getPreviousDot(this.id, 1); var previousDot2 = getPreviousDot(this.id, 2); var previousDot3 = getPreviousDot(this.id, 3); var previousDot4 = getPreviousDot(this.id, 4); if (!previousDot1) return; ctx.strokeStyle = this.linkColor; ctx.moveTo(previousDot1.x, previousDot1.y); ctx.beginPath(); ctx.lineTo(this.x, this.y); if (previousDot2 != false) ctx.lineTo(previousDot2.x, previousDot2.y); if (previousDot3 != false) ctx.lineTo(previousDot3.x, previousDot3.y); if (previousDot4 != false) ctx.lineTo(previousDot4.x, previousDot4.y); ctx.stroke(); ctx.closePath(); }, move : function () { this.a -= this.aReduction; if(this.a <= 0 ){ this.die(); return } this.dotCtx.a -= this.aReduction; this.dotCtx.color = "rgba(255,255,255," + this.dotCtx.a + ")"; this.color = "rgba(255,255,255," + this.a + ")"; this.linkColor = "rgba(255,255,255," + this.a/4 + ")"; this.x = this.x + Math.cos(degToRad(this.dir)) * this.speed; this.y = this.y + Math.sin(degToRad(this.dir)) * this.speed; this.draw(); this.link(); }, die : function () { dots[this.id] = null; delete dots[this.id]; } }; 鼠标移入事件监听

    此外,我们还需要设置一些其他的函数和对鼠标移入事件的监听,这里就不再赘述了,感兴趣的同学可以直接到 github 下载源码。

    canvas 离屏渲染优化

    我所使用的离屏优化是基于此文,原文写的很好,大家感兴趣的话可以去看一下: …

    因为这个效果之前我也在博客用当做背景过,不少同学都反应很卡,所以我就找了下优化的教程做了下优化,我发现对性能影响最大的可能就是 canvas 的离屏渲染优化了,这也是 canvas 的最常见优化之一。

    名字听起来很复杂,什么离屏渲染,其实就是设置缓存,绘制图像的时候在屏幕之外的地方绘制好,然后再直接拿过来用,这不就是缓存的概念吗?!︿( ̄︶ ̄)︿.

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 用Canvas + WASM画一个迷宫

      用Canvas + WASM画一个迷宫

      2017-08-05 11:00

    • 利用html5 canvas 画图的一个例子

      利用html5 canvas 画图的一个例子

      2017-08-04 16:00

    • struts_20_对Action中所有方法、某一个方法进行输入校验(基于XML配置方式实现输入校验)

      struts_20_对Action中所有方法、某一个方法进行输入校验(基于XML配

      2017-07-27 13:02

    • HTML5中Canvas(绘制)使用例子

      HTML5中Canvas(绘制)使用例子

      2017-07-21 14:00

    网友点评