像素跳动效果

1,034 阅读1分钟

效果说明

本案例实现了一个图片像素跳动的动画效果。将图片分解成像素块,默认进行垂直运动,当鼠标悬浮时切换为水平运动,创造出独特的视觉效果。

Snipaste_2024-12-31_15-14-03.png

实现原理

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);

核心技术点

  1. Canvas 像素操作

    • 使用 getImageData 获取图片像素数据
    • 通过离屏 canvas 优化性能
  2. 动画算法

    • 使用正弦函数实现周期运动
    • 为每个像素设置独立的运动参数
    • 实现平滑的状态过渡
  3. 性能优化

    • 使用 requestAnimationFrame 实现动画循环
    • 优化像素采样大小
    • 使用离屏渲染

Demo

吐槽一下:代码片段功能,没有找到上传图片资源功能,导致把图片转base64字符串才能正常运行