乐趣区

关于canvas:你的代码怎么下起了雨

大多数的程序员都会有一个本人的集体网站,咱们想要在本人的网站上面去刻画一个酷炫的背景,咱们可能会应用一些炫酷的图片,或者叠加一个视频背景,亦或是通过 css3 来进行手动绘制,这些计划都各有利弊,在呈现canvas 之后,咱们呈现了一种新的可能,咱们能够通过 canvas 绘制一些十分炫酷的背景,有意思的是,咱们还能够通过鼠标或者键盘事件与其交互,这样,咱们就领有了一种绘制动静背景的能力。

什么是 canvas

其实它是 Html5 新增的一个标签,翻译过去就是画布的意思,他就是一张画布,须要开发者们手动绘制,咱们如何绘制呢?很显著作为一个标签能力无限,咱们须要应用 javascript 对其进行加工绘制,所以咱们很好了解了,canvas是纸,而 JavaScript 是笔,通过两者的单干能力实现绘制工作。

咱们平时用的网页截图、H5 游戏、前端动效、可视化图表 …, 都有 canvas 的利用场景,所以其性能是特地弱小的,同时其大量的工作都是在 GPU 当中进行,一般来说性能是很高的,在咱们去做一些对性能要求更高的场景下,是一种不错的抉择,当然,本次咱们不是为了来解说canvas,这里就不做过多的解说,接下来咱们来进入实战。

实战

残缺的代码曾经放在文章开端,能够通过码上掘金间接观看,咱们来细聊一下其实现思路和过程,逐渐拆解进去,看完置信你也能够轻松绘制出这样的一个成果。

1. 根底筹备工作

  1. 当然最根底的是咱们须要一个 canvas 标签了,所以第一步须要创立一个标签并且给绑定一个 id 属性不便 JavaScript 获取到他
  2. 有了标签之后,咱们须要干嘛呢,总结下来是这几部,获取 canvas 节点,获取窗口的宽高,给 canvas 设置宽高,同时拿到其绘制的上下文对象,咱们要操作他须要调用其中的各种 api 办法。

    /* 1. 获取节点 */
    const canvs =  document.getElementById('app')
    /*  2. 设置 canvas 的宽高 */
    ({innerWidth: cvs.width, innerHeight: cvs.height} = window);
    /* 3. 获取 canvans 绘制上下文对象 */
    const ctx = cvs.getContext('2d');
  3. 其次咱们是渲染不同的文字,所以咱们定义一下咱们须要渲染哪些文字,同时,每次渲染的时候,随机获取一个,所以,咱们写一个办法,用于每次随机拿到一个文字。

    /* 4. 筹备一个获取随机文字办法 */
    function getRandomChar(){
     const str = '码上掘金永远滴神 YYDS'
     return str[Math.floor(Math.random() * str.length)]
    }
  4. 咱们心愿每次绘制的文字色彩也是不同的色彩,所以咱们须要筹备一个获取随机色彩的办法,置信这里都是很简略的。

    /* 5. 筹备一个获取随机色彩的办法 */
    function getRandomColor() {
     const colors = [
       '#33B5E5',
       '#0099CC',
       '#AA66CC',
       '#9933CC',
       '#669900',
       '#FFBB33',
       '#FF8800',
       '#FF4444',
       '#CC0000'
     ]
     return colors[Math.floor(Math.random() * colors.length)]
    }

    有了这些筹备工作,上面进入外围的绘制过程,咱们持续

2. 绘制过程

有了后面的步骤,咱们曾经有了根底的一些工具办法筹备了,上面咱们来开始绘制,在此之前咱们须要对其略微思考一下咱们应该怎么做,上面看看这张简略图来了解,咱们如果下实现这样的一个成果,咱们最根底的是须要啥样的。

  1. 咱们能想到的是根底场景下,咱们一行可能就须要这么多,要实现下面的成果,只须要铺满屏幕并且让他们的 y 点的程序不同即可,那么对于根底的这几列,咱们须要哪些货色呢,首先咱们得本人定义一列须要多宽的间隔,其次就能够通过窗口的宽度 / 一列宽晓得咱们最多能够一行放多少列了,其次咱们须要晓得每一列的(x,y)点的坐标,因为咱们的绘制是整个窗口,坐标从左上角(0,0)开始计算,很显著第一行的状况下,所有的 y 坐标是怎么计算的呢,第一列的 y 就是一个字体高度,第二列就是两个以此类推,然而 x 的坐标也很简略,就是一列的宽度 * 你是第几列即可,咱们就轻松算出了第一列的(x,y),接下来咱们就让第一列绘制进去,代码中咱们会有具体的正文。
