canvas 重绘时的闪动问题

产生原因

canvas画布清空或者被重新绘制时,会导致之前绘制的内容瞬间消失然后重新绘制,产生了视觉上的闪烁感。

解决办法

创建两个canvas,一个 canvas用于缓存数据,另一个canvas用于显示。首先当要进行清空重新绘制之前,将要绘制的新数据缓存到用于缓存的canvas上,最后将缓存的canvas 绘制到用于显示的canvas上即可,这种方法又叫双缓冲方法

案例

<!-- 双缓冲技术解决canvas重绘闪动问题 -->
<template>
    <div ref="container" class="container">
        <!-- <div class="mask">
            <span style="mix-blend-mode: multiply;">KOOND66</span>
        </div> -->
        <canvas id="myCanvas" :width="width" :height="height"></canvas>
        <canvas id="myCanvas1" :width="width" :height="height" style="opacity: 0;"></canvas>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                animationFrameId: null,
                isAdmation: false,
                flag: true,
                width: null,
                height: null,
                list: [],
                timer: null
            }
        },
        async mounted() {
            this.width = this.$refs.container.clientWidth
            this.height = this.$refs.container.clientHeight
            await this.computedCircle()
            window.addEventListener('resize', this.handleResize);
        },
        beforeDestroy() {
            window.cancelAnimationFrame(this.animationFrameId);
        },
        methods: {
            startAdmation() {
                this.requestAdmationStart()
            },
            requestAdmationStart() {
                this.move()
                window.cancelAnimationFrame(this.animationFrameId);
                this.animationFrameId = window.requestAnimationFrame(this.requestAdmationStart)
            },
            handleResize() {
                this.width = this.$refs.container.clientWidth
                this.height = this.$refs.container.clientHeight
                // this.initBall(true)
                let canvas = document.getElementById('myCanvas')
                let content = canvas.getContext('2d')
                let tempCanvas = document.getElementById('myCanvas1');
                let tempCtx = tempCanvas.getContext('2d');
                tempCtx.clearRect(0, 0, tempCtx.canvas.width, tempCtx.canvas.height)
                this.list.forEach(item => {
                    tempCtx.beginPath()
                    tempCtx.arc(item.x, item.y, item.r, 0, Math.PI * 2, false)
                    tempCtx.fillStyle = item.color
                    tempCtx.fill()
                })
                const imageData = tempCtx.getImageData(0, 0, tempCtx.canvas.width, tempCtx.canvas.height);
                //content.clearRect(0, 0, content.canvas.width, content.canvas.height)
                content.putImageData(imageData, 0, 0); // 渲染到显示的canvas上
                // this.startAdmation()
            },
            computedCircle() {
                let canvas = document.getElementById('myCanvas')
                let content = canvas.getContext('2d')
                for(let i = 0; i < 10; i++) {
                    let newR = 50 * Math.random()+10
                    this.list[i] = {
                        r: newR,
                        x: content.canvas.width * Math.random() <= newR + 200 ? content.canvas.width * Math.random() + newR + 200: content.canvas.width * Math.random() > content.canvas.width - newR ? content.canvas.width - newR : content.canvas.width * Math.random(),
                        y: content.canvas.height * Math.random() <= newR + 200 ? content.canvas.height * Math.random() + newR + 200: content.canvas.height * Math.random() > content.canvas.height - newR ? content.canvas.height - newR : content.canvas.height * Math.random(),
                        vx: 4 * Math.random()-2,
                        vy: 4 * Math.random()-2,
                        color: 'rgba(' +
                            (Math.random() * 255).toFixed(0) + ',' +
                            (Math.random() * 255).toFixed(0) + ',' +
                            (Math.random() * 255).toFixed(0) + ',' +
                            (0.5+0.5*Math.random()).toFixed(1) + ')'
                    }
                }
                this.initBall(true)
            },
            initBall(flag) {
                let canvas = document.getElementById('myCanvas')
                let content = canvas.getContext('2d')
                content.clearRect(0, 0, content.canvas.width, content.canvas.height)
                this.list.forEach(item => {
                    content.beginPath()
                    content.arc(item.x, item.y, item.r, 0, Math.PI * 2, false)
                    content.fillStyle = item.color
                    content.fill()
                })
                if(flag) {
                    this.startAdmation()
                }
            },
            move() {
                let canvas = document.getElementById('myCanvas')
                let content = canvas.getContext('2d')
                this.list.forEach(item => {
                    if(item.x + item.vx > content.canvas.width - item.r || item.x + item.vx < 0 + item.r) {
                        item.vx = -item.vx
                    }
                    if(item.y + item.vy > content.canvas.height - item.r || item.y + item.vy < 0 + item.r) {
                        item.vy = -item.vy
                    }
                    item.x += item.vx
                    item.y += item.vy
                })
                let tempCanvas = document.getElementById('myCanvas1');
                let tempCtx = tempCanvas.getContext('2d');
                tempCtx.clearRect(0, 0, tempCtx.canvas.width, tempCtx.canvas.height)
                this.list.forEach(item => {
                    tempCtx.beginPath()
                    tempCtx.arc(item.x, item.y, item.r, 0, Math.PI * 2, false)
                    tempCtx.fillStyle = item.color
                    tempCtx.fill()
                })
                const imageData = tempCtx.getImageData(0, 0, tempCtx.canvas.width, tempCtx.canvas.height); // 先缓存最新的数据
                content.clearRect(0, 0, content.canvas.width, content.canvas.height)
                content.putImageData(imageData, 0, 0); 
            }
        }
    }
</script>

<style lang="less" scoped>
    .container {
        width: 80%;
        height: 80%;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }
    canvas {
        width: 100%;
        height: 100%;
        border: 1px solid #eee;
    }
    .mask {
        width: 100%;
        height: 100%;
        position: absolute;
        background-color: black;
        left: 0;
        top: 0;
        font-size: 100px;
        font-weight: 700;
        // color: aliceblue;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    #myCanvas1 {
        position: absolute;
        left: -9999999999999999px;
        top: -99999999999999px;
    }
</style>

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值