canvas动画心得

canvas的一些心得

由于最近课比较少,因此在codepen上逛的时间比较多,借此能够学习一些优秀的做品,昨天看到了一个很炫的星空,先给你们看看效果。css

源码出奇的短,总共不过一百余行,代码的逻辑也写的浅显易懂,主要思路就是不一样轨道的星星绕着中心点旋转,其次就是半径越大的星星在视觉上距离咱们越近,由于中心点是最远点,因此最远点应该旋转的速率最快,越清晰,更大。读这段代码的时候,并无花费不少时间,初读的时候仍是停留在逻辑层面。前端

  • 却是做者源码里有一段注释,仍是颇有必要的,这里引用一下。

// Thanks @jackrugile for the performance tip! https://codepen.io/jackrugile/pen/BjBGoM // Cache gradientcanvas

咱们再引用一下注释下面的代码缓存

var canvas2 = document.createElement('canvas'),
ctx2 = canvas2.getContext('2d');
canvas2.width = 100;
canvas2.height = 100;
var half = canvas2.width/2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#fff');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');

ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
复制代码

这段代码的意思是在新的canvas 里画渐变,对应的是天上的星星。结合做者的注释,目的就是将不变的元素放在一个离屏的canvas里,而后在主canvas里经过drawImage里引用,以此减小绘制。也是性能调优的一个策略,其实对稍微有点经验的同窗来讲,这也是很普通的技巧了,这里特意拿出来,也是但愿能给新同窗一点建议。dom

  • 第二点就是色彩

我相信大多数前端爱好者都是和我同样,本硕都是计算机,对色彩没有理解,往深处分析了一下做者的代码,有不少颇有意思的trick,你能感觉到做者颇有意思的想象力。性能

星星是会闪烁的,怎么突出星星的闪烁呢? canvas里 有shadowBlur的属性,相似css里的box-shadow,固然能够用这种方法来突出闪烁,可是这样的效果并很差!做者的方法很巧妙。做者的思路是用径向渐变,放上代码。学习

gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#fff');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
复制代码

我的以为这段代码真是神来之笔,这里还有一个点,就是做者对body背景色的设置动画

body {
 		 background: #060e1b;
  		 overflow: hidden;
	}
复制代码

这里把 #060e1b 转化成hsl(217, 64%, 6%) 包括后面做者fillRect清屏的时候,填充色也是选择 hsl(217, 64%, 6%)。这个颜色正是渐变色的第三种颜色。this

咱们如今来分析做者为何要分别选取这渐变的四种颜色呢? 从上往下分别是spa

#fff  白色
hsl(217, 61%, 33%) 墨蓝 夜里的天空
hsl(217, 61%, 6%) 更墨的蓝 由于亮度减小了
rgba(0,0,0,0)   //注意注意,原来transparent里的色值是 rgba(0,0,0,0);
复制代码

第一种颜色白色很好理解,是星星的光,第二种颜色是明亮的背景色,第三种由于光少了,因此暗了,最后逐渐变深。 不少人会说最后的rgba(0,0,0,0)有什么用?

这里要结合后面部分的代码来看

ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.8;
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
ctx.fillRect(0, 0, w, h)

 ctx.globalCompositeOperation = 'lighter';
复制代码

这样就茅塞对开了,做者用了hsla(' + hue + ', 64%, 6%, 1) 平铺背景后,用了globalCompositeOperation = 'lighter' 让星星和背景的颜色融合,这样最后因为transparent 就彻底融入了背景。

而在 hsl(217, 61%, 6%) -> rgba(0,0,0,0) 的变化呢?

咱们把 hsl(217, 61%, 6%) 转换成rgb为 rgb(6, 14, 25) 这个和 rgba(0,0,0) 很接近呀,肉眼看不出来呀。

咱们放上 #fff -> rgba(0,0,0,0) 的过渡图。

white->black

大体是变深色,而后变浅,由于最后是透明吗,这里就是对应底色了。因此咱们能够得出 hsl(217, 61%, 6%) -> rgba(0,0,0,0) 的变化,就是深一点的背景色->背景色的变化,由于两种颜色相近,真是区别不大。

做者在绘制开头用了 ctx.globalCompositeOperation = 'source-over'; 来避免星星过多,过亮,用了 ctx.globalAlpha = 0.8 来平铺背景色,让有星星的帧,会有一点余光透过去,好像星星变暗了,都是很棒的想法。

因此之后咱们要作闪烁的物体能够参照上面的方法,好比烟火,激光之类的

学以至用

受到启发后,本身下午就写了一个demo,仍是先上效果图吧。

这里发光的方案都是来自前面的方案,嘿嘿,做者感受蛮不错的,有一种**‘黑黑的天空低垂,亮亮的繁星相随’**的感受,好了给你们分析一下个人一些trick吧。这里把一些不错的的点给你们分享一下,由于这里元素比较多,确定不能按照前面的代码组织方式了。

个人组织方式

var Render = {
	  startCount: 100,
     starList: [],
     cacheCanvas: {}
     init: () => {},
     drawFigure: () => {}
}
	
var Star = () => {};
Star.prototype.draw = () => {}
复制代码

其中 Render控制屏幕中的整个动画,init 方法用于生成星星,草,路灯等。drawFigure用于作动画,cancheCanvas 用于缓存不变的物体,好比星星等。

给你们看看我画星星的方法吧,你们就明白了个人方案了,个人星星是横向移动的,因此要考虑星星飞出屏幕的状况,一旦飞出屏幕,要再补上星星。

  • 生成星星

    对应init方法

    for (var i = 0; i < this.startCount; i++) {
          this.starList.push(new Star(random(w), random(0, h), 			this.radius));
    	}
    复制代码
  • 绘制星星

    对应drawFigure方法

    ctx.globalCompositeOperation = 'source-over';
      ctx.globalAlpha = 0.8;
      ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
      ctx.fillRect(0, 0, w, h);
      ctx.globalCompositeOperation = 'lighter';
      for (var i = 0; i < this.starList.length; i++) {
      if (this.starList[i].draw()) {    //星星超出边界
       		this.starList.splice(i, 1);
       		this.starList.push(new Star(random(w), random(h), 					this.radius, 1));
          }
      }
    复制代码
  • 星星的移动

    对应star的draw方法

    this.x = this.x + 0.5 * Math.random() * Math.random(); 	
      var twinkle = random(10);
    
      if (twinkle === 1 && this.alpha < 0) {
      this.alpha += 0.05;
      }
      if (twinkle === 2 && this.alpha > 1) {
      this.alpha -= 0.05;
      }
      ctx.globalAlpha = this.alpha;
      ctx.drawImage(Render.cacheCanvas.star, this.x - this.radius / 2, 		this.y - this.radius / 2, this.radius, this.radius);
      return this.x > w || this.y > h ? true : false       
    复制代码

    动画里的草是贝塞尔曲线绘制的,这个没有诀窍,只能本身一点点调,咱们要让小草随风摇摆这里的诀窍是把画布旋转到小草的根部,而后旋转画布,贴出代码。

    ctx.save();
      ctx.translate(this.x, this.y);
      ctx.rotate(this.theta);
      ctx.globalCompositeOperation = 'source-over';
    复制代码

至于台灯和月亮就是本身一点点画,一点点调了,没有捷径。canvas就是一块画布,你能够在上面发挥你的无尽想象力。课余多逛逛codepen,学习一下别人优秀的做品,提升本身。

相关文章
相关标签/搜索