首页 > 解决方案 > 使用 mousedown 和 mouseup 的 Javascript 画布动画

问题描述

我有一个带有 88 个钢琴键的 html 表,页面的其余部分是画布。当用户单击钢琴键时,我正在尝试制作“SeeMusic”动画,即制作一个长度与用户按下鼠标时间相关的瓷砖。因此有两种可能性:

对于我尝试创建的第一个图块,我的代码就像一个魅力,但问题来自下一个,它们的速度随着每个图块的创建而增加......有人知道问题出在哪里吗?

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>

标签: javascriptanimationcanvasmouseevent

解决方案


每次调用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>


推荐阅读