图片效果
代码分析
获取图片
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let img = new Image(), imgData, points = [], pos
img.src = 'image.jpg'
// img.src = 'answer.png'
img.onload = function () {
canvas.width = (img.width>document.body.width?document.body.width:img.width) || canvas.width
canvas.height = (img.height>document.body.height?document.body.height:img.height) || canvas.height
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data
getPoints()
draw()
}
- 将canvas的宽高设置为图片的宽高,若超过屏幕的宽高,以屏幕的宽高为主。
- drawImage存在跨域问题,需要获得base64的图片或者本地启动服务器解决跨域。
- getImageData可以得到data,height,width。在此,仅需拿到包含rgba数组的data即可。
data的数据格式
获取粒子
function getPoints() {
for (let i = 0; i < canvas.height; i++) {
for (let j = 0; j < canvas.width; j++) {
pos = (i * canvas.width + j) * 4
points.push({
xa: (canvas.width/10) * Math.random()+1 | 0,
ya: (canvas.height/10) * Math.random()+1 | 0,
xs: Math.random() * canvas.width | 0,
ys: Math.random() * canvas.height | 0,
x: j,
y: i,
fillStyle: `rgba(${imgData[pos]},${imgData[pos + 1]},${imgData[pos + 2]},${imgData[pos + 3]})`
})
}
}
}
- 将图片的每个点最终的位置x,y轴,xy的移动速度xa,ya,xy的当前随机位置xs,ys,颜色值,存储到points中。
- pos为当前点所在颜色的r的位置
- |0的写法代表的是不保留小数,因为随机数是有小数的
随机点寻找目标位置
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
let continueDraw = false
points.forEach((p, index) => {
p.xs = Math.abs(p.xs - p.x) <= p.xa ? p.x : (p.xs + ((p.x - p.xs) > 0 ? p.xa : -p.xa))
p.ys = Math.abs(p.ys - p.y) <= p.ya ? p.y : (p.ys + ((p.y - p.ys) > 0 ? p.ya : -p.ya))
p.xa = p.xa + (canvas.width/100 + 1 |0)
p.ya = p.ya + (canvas.height/100 + 1 |0)
ctx.fillRect(p.xs, p.ys, 1, 1)
ctx.fillStyle = p.fillStyle
if(p.xs !== p.x || p.ys !== p.y) continueDraw = true
})
if(continueDraw) requestAnimationFrame(draw)
else cancelAnimationFrame(draw)
}
- 原来的画布是有图片的,所以需要先清空画布
- continueDraw是判断所有的点是否都找到对应位置,是的话就取消动画,不是的话继续寻找
- 当前点的位置移动,如果距离目标点的位置比速度要小,直接到目标点的位置,不然就加上或减去该方向的速度
- 如果粒子一直保持某个速度,用户等待时间长会不美观,所以每次循环后,都将粒子的速度加快
下一个学习任务: 粒子消失的效果