]> git.sesse.net Git - remoteglot/commitdiff
Animate pieces using the Web Animation API.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 7 Sep 2023 16:36:25 +0000 (18:36 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 7 Sep 2023 16:36:25 +0000 (18:36 +0200)
This seemingly fixes our Chromium power saving issues.
Since we don't use all the new fanciness (e.g. fill mode),
it ends up being a bit icky, but no more than what we already had.

www/js/chessboard-0.3.0.js

index f69d0ed3802968a07c2ee533464565c82cb7a88e..24aa3da618d25cf3a9d27456aa3f09d53e2c825a 100644 (file)
@@ -608,77 +608,51 @@ function doAnimations(a, oldPos, newPos) {
 
   var numFinished = 0;
   function onFinish(e, opt_force) {
-    if (e && e.target) {
-      e.target.transitionProperty = null;
-      e.target.transitionDuration = null;
-    }
-
-    if (opt_force) {
-      // For whatever reason, the transition didn't seem to actually run
-      // (and thus, we didn't get an end event). Finish off now.
-      // (In particular, this seems to happen in Chrome if the tab is
-      // hidden and left alone for a while.)
-      if (numFinished == a.length) return;
-      numFinished = a.length;  // Make sure a very delayed later event will be ignored.
-    } else {
-      numFinished++;
-      if (numFinished !== a.length) return;
-    }
-
-    for (let piece of removed_pieces) {
-      piece.remove();
-    }
+    if (++numFinished === a.length) {
+      for (let piece of removed_pieces) {
+        piece.remove();
+      }
 
-    // run their onMoveEnd function
-    if (cfg.hasOwnProperty('onMoveEnd') &&
-      typeof cfg.onMoveEnd === 'function') {
-      cfg.onMoveEnd(deepCopy(oldPos), deepCopy(newPos));
+      // run their onMoveEnd function
+      if (cfg.hasOwnProperty('onMoveEnd') &&
+        typeof cfg.onMoveEnd === 'function') {
+        cfg.onMoveEnd(deepCopy(oldPos), deepCopy(newPos));
+      }
     }
   }
 
-  if (fadeout_pieces.length == 0 || fadein_pieces.length > 0 || move_pieces.length > 0) {
-    requestAnimationFrame(() => {  // Firefox workaround.
-      // Backup in case the transition never runs.
-      setTimeout(() => onFinish(null, true),
-                 cfg.appearSpeed + cfg.trashSpeed + cfg.moveSpeed + 100);
-
-      fadein_pieces.forEach((piece) => {
-        piece.style.opacity = 0;
-        piece.style.display = null;
-        piece.addEventListener('transitionend', onFinish, {once: true});
-      });
-      fadeout_pieces.forEach((piece) => {
-        piece.style.opacity = 1;
-        piece.style.display = null;
-        piece.addEventListener('transitionend', onFinish, {once: true});
-      });
-      for (const [piece, destination] of move_pieces) {
-        // Move it to the end of the stack, which changes the implicit z-index
-        // so that it will go on top of any pieces it's replacing.
-        piece.remove();
-        boardEl.appendChild(piece);
-        piece.addEventListener('transitionend', onFinish, {once: true});
-      }
-      requestAnimationFrame(() => {
-        fadein_pieces.forEach((piece) => {
-          piece.style.transitionProperty = 'opacity';
-          piece.style.transitionDuration = cfg.appearSpeed + 'ms';
-          piece.style.opacity = 1;
-        });
-        fadeout_pieces.forEach((piece) => {
-          piece.style.transitionProperty = 'opacity';
-          piece.style.transitionDuration = cfg.trashSpeed + 'ms';
-          piece.style.opacity = 0;
-        });
-        for (const [piece, destination] of move_pieces) {
-          let destSquarePosition = findSquarePosition(destination);
-          piece.style.transitionProperty = 'top, left';
-          piece.style.transitionDuration = cfg.moveSpeed + 'ms';
-          piece.style.top = destSquarePosition.top;
-          piece.style.left = destSquarePosition.left;
-        }
-      });
-    });
+  fadein_pieces.forEach((piece) => {
+    piece.style.display = null;
+    piece.style.opacity = 1;
+    piece.animate(
+      [ { opacity: 0 }, { opacity: 1 } ],
+      { duration: cfg.appearSpeed }
+    ).addEventListener('finish', onFinish);
+  });
+  fadeout_pieces.forEach((piece) => {
+    piece.style.display = null;
+    piece.style.opacity = 0;
+    piece.animate(
+      [ { opacity: 1 }, { opacity: 0 } ],
+      { duration: cfg.trashSpeed }
+    ).addEventListener('finish', onFinish);
+  });
+  for (const [piece, destination] of move_pieces) {
+    // Move it to the end of the stack, which changes the implicit z-index
+    // so that it will go on top of any pieces it's replacing.
+    piece.remove();
+    boardEl.appendChild(piece);
+
+    let destSquarePosition = findSquarePosition(destination);
+    piece.animate(
+      [
+        { top: piece.style.top, left: piece.style.left },
+        { top: destSquarePosition.top, left: destSquarePosition.left }
+      ],
+      { duration: cfg.moveSpeed }
+    ).addEventListener('finish', onFinish);
+    piece.style.top = destSquarePosition.top;
+    piece.style.left = destSquarePosition.left;
   }
 }
 
@@ -882,13 +856,15 @@ function snapbackDraggedPiece() {
   var sourceSquarePosition = findSquarePosition(DRAGGED_PIECE_SOURCE);
 
   // animate the piece to the target square
-  DRAGGED_PIECE.addEventListener('transitionend', complete, {once: true});
-  requestAnimationFrame(() => {
-    DRAGGED_PIECE.style.transitionProperty = 'top, left';
-    DRAGGED_PIECE.style.transitionDuration = cfg.snapbackSpeed + 'ms';
-    DRAGGED_PIECE.style.top = sourceSquarePosition.top;
-    DRAGGED_PIECE.style.left = sourceSquarePosition.left;
-  });
+  DRAGGED_PIECE.animate(
+    [
+      { top: DRAGGED_PIECE.style.top, left: DRAGGED_PIECE.style.left },
+      { top: sourceSquarePosition.top, left: sourceSquarePosition.left }
+    ],
+    { duration: cfg.snapbackSpeed }
+  ).addEventListener('finish', complete);
+  DRAGGED_PIECE.style.top = sourceSquarePosition.top;
+  DRAGGED_PIECE.style.left = sourceSquarePosition.left;
 
   // set state
   DRAGGING_A_PIECE = false;
@@ -933,13 +909,15 @@ function dropDraggedPieceOnSquare(square) {
   };
 
   // snap the piece to the target square
-  DRAGGED_PIECE.addEventListener('transitionend', complete, {once: true});
-  requestAnimationFrame(() => {
-    DRAGGED_PIECE.style.transitionProperty = 'top, left';
-    DRAGGED_PIECE.style.transitionDuration = cfg.snapSpeed + 'ms';
-    DRAGGED_PIECE.style.top = targetSquarePosition.top;
-    DRAGGED_PIECE.style.left = targetSquarePosition.left;
-  });
+  DRAGGED_PIECE.animate(
+    [
+      { top: DRAGGED_PIECE.style.top, left: DRAGGED_PIECE.style.left },
+      { top: targetSquarePosition.top, left: targetSquarePosition.left }
+    ],
+    { duration: cfg.snapSpeed }
+  ).addEventListener('finish', complete);
+  DRAGGED_PIECE.style.top = targetSquarePosition.top;
+  DRAGGED_PIECE.style.left = targetSquarePosition.left;
 }
 
 function beginDraggingPiece(source, piece, x, y) {
@@ -956,8 +934,6 @@ function beginDraggingPiece(source, piece, x, y) {
   DRAGGED_PIECE = PIECE_ON_SQUARE[source];
   DRAGGED_PIECE_SOURCE = source;
   DRAGGED_PIECE_LOCATION = source;
-  DRAGGED_PIECE.style.transitionProperty = null;
-  DRAGGED_PIECE.style.transitionDuration = null;
 
   // Move it to the end of the stack, which changes the implicit z-index
   // so that it will go on top of any pieces it's replacing.