canvas动态随机纹理

点击图片启/停动态

配置参数,包括重复平铺元素的尺寸、背景的放大系数、纹理的透明度、动态重绘频率。

const config = {
size: 150,
scaleX: 1,
scaleY: 1,
alpha: 20,
interval: 8
}

背景画布,scale方法可对绘图进行缩放。

let bgCanvas, viewW, viewH, bgCtx

bgCanvas = document.getElementById('grain')
viewW = bgCanvas.width = bgCanvas.parentNode.clientWidth
viewH = bgCanvas.height = Math.round(viewW * 0.4)
bgCtx = bgCanvas.getContext('2d')
bgCtx.scale(config.scaleX, config.scaleY)

创建重复平铺元素,使用createImageData方法创建空白ImageData对象,ImageData对象的data是一个Uint8ClampedArray数组,图像的每个像素信息占4个元素储存,其中:

  • R - 红色 (0-255)
  • G - 绿色 (0-255)
  • B - 蓝色 (0-255)
  • A - alpha通道 (0-255 0透明 255完全可见)

这里空白ImageData对象data的所有像素初始值均为0。

let ptCanvas, ptCtx, ptData, ptDataLength

ptCanvas = document.createElement('canvas')
ptCanvas.width = ptCanvas.height = config.size
ptCtx = ptCanvas.getContext('2d')
ptData = ptCtx.createImageData(config.size, config.size)
ptDataLength = config.size * config.size * 4

绘图,给ImageData设置随机像素值,使用putImageData方法将图像数据放入平铺元素画布,擦除背景上的纹理图像,然后设置用于填充绘画的重复平铺模式,最后矩形填充背景。

function draw() {
for (let i = 0; i < ptDataLength; i += 4) {
const v = (Math.random() * 255) | 0
ptData.data[i] = v
ptData.data[i + 1] = v
ptData.data[i + 2] = v
ptData.data[i + 3] = config.alpha
}
ptCtx.putImageData(ptData, 0, 0)

bgCtx.clearRect(0, 0, viewW, viewH)
bgCtx.fillStyle = bgCtx.createPattern(ptCanvas, 'repeat')
bgCtx.fillRect(0, 0, viewW, viewH)
}
draw()

以一定的频率动态重绘。

let frame = 0, play = false

function loop() {
if (++frame % config.interval === 0) draw()
play && requestAnimationFrame(loop)
}

bgCanvas.addEventListener('click', () => {
play = !play
play && loop()
})