简体   繁体   中英

how to make animation with javascript

I have a task to make animation with JavaScript.
Basically I have two squares (red and yellow) and a two buttons (button 1 and button 2).

When I click on button1 the red square goes from the (top-left corner) to the (bottom-right corner).

I need to make another button ( button2 ) such that when I click on it I need the red square to go back to the beginning.

I need it to do the opposite move (moving from the bottom-right corner to the top-left corner).

What changes should I do in the second function?

here is the code

 function myMove1() { var elem = document.getElementById("animate"); var pos = 0; var id = setInterval(frame, 5); function frame() { if (pos == 350) { clearInterval(id); } else { pos++; elem.style.top = pos + 'px'; elem.style.left = pos + 'px'; } } } function myMove2() { } 
 #container { width: 400px; height: 400px; position: relative; background: yellow; } #animate { width: 50px; height: 50px; position: absolute; background-color: red; } 
 <p> <button onclick="myMove1()">button 1</button> <button onclick="myMove2()">button 2</button> </p> <div id="container"> <div id="animate"></div> </div> 

I'm going to assume the teacher is trying to teach basic javascript, and tell you how I'd solve this with the parts you've provided.

That said, your commenters are correct, requestAnimationFrame is the right tool here. Also, the 5 ms delay on your interval is really short (125fps). If you made this number, I'd suggest changing it to 16, which is roughly 60fps.

  // We want each function to be able to see these vars. var pos = 0; // Either -1, 0, or 1, depending on if were moving forward, backwards or // stopped. var direction = 0; // This var now serves dual purpose, either its a number which is the // interval id or its falsy, which we can use to understand the animation // has stopped. var id = null; // Doing this here, will save the browser from having to redo this step on // each frame. var elem = document.getElementById("animate"); // Render the elem to the correct starting location. elem.style.top = pos + 'px'; elem.style.left = pos + 'px'; // A single animation function. function frame() { // Assume we are heading for 350. var goal = 350 if (direction < 0) { // unless the goal is -1, when the goal is zero. goal = 0 } if (pos != goal) { pos += direction; elem.style.top = pos + 'px'; elem.style.left = pos + 'px'; } else { // Reset all the shared vars. direction = 0; clearInterval(id); id = null; } } function myMove1() { if (id) { clearInterval(id) } direction = 1; id = setInterval(frame, 5); } function myMove2() { if (id) { clearInterval(id) } direction = -1; id = setInterval(frame, 5); } 
  #animate { position: absolute; width: 10px; height: 10px; background-color: red; } 
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <p> <button onclick="myMove1()">button 1</button> <button onclick="myMove2()">button 2</button> </p> <div id="container"> <div id="animate"></div> </div> </body> </html> 

What you're asking is straightforward: take the function you already wrote and change the increment direction on pos . The only difference is you'll need to keep track of x and y coordinates separately since they move in opposite directions. I used this object initialized to the start position of the box:

pos = {x: 350, y: 0};

 function myMove1() { var elem = document.getElementById("animate"); var pos = 0; var id = setInterval(frame, 5); function frame() { if (pos == 350) { clearInterval(id); } else { pos++; elem.style.top = pos + 'px'; elem.style.left = pos + 'px'; } } } function myMove2() { var elem = document.getElementById("animate"); var pos = {x: 350, y: 0}; var id = setInterval(frame, 5); function frame() { if (pos.y >= 350 || pos.x <= 0) { clearInterval(id); } else { pos.x--; pos.y++; elem.style.top = pos.y + 'px'; elem.style.left = pos.x + 'px'; } } } 
 #container { width: 400px; height: 400px; position: relative; background: yellow; } #animate { width: 50px; height: 50px; position: absolute; background-color: red; } 
 <p> <button onclick="myMove1()">button 1</button> <button onclick="myMove2()">button 2</button> </p> <div id="container"> <div id="animate"></div> </div> 

However, these functions aren't reusable without parameters; this code is WET (wrote everything twice). The animation is brittle because each click creates a new timeout (you can spam the buttons and watch it crumble). Entities in the animation have no state. If you want to change the position or add another box, you have to we-write and duplicate all of your code again.

With that in mind, here's a sketch to illustrate a somewhat improved version as food for thought. The functions and objects are more general and don't need to be re-written for new movements you decide to add. The Box class keeps track of entity state over time. requestAnimationFrame() is used to update and draw all entities on the screen at once, avoiding the many problems with setTimeout .

 const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1; const dist = (a, b) => ((ax - bx) ** 2 + (ay - by) ** 2) ** 0.5; class Box { constructor(elem, pos, size, color, speed) { this.elem = elem; this.speed = speed; this.from = this.to = this.pos = pos; this.t = 0; this.elem.style.position = "absolute"; this.elem.style.background = color; this.elem.style.height = `${size}px`; this.elem.style.width = `${size}px`; this.elem.style.top = `${this.pos.y}px`; this.elem.style.left = `${this.pos.x}px`; } move(to) { this.from = {x: this.pos.x, y: this.pos.y}; this.to = {x: to.x, y: to.y}; this.t = 0; } update() { if (dist(this.pos, this.to) > 1) { this.pos.x = lerp(this.from.x, this.to.x, this.t); this.pos.y = lerp(this.from.y, this.to.y, this.t); this.elem.style.top = `${this.pos.y}px`; this.elem.style.left = `${this.pos.x}px`; this.t += this.speed; } } } const data = [ {color: "red", pos: {x: 0, y: 0}, size: 10}, {color: "yellow", pos: {x: 350, y: 0}, size: 10}, ]; const elems = document.getElementsByClassName("box"); const boxes = []; for (let i = 0; i < elems.length; i++) { boxes.push(new Box(elems[i], data[i].pos, data[i].size, data[i].color, 0.01)); } function myMove1() { boxes[0].move({x: 350, y: 350}); boxes[1].move({x: 0, y: 350}); } function myMove2() { boxes[0].move({x: 0, y: 0}); boxes[1].move({x: 350, y: 0}); } (function render() { boxes.forEach(e => e.update()); requestAnimationFrame(render); })(); 
 <p> <button onclick="myMove1()">button 1</button> <button onclick="myMove2()">button 2</button> </p> <div id="container"> <div class="box"></div> <div class="box"></div> </div> 

Lastly, consider using CSS animations , JS canvas or an animation framework to do this sort of task; these tools will abstract away a lot of the math and state representation that animations involve.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM