javascript - 使用 mousedown 和 mouseup 的 Javascript 画布动画
问题描述
我有一个带有 88 个钢琴键的 html 表,页面的其余部分是画布。当用户单击钢琴键时,我正在尝试制作“SeeMusic”动画,即制作一个长度与用户按下鼠标时间相关的瓷砖。因此有两种可能性:
- Mousedown 处于活动状态:h(图块的高度)每帧增加 2
- 检测到 Mouseup:h 不再增加,并且 y(图块的 y 位置)每帧增加 2(使其看起来像是在下降)
对于我尝试创建的第一个图块,我的代码就像一个魅力,但问题来自下一个,它们的速度随着每个图块的创建而增加......有人知道问题出在哪里吗?
const canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
keys = document.querySelectorAll(".key")
document.querySelector(".keyboard").style.gridTemplateColumns = "repeat("+keys.length+", 1fr)"
canvas.width = window.innerWidth
canvas.height = window.innerHeight*0.8
// Variables
let tile,
particle,
tiles = [],
tileX,
tileWidth = keys[0].offsetWidth
class Tile {
constructor (x, y, h, dh, dy, c) {
this.x = x
this.y = y
this.h = h
this.c = c
this.dh = dh
this.dy = dy
}
Animate() {
this.h += this.dh
this.y += this.dy
window.addEventListener("mouseup", () => {
this.dh = 0
this.dy = 2
})
this.Draw()
}
Draw() {
ctx.beginPath()
ctx.fillStyle = this.c
ctx.fillRect(this.x, this.y, keys[0].offsetWidth, this.h)
ctx.closePath()
}
}
function SpawnTile() {
tiles.push(new Tile(tileX, 0, 0, 2, 0, "red"))
requestAnimationFrame(Update)
}
function Update() {
requestAnimationFrame(Update)
ctx.clearRect(0,0,canvas.width, canvas.height)
tiles.forEach(tile => {
tile.Animate()
})
}
keys.forEach(key => {
key.addEventListener("mousedown", () => {
tileX = key.getBoundingClientRect().left
SpawnTile()
})
})
*
{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body
{
height: 100vh;
width: 100vw;
background-color: white;
}
canvas
{
display: block;
margin: auto;
background-color: black;
height: 80%;
}
.keyboard
{
display: grid;
height: 20%;
position: relative;
border-bottom: solid 1px black;
background: radial-gradient(#fff, rgb(119, 119, 119));
}
.key
{
width: 100%;
position: relative;
}
.white {
background-color: transparent;
height: 100%;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.do::before, .fa::before
{
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 100%;
width: 100%;
background-color: transparent;
border-left: solid 1px black;
}
.do::after, .fa::after
{
content: '';
position: absolute;
bottom: 0;
left: 60%;
height: 35%;
width: 100%;
background-color: transparent;
border-right: solid 1px black;
}
.la::before
{
content: '';
position: absolute;
bottom: 0;
left: -50%;
height: 35%;
width: 100%;
background-color: transparent;
border-left: solid 1px black;
}
.la::after
{
content: '';
position: absolute;
bottom: 0;
left: 30%;
height: 35%;
width: 100%;
background-color: transparent;
border-right: solid 1px black;
}
.mi::before
{
content: '';
position: absolute;
bottom: 0;
left: -60%;
height: 35%;
width: 100%;
background-color: transparent;
border-left: solid 1px black;
}
.black
{
background-color: rgb(29, 28, 28);
height: 65%;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Canvas test</title>
</head>
<body>
<canvas></canvas>
<div class="keyboard">
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
</div>
<script src="main.js"></script>
</body>
</html>
解决方案
每次调用SpawnTile
函数时,都会开始新的Update
循环。它不是那样工作的,所有图块只需要一个动画循环。您可以在开始时初始化该循环,然后添加样式:
const canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
keys = document.querySelectorAll(".key")
document.querySelector(".keyboard").style.gridTemplateColumns = "repeat("+keys.length+", 1fr)"
canvas.width = window.innerWidth
canvas.height = window.innerHeight*0.8
// Variables
let tile,
particle,
tiles = [],
tileX,
tileWidth = keys[0].offsetWidth
class Tile {
constructor (x, y, h, dh, dy, c) {
this.x = x
this.y = y
this.h = h
this.c = c
this.dh = dh
this.dy = dy
}
Animate() {
this.h += this.dh
this.y += this.dy
window.addEventListener("mouseup", () => {
this.dh = 0
this.dy = 2
})
this.Draw()
}
Draw() {
ctx.beginPath()
ctx.fillStyle = this.c
ctx.fillRect(this.x, this.y, keys[0].offsetWidth, this.h)
ctx.closePath()
}
}
function SpawnTile() {
// just add tile to array
tiles.push(new Tile(tileX, 0, 0, 2, 0, "red"))
}
function Update() {
requestAnimationFrame(Update)
ctx.clearRect(0,0,canvas.width, canvas.height)
tiles.forEach(tile => {
tile.Animate()
})
}
// start update loop one time
requestAnimationFrame(Update)
keys.forEach(key => {
key.addEventListener("mousedown", () => {
tileX = key.getBoundingClientRect().left
SpawnTile()
})
})
*
{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body
{
height: 100vh;
width: 100vw;
background-color: white;
}
canvas
{
display: block;
margin: auto;
background-color: black;
height: 80%;
}
.keyboard
{
display: grid;
height: 20%;
position: relative;
border-bottom: solid 1px black;
background: radial-gradient(#fff, rgb(119, 119, 119));
}
.key
{
width: 100%;
position: relative;
}
.white {
background-color: transparent;
height: 100%;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.do::before, .fa::before
{
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 100%;
width: 100%;
background-color: transparent;
border-left: solid 1px black;
}
.do::after, .fa::after
{
content: '';
position: absolute;
bottom: 0;
left: 60%;
height: 35%;
width: 100%;
background-color: transparent;
border-right: solid 1px black;
}
.la::before
{
content: '';
position: absolute;
bottom: 0;
left: -50%;
height: 35%;
width: 100%;
background-color: transparent;
border-left: solid 1px black;
}
.la::after
{
content: '';
position: absolute;
bottom: 0;
left: 30%;
height: 35%;
width: 100%;
background-color: transparent;
border-right: solid 1px black;
}
.mi::before
{
content: '';
position: absolute;
bottom: 0;
left: -60%;
height: 35%;
width: 100%;
background-color: transparent;
border-left: solid 1px black;
}
.black
{
background-color: rgb(29, 28, 28);
height: 65%;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Canvas test</title>
</head>
<body>
<canvas></canvas>
<div class="keyboard">
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
<div class="key black reb"></div>
<div class="key white re"></div>
<div class="key black mib"></div>
<div class="key white mi"></div>
<div class="key white fa"></div>
<div class="key black solb"></div>
<div class="key white sol"></div>
<div class="key black lab"></div>
<div class="key white la"></div>
<div class="key black sib"></div>
<div class="key white si"></div>
<div class="key white do"></div>
</div>
<script src="main.js"></script>
</body>
</html>
推荐阅读
- javascript - 为网络创建自定义 Rxjs Observable
- java - 如何将 SpringBoot (.war) 应用程序部署到 Cloud Run?
- sql - 如何根据条件在 SQL 中创建多行
- javascript - 如何使用 cypress 导入夹具文件
- json - 打开 Refine 多词分类
- aws-iot - AWS IoT 设备开发工具包和 AWS IoT 设备客户端之间的区别
- r - 如何最好地设计多节点/多核计算过程
- python - 张量和张量的区别
- redis - Redis 哨兵节点在故障转移后无法同步
- java - 充气城堡:多个 PGPSignature 在同一时间范围内相同(约 1 秒)