/* 6. 设置一列宽度并计算一行须要多少列 */
const columnWidth = 30;
const columnCount = Math.floor(window.innerWidth / columnWidth)
  1. 咱们定义一列为 30,同时计算出了一列能够最多 columnCoun 列,所以咱们开始绘制,只须要循环 columnCoun 次就能够画出一整排的字了,同时这里咱们确定他的(x,y)坐标,上面开始绘制第一行:
/* 7. 开始绘制 */
function draw(){
    /* 定义一下字体大小,同时 y 坐标每行的所需高度就是字体大小的高度 */
  const fontsize = 16;
    /* 获取一个随机色彩用于字体绘制 */
  ctx.fillStyle = getRandomColor();
    /* 设置字体格局和字体大小,这个随便本人设置 */
  ctx.font = `${fontsize}px "Microsoft YaHei"`;
    /* 循环列数次,同时每次计算出 xy 的坐标,因为是第一行所以 y 默认就是 1 * 字体高度 */
  for (let i = 0; i < columnCount; i++) {
    const x = i * columnWidth;
    const y = 1 * fontsize
        /* 绘制 三个参数别离是 字符  x 坐标 y 坐标 */
    ctx.fillText(getRandomChar(), x, y)
  }
}

当咱们实现这个办法之后,咱们只须要调用这个办法就能够绘制出一行文字了,例如下图:

  1. 咱们能够多调用几次,发现每次都在第一行会重叠,为什么会这样呢,很简略,因为咱们 y 轴基本没变过啊,所以反复调用不就笼罩了么,所以咱们心愿,每次调用之后扭转这个 y 坐标,所以咱们须要定义一个变量记录其以后绘制处于第几行,然而很显著这个操作应该在绘制前实现,所以这一步咱们须要增加在第一步之前,其二,如果咱们都是用同一个数字对立 y 那么无论多少次绘制,这么多列始终都是在同一高度,所以咱们须要对其进行别离统计,那么咱们定义一个数组,用于统计每一行的 y 绘制的行数计算,初始值,咱们都默认为 1,在第一行,所以咱们只须要定义一个 columnCoun 长度且默认值为 1 的数组就能够记录所有值了,后续绘制的过程中扭转这个数组的 [index] 即可别离管制不同列间接的高下差别了:
/* 6.5 定义一个变量记录所有 y 轴的绘制次数记录 并让其默认值为 1 */
const columnNextIndexs = new Array(columnCount).fill(1)
  1. 有了这个变量记录之后,每次绘制实现之后咱们让其 +1, 就能够一直扭转 y 的高度了,那么咱们来扭转 draw 绘制办法,为了不便大家比拟,我只对批改的中央进行正文,更好了解:
function draw(){
  const fontsize = 16;
  ctx.fillStyle = getRandomColor();
  ctx.font = `${fontsize}px "Microsoft YaHei"`;
  for (let i = 0; i < columnCount; i++) {
    const x = i * columnWidth;
    /* 每次从记录中拿到 y 的绘制次数 */
    const y = columnNextIndexs[i] * fontsize
    ctx.fillText(getRandomChar(), x, y)
    /* 每次绘制之后 ++ */
    columnNextIndexs[i]++
  }
}

setInterval(()=> draw()},40)
  1. 这样咱们反复调用屡次,或者本人写个定时器一秒调用一次 drwa 函数即可实现按程序绘制多列:最终达到下图的成果
  1. 咱们当初就能够实现绘制多列了,然而发现,这个到底部之后他回不到结尾了,他仍然始终向下执行,那么很显著,咱们须要判断当这个 y 坐标的高度大于窗口高度的时候,咱们就须要让,columnNextIndexs 的以后这列回到初始值 1,那么他又从上开始渲染了,所以咱们加上判断:
