效果说明
本案例实现了一个图片像素跳动的动画效果。将图片分解成像素块,默认进行垂直运动,当鼠标悬浮时切换为水平运动,创造出独特的视觉效果。
实现原理
1. 图片像素化处理
通过 Canvas 的 getImageData 方法获取图片像素数据,并转换为可操作的像素对象:
function initPixels() {
const offscreen = document.createElement('canvas');
const offscreenCtx = offscreen.getContext('2d');
// ... 绘制图片到离屏 canvas
const imageData = offscreenCtx.getImageData(0, 0, canvas.width, canvas.height);
// 遍历图片数据,创建像素对象
for (let y = 0; y < canvas.height; y += pixelSize) {
for (let x = 0; x < canvas.width; x += pixelSize) {
const index = (y canvas.width + x) 4;
pixels.push({
x, y,
baseX: x,
baseY: y,
color: rgb(${r}, ${g}, ${b}),
amplitude: Math.random() 3 + 2,
angle: Math.random() Math.PI 2,
speed: 0.03 + Math.random() 0.02
// ...
});
}
}
}
2. 像素运动控制
每个像素点都具有独立的运动参数,通过正弦函数实现周期运动:
function updatePixels() {
pixels.forEach(pixel => {
pixel.angle += pixel.speed;
if (isMouseOver) {
// 水平运动
pixel.x = pixel.baseX + Math.sin(pixel.angle) * pixel.currentAmplitude;
pixel.y = pixel.baseY;
} else {
// 垂直运动
pixel.x = pixel.baseX;
pixel.y = pixel.baseY + Math.sin(pixel.angle) * pixel.currentAmplitude;
}
});
}
3. 平滑过渡实现
- 使用 currentAmplitude 和 targetAmplitude 实现运动幅度的平滑过渡
- 通过 mouseenter/mouseleave 事件切换运动方向
- 随机改变振幅使动画更加生动
// 鼠标事件处理 canvas.addEventListener('mouseenter', () => { isMouseOver = true; pixels.forEach(pixel => { pixel.targetAmplitude = Math.random() 3 + 2; }); }); // 定期随机改变振幅 setInterval(() => { pixels.forEach(pixel => { if (Math.random() < 0.1) { pixel.targetAmplitude = Math.random() 3 + 2; } }); }, 2000);
核心技术点
-
Canvas 像素操作
- 使用 getImageData 获取图片像素数据
- 通过离屏 canvas 优化性能
-
动画算法
- 使用正弦函数实现周期运动
- 为每个像素设置独立的运动参数
- 实现平滑的状态过渡
-
性能优化
- 使用 requestAnimationFrame 实现动画循环
- 优化像素采样大小
- 使用离屏渲染
-
Demo
吐槽一下:代码片段功能,没有找到上传图片资源功能,导致把图片转base64字符串才能正常运行