如何用 Canvas实现序列帧动画

227 阅读1分钟

先封装一个imageLoader类,新建一个imageLoader.js文件

class ImageLoader {
    constructor() {
        this.images = []
        this.progressCallback = null
    }

    // 加载图片,并返回一个 Promise
    loadImage(url) {
        return new Promise((resolve, reject) => {
            const image = new Image()
            image.onload = () => resolve(image)
            image.onerror = reject
            image.src = url
        })
    }

    // 加载所有图片
    loadImages(urls) {
        const totalImages = urls.length
        let loadedImages = 0

        return Promise.all(
            urls.map((url) => {
                return this.loadImage(url).then((image) => {
                    loadedImages++
                    if (this.progressCallback) {
                        const progress = (loadedImages / totalImages) * 100
                        this.progressCallback(progress)
                    }
                    return image
                })
            })
        )
    }

    // 设置进度回调函数
    onProgress(callback) {
        this.progressCallback = callback
    }

    // 创建 Canvas 动画
    createAnimation(canvas, images, frameRate = 30) {
        const ctx = canvas.getContext('2d')
        let currentIndex = 0
        let isPaused = true
        let animationInterval

        const drawFrame = () => {
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            ctx.drawImage(images[currentIndex], 0, 0)
            currentIndex = (currentIndex + 1) % images.length
        }

        const startAnimation = () => {
            animationInterval = setInterval(drawFrame, 1000 / frameRate)
        }

        const stopAnimation = () => {
            clearInterval(animationInterval)
        }

        return {
            play: () => {
                if (isPaused) {
                    startAnimation()
                }
                isPaused = false
            },
            pause: () => {
                stopAnimation()
                isPaused = true
            },
            setSpeed: (fps) => {
                frameRate = fps
                if (!isPaused) {
                    stopAnimation()
                    startAnimation()
                }
            },
        }
    }
}

在页面中具体使用,创建一个index.html 文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sequence Animation</title>
    <style>
        .flex {
            display: flex;
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="800" height="600"></canvas>
    <div class="flex">
        <button id="playButton">开始</button>
        <button id="pauseButton">暂停</button>
        <input type="range" id="speedSlider" min="1" max="60" value="30">
        <span id="speedValue">30 FPS</span>
    </div>


    <script src="imageLoader.js"></script>
    <script>
        const imageLoader = new ImageLoader();
        const canvas = document.getElementById('canvas');

        const urls = [
            'https://img.alicdn.com/bao/uploaded/i1/2844183150/O1CN01sk4WyK1Z8kL5J8nCm_!!2844183150.jpg',
            'https://img.alicdn.com/bao/uploaded/i2/735011836/O1CN018Dvhtw1PQvyjpdWKH_!!2-item_pic.png',
            'https://img.alicdn.com/bao/uploaded/i4/3548771708/O1CN01jqFX831OUJKXuxHpF_!!3548771708.jpg'

            // 添加其余图片的 URL
        ];

        imageLoader.loadImages(urls).then(images => {
            const animation = imageLoader.createAnimation(canvas, images);

            animation.play();

            // 示例:监听下载进度
            imageLoader.onProgress(progress => {

                console.log(`Progress: ${progress}%`);
            });

            // 示例:动画控制
            document.getElementById('playButton').addEventListener('click', () => {
                console.log('Play button clicked')
                animation.play();
            });

            document.getElementById('pauseButton').addEventListener('click', () => {
                console.log('pause button clicked')
                animation.pause();
            });

            document.getElementById('speedSlider').addEventListener('input', (event) => {
                const speed = parseInt(event.target.value);
                document.getElementById('speedValue').textContent = `${speed} FPS`;
                animation.setSpeed(speed);
            });
        });
    </script>
</body>

</html>