if(y > window.innerHeight){columnNextIndexs[i] = 1
}
  1. 增加完判断之后,咱们就能够每次触底之后就持续回到顶部,然而当初咱们发现,回到顶部之后咱们会笼罩上次的文字,并不能如文章结尾的样子,能够让绘制的文字随后消失掉,要想让绘制的文字消失掉咱们能够怎么做呢, 咱们能够通过对 ctx 设置一个半透明的背景色,并且对屏幕进行填充,这样每次往后的时候,后面的字就会越来越通明,把上面两行代码放在 drwa 的最开始就能够实现这个成果了,
ctx.fillStyle = `rgba(0, 0, 0, 0.1)`;
ctx.fillRect(0, 0, window.innerWidth, window.innerHeight)

当设置完之后咱们就领有了这样的一个成果了

  1. 和咱们开始的成果貌似只差最初一步了,只须要扭转不同列之间高度差别即可,要扭转这个差值,咱们只须要让 columnNextIndexs 中每一项的值产生扭转,让他们不是同一个值既能够产生高度差,怎么扭转呢,咱们之前都是在绘制实现后 ++,那们咱们只须要让他们在达到底部的时候,增加一个判断当他触底并且 Math.random() > 0.9 的时候,咱们再让他回到顶部,因为随机数的不确定性,当他触底之后,不同列之间回到顶部的工夫就不同了,就达到了咱们最开始的成果了,咱们看看具体实现
/* 7. 开始绘制 */
function draw(){ctx.fillStyle = `rgba(0, 0, 0, 0.1)`;
  ctx.fillRect(0, 0, window.innerWidth, window.innerHeight)
  const fontsize = 16;
  ctx.fillStyle = getRandomColor();
  ctx.font = `${fontsize}px "Microsoft YaHei"`;
  for (let i = 0; i < columnCount; i++) {
    const x = i * columnWidth;
    const y = columnNextIndexs[i] * fontsize
        /* 只须要加上这一个判断就能够让不同列之间随机回到顶部造成高度差别 */
        if(y > window.innerHeight && Math.random() > .9) return columnNextIndexs[i] = 1
        ctx.fillText(getRandomChar(), x, y)
        columnNextIndexs[i]++
  }
}

至此,代码雨的成果及其实现思路曾经实现了,按着这样的思路还能够实现很多好玩的难看的货色,你也能够本人调整文字的内容,文字的大小,文字的距离,文字的背景,等等货色对其进行扭转,最终就能够实现一个本人的非凡背景图了,把它放在你的网站做背景图是不是很炫酷呢?最初别忘了你须要应用 setInterval 不停的调用draw() 办法, 当然速度也由你管制。

扩大点小性能

为了让这个 Demo 更好玩,我为其减少了一点点交互,咱们能够在 码上掘金 上进行体验,咱们说说其实现思路即可:

增加实时自定义代码雨下雨内容

首先咱们绘制的文字是由咱们本人提供的一段字符串,咱们在其中搁置一个 input 框 让后通过批改其内容,就能够实现实时批改代码雨下雨的内容了,因为每次绘制前都会去调用随机读取文字,所以咱们只须要扭转下读取文字内容就能够在下一次读取的时候从咱们输出的新的内容中获取了

让文字进行有序排列

咱们默认是无序排列的,因为获取文字的时候是随机的,然而看到咱们的封面图发现其实咱们是有序的,咱们如何实现这个性能呢,那么很显著咱们须要在获取文字的时候,按程序返回文字,然而呢,不同列之间是程序不同的,咱们须要参考最开始对不同列高度差别之间的模式,定义一个数组记录所有列以后的绘制次数,从而按程序拿到文字,就能够让其看起来更有意思了

更多好玩的货色能够本人思考 ….

在线体验

联合以上所有内容,这里提供完整版的代码,大家快来体验吧, 在线体验地址:

残缺的代码

退出移动版