产生原因
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>