Skip to content

Instantly share code, notes, and snippets.

@JSoon
Last active July 19, 2018 07:46
Show Gist options
  • Save JSoon/4dac8d2d901958eaf902025a1e95c1b7 to your computer and use it in GitHub Desktop.
Save JSoon/4dac8d2d901958eaf902025a1e95c1b7 to your computer and use it in GitHub Desktop.
【canvas】电视机无信号噪点动效,利用正弦函数模拟真实噪声影像
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>电视机无信号噪点动效,利用正弦函数模拟真实噪声影像</title>
<style>
.tv-box {
position: relative;
width: 600px;
height: 400px;
}
.tv-box canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
</style>
</head>
<body>
<div id="J_TVBox" class="tv-box"></div>
<script>
tvNoiseEffect({
containerId: 'J_TVBox',
cycleFactor: 50000,
grayscale: 10
});
/**
* @description
* 电视机无信号噪点动效,利用正弦函数模拟真实噪声影像
* @author J.Soon <[email protected]>
* @date 2018-07-17
* @see {@link https://stackoverflow.com/questions/22003491/animating-canvas-to-look-like-tv-noise/23572465}
* @param {object} opts 配置参数对象
* @param {string} opts.containerId 播放器容器id
* @param {number} opts.interval 噪声绘制时间频率,单位毫秒
* @param {number} opts.grayscale 噪声灰度
* @param {number} opts.opacity 画布像素不透明度
* @param {number} opts.cycleFactor 周期系数,影响正弦周期大小,该值越小,则正弦周期越小,反之越大
* @returns {object} 包含销毁画布方法的对象
*/
function tvNoiseEffect(opts) {
var canvas = null; // 画布
var context = null; // 画布上下文(这里是2D画布)
var time = 0; // 噪声带生成次数系数(最多不超过噪声画布高度,计算方式为取模)
var intervalId = 0; // 噪声绘制定时器id
var interval = opts.internal || 50; // 噪声绘制时间频率,单位毫秒
var grayscale = opts.grayscale || 8; // 噪声灰度
var opacity = opts.opacity || 255; // 画布像素不透明度,默认完全不透明
var cycleFactor = opts.cycleFactor || 80000; // 周期系数,影响正弦周期大小,该值越小,则正弦周期越小,反之越大
var containerId = opts.containerId; // 播放器容器id
if (!containerId) {
throw new Error('请指定播放器容器id!');
}
var makeNoise = function () {
if (!canvas.parentNode) {
return;
}
var canvasWidth = canvas.parentNode.clientWidth;
var canvasHeight = canvas.parentNode.clientHeight;
if (!canvasWidth || !canvasHeight) {
return;
}
canvas.width = canvasWidth;
canvas.height = canvasHeight;
var imgData = context.createImageData(canvasWidth, canvasHeight);
var pix = imgData.data;
// 由下至上渲染噪声带,绘制整幅噪声图像
for (var i = 0, n = pix.length; i < n; i += 4) {
var c = 7 + Math.sin(i / cycleFactor + time / 7); // A sine wave of the form sin(ax + bt)
pix[i] = pix[i + 1] = pix[i + 2] = grayscale * Math.random() * c; // Set a random gray
pix[i + 3] = opacity; // 100% opaque
}
context.putImageData(imgData, 0, 0);
time = (time + 1) % canvas.height; // 取模,保证噪声带渲染不会超过画布
};
var setup = function () {
canvas = document.createElement('canvas');
canvas.setAttribute('class', 'video-player-tv-noise');
document.getElementById(containerId).appendChild(canvas);
context = canvas.getContext('2d');
};
// 销毁噪声动效
var destroy = function() {
if (canvas.parentNode) {
canvas.parentNode.removeChild(canvas);
}
if (intervalId) {
window.clearInterval(intervalId);
}
};
setup();
intervalId = setInterval(makeNoise, interval);
return {
destroy: destroy
};
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment