Tengo una imagen que quiero mover una cierta distancia (siempre la misma) y una cierta dirección (especificada en una matriz) con cada clic del mouse. El primer clic lo mueve en la dirección especificada en el primer elemento de la matriz, el segundo en el segundo y así sucesivamente.
Esto funciona bien a menos que le pida que se mueva en la misma dirección dos veces seguidas. En ese caso, se mueve instantáneamente a la posición final sin animación, como si hubiera comenzado la animación allí, aunque el depurador muestra la ubicación, definida por unitElement.style.left como correspondiente correctamente a su apariencia en pantalla.
El HTML, con cuatro transformaciones y una imagen para mover:
<style> .unit { width: 60px; height: 60px; position: absolute; } @keyframes N {100% {transform: translate(0px, -60px);}} @keyframes E {100% {transform: translate(60px, 0px);}} @keyframes S {100% {transform: translate(0px, 60px);}} @keyframes W {100% {transform: translate(-60px, 0px);}} </style> <body> <img src="test.png" class="unit" id="F1" /> </body>La función que se llama en el evento de clic:
function nextPulseAnimate() { pulse++; for(var index = 0; index < units.length; index++) { var unit = units[index]; var direction = unit.moves[pulse-1] var unitElement = document.getElementById(unit.name); //ensure that the image is starting from the right place unitElement.style.left = unit.start.x; unitElement.style.top = unit.start.y; unitElement.style.animation = direction + " 2s ease-in-out forwards"; } //then re-set the locations ready for next pulse //If this is not done, each animation will start from the unit's original location for(var index = 0; index < units.length; index++) { var unit = units[index]; var direction = unit.moves[pulse-1] switch (direction){ case "N": unit.start.y -= 60; break; case "E": unit.start.x += 60; break; case "S": unit.start.y += 60; break; case "W": unit.start.x -= 60; break; } } }La "unidad" a la que se hace referencia en la función se deriva de una matriz global de objetos que se ve así (en la práctica, tendrá un par de docenas de elementos):
units = [ {name: "F1", start: {x: 0, y: 0}, moves: ["S", "E", "E", "E"]} ];Para completar, hay otra variable global definida (y utilizada anteriormente): pulso = 0
Esto es lo que quiero decir:
units = [{name: "F1", start: { x: '0px', y: '0px'}, moves: ["S", "E", "E", "N", "W", "W"] }, { name: "F2", start: { x: '120px', y: '60px' }, moves: ["N", "W", "W", "S", "E", "E"] } ]; var pulse = 0; function init() { document.body.addEventListener("click", nextPulseAnimate); for (var index = 0; index < units.length; index++) { var unit = units[index]; var unitElement = document.getElementById(unit.name); unitElement.style.left = unit.start.x; unitElement.style.top = unit.start.y; unitElement.addEventListener('animationend', (event) => { document.body.addEventListener("click", nextPulseAnimate); var e = event.target; /* get position relative to viewport */ var r = e.getBoundingClientRect(); e.style.left = r.left + 'px'; e.style.top = r.top + 'px'; /* remove animation so that you can use it again */ e.style.animation = 'none'; }); } } function nextPulseAnimate() { pulse++; if (pulse < 7) { document.getElementById('stats').innerText = 'Moves: ' + pulse + '/6'; //don't let user click while animation is going on document.body.removeEventListener('click', nextPulseAnimate); } for (var index = 0; index < units.length; index++) { var unit = units[index]; var direction = unit.moves[pulse - 1] var unitElement = document.getElementById(unit.name); unitElement.style.animation = direction + " 2s ease-in-out forwards"; } } body { width: 90vw; height: 90vh } p { position: fixed; top: 40vh; } .unit { width: 60px; height: 60px; position: absolute; } @keyframes N {100% {transform: translate(0px, -60px);}} @keyframes E {100% {transform: translate(60px, 0px);}} @keyframes S {100% {transform: translate(0px, 60px);}} @keyframes W {100% {transform: translate(-60px, 0px);}} <!DOCTYPE html> <html> <body onload="init()"> <img src="https://dummyimage.com/60x60/000/fff.jpg" class="unit" id="F1" /> <img src="https://dummyimage.com/60x60/a0a/fff.jpg" class="unit" id="F2" /> <p id=stats>Click anywhere to trigger moves</p> </body> </html>