canvas鼠标点击特效
1. 基础准备
1.准备基础的canvas画布
let mousedown // 鼠标按下事件
let mouseup // 鼠标抬起事件
const balls = [] // 存放小球
let longPressed = false
let longPress // 长按事件计时器
let multiplier = 0 // 倍数器
let width, height // 画布宽高
let origin // 原点坐标
let normal // 每次小球坐标变化的基数
let ctx // canvas的上下文
const colours = ["#F73859", "#14FFEC", "#00E0FF", "#FF99FE", "#FAF15D"] // 烟花色彩
const canvas = document.createElement("canvas") // 创建canvas
document.body.appendChild(canvas) // 添加canvas
// 设置基础样式
canvas.setAttribute(
"style",
"width: 100%; height: 100%; top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;"
)
2.准备鼠标样式
const pointer = document.createElement("span") // 生成鼠标元素
pointer.classList.add("pointer") // 添加样式
document.body.appendChild(pointer) // 添加到body
// 添加鼠标移动事件
window.addEventListener(
"mousemove",
function (e) {
const x = e.clientX
const y = e.clientY
pointer.style.top = y + "px"
pointer.style.left = x + "px"
},
false
)
body{
cursor: none; /* 隐藏鼠标 */
}
.pointer {
position: fixed; /* 固定位置 */
top: 50%;
left: 50%;
width: 50px;
height: 50px;
border-radius: 50%;
transform: translate(-50%, -50%);
background-image: url(./image.jpg); /* 鼠标图片 */
background-size: cover;
background-repeat: no-repeat;
}
3.监听并实时更新画布样式
// 判断当前画笔状态和页面事件监听状态,用于增强代码的兼容性
if (canvas.getContext && window.addEventListener) {
ctx = canvas.getContext("2d") // 获取canvas的上下文
updateSize() // 更新画布大小
window.addEventListener("resize", updateSize, false) // 监听窗口大小变化,重新设置画布大小和原点坐标
// TODO: 开启渲染
// TODO: 设置点击事件
} else {
console.log("对不起,您的浏览器不支持")
}
// 更新画布大小
function updateSize() {
canvas.width = window.innerWidth * 2 // canvas 宽
canvas.height = window.innerHeight * 2 // canvas 高
canvas.style.width = window.innerWidth + "px"
canvas.style.height = window.innerHeight + "px"
ctx.scale(2, 2) // 将画布放大2倍,绘制的所有东西都放大2倍
width = canvas.width = window.innerWidth
height = canvas.height = window.innerHeight
origin = {
x: width / 2,
y: height / 2
}
normal = {
x: width / 2,
y: height / 2
}
}
2. 生成烟花小球
1.准备小球类
class Ball {
x // x轴坐标
y // y轴坐标
angle // 弧度
multiplier // 倍数
vx // x轴速度
vy // y轴速度
r // 半径
color // 颜色
// 构造函数
constructor(x = origin.x, y = origin.y) {
// 设置位置
this.x = x
this.y = y
this.angle = Math.PI * 2 * Math.random() // 设置一个随机弧度
// 判断是否是长按状态
// TODO: 处理长按
this.multiplier = randBetween(6, 12) // 生成随机倍数
// 生成速度
this.vx = (this.multiplier + Math.random() * 0.5) * Math.cos(this.angle)
this.vy = (this.multiplier + Math.random() * 0.5) * Math.sin(this.angle)
this.r = randBetween(8, 12) + 3 * Math.random() // 生成随机半径
this.color = colours[Math.floor(Math.random() * colours.length)] // 生成随机颜色
}
update() {
this.x += this.vx - normal.x // 更新x轴坐标
this.y += this.vy - normal.y // 更新y轴坐标
normal.x = (-2 / window.innerWidth) * Math.sin(this.angle)
normal.y = (-2 / window.innerHeight) * Math.cos(this.angle)
this.r -= 0.3 // 缩小半径
// 减慢速度
this.vx *= 0.9 //
this.vy *= 0.9
}
}
2.开始绘制
if (canvas.getContext && window.addEventListener) {
...
loop() // 开始绘制 此时什么都没有绘制,只是开启了一个循环,只要balls有数据就会开始绘制
...
}
// 渲染函数
function loop() {
ctx.fillStyle = "rgba(255, 255, 255, 0)" // 设置画布背景色
ctx.clearRect(0, 0, canvas.width, canvas.height) // 清理画布内容
// 遍历所有小球
for (let i = 0; i < balls.length; i++) {
const b = balls[i] // 小球对象
if (b.r < 0) continue // 小球半径小于0,则进行绘制
ctx.fillStyle = b.color // 设置小球颜色
ctx.beginPath() // 开始绘制
// 在路径中添加一个圆,圆心在 (b.x, b.y),半径为 b.r,从0弧度开始,绘制一个完整的圆(Math.PI * 2 弧度),false 表示顺时针绘制
ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2, false)
ctx.fill() // 用当前的填充颜色填充路径,即填充球体。其实就是b.color
b.update() // 用球体对象的 update 方法,更新球体的状态,如位置、速度等
}
multiplier -= 0.4
// TODO: 处理长按
// TODO: 处理小球删除
requestAnimationFrame(loop) // 循环调用 loop 函数,实现动画效果
}
3.设置鼠标点击生成特效
// 鼠标按下事件
mousedown = function (e) {
pushBalls(randBetween(10, 20), e.clientX, e.clientY) // 添加小球,同时随机生成一个数量,同时设置鼠标点击位置为原点
// TODO: 处理长按
}
window.addEventListener("mousedown", mousedown, false)
function pushBalls(count = 1, x = origin.x, y = origin.y) {
for (let i = 0; i < count; i++) {
balls.push(new Ball(x, y)) // 添加小球
}
}
// 生成随机数
function randBetween(min, max) {
return Math.floor(Math.random() * max) + min
}
3.鼠标长按特效
1.设置小球长按增长倍数
class Ball {
...
constructor(...) {
// 判断是否是长按状态
if (longPressed == true) {
this.multiplier = randBetween(14 + multiplier, 15 + multiplier) // 生成随机倍数
} else {
this.multiplier = randBetween(6, 12) // 生成随机倍数
}
...
}
}
2.渲染时判断长按,生成更多的小球
function loop() {
...
// 判断是否是长按状态
if (longPressed == true) {
this.multiplier = randBetween(14 + multiplier, 15 + multiplier) // 生成随机倍数
} else {
this.multiplier = randBetween(6, 12) // 生成随机倍数
}
...
}
3.鼠标按下时循环生成更多小球
mouseup = () => {
...
if (longPressed == true) {
document.body.classList.remove("is-longpress") // 移除长按样式
pushBalls(randBetween(50 + Math.ceil(multiplier), 100 + Math.ceil(multiplier)), e.clientX, e.clientY) // 添加小球,同时随机生成一个数量,同时设置鼠标点击位置为原点
longPressed = false
}
...
}
4.鼠标弹起改变按压状态,开启特效
mouseup = function (e) {
clearInterval(longPress) // 清除长按事件计时器
if (longPressed == true) {
document.body.classList.remove("is-longpress") // 移除长按样式
pushBalls(randBetween(50 + Math.ceil(multiplier), 100 + Math.ceil(multiplier)), e.clientX, e.clientY) // 添加小球,同时随机生成一个数量,同时设置鼠标点击位置为原点
longPressed = false
}
document.body.classList.remove("is-pressed") // 移除鼠标按下样式
}
window.addEventListener("mouseup", mouseup, false)
4.清除小球**
function loop() {
...
removeBall() // 检察小球是否超出画布边界,如果超出则删除小球
...
}
function removeBall() {
for (let i = 0; i < balls.length; i++) {
const b = balls[i]
// 检察小球是否超出画布边界,如果超出则删除小球
if (b.x + b.r < 0 || b.x - b.r > width || b.y + b.r < 0 || b.y - b.r > height || b.r < 0) {
balls.splice(i, 1)
}
}
}
复制链接到抖音查看
8.92 Mjc:/ 01/09 t@r.EH 鼠标点击烟花特效 # 程序员 # 代码 # 前端 # canvas # 艺术在抖音 https://v.douyin.com/iSRSQQJ6/ 复制此链接,打开Dou音搜索,直接观看视频!