PERF: Animate request animation frame (#13337)

PERF: Animate request animation frame (#13337)

  • PERF: requestanimationframe for better performance on pan events
  • PERF: temporarily remove items on animate
diff --git a/app/assets/javascripts/discourse/app/components/site-header.js b/app/assets/javascripts/discourse/app/components/site-header.js
index b037a30..2830bca 100644
--- a/app/assets/javascripts/discourse/app/components/site-header.js
+++ b/app/assets/javascripts/discourse/app/components/site-header.js
@@ -87,6 +87,7 @@ const SiteHeaderComponent = MountWidget.extend(
       const menuPanels = document.querySelectorAll(".menu-panel");
       const menuOrigin = this._panMenuOrigin;
       menuPanels.forEach((panel) => {
+        panel.classList.remove("moving");
         if (this._shouldMenuClose(event, menuOrigin)) {
           this._animateClosing(panel, menuOrigin);
         } else {
@@ -129,6 +130,10 @@ const SiteHeaderComponent = MountWidget.extend(
       ) {
         e.originalEvent.preventDefault();
         this._isPanning = true;
+        const panel = document.querySelector(".menu-panel");
+        if (panel) {
+          panel.classList.add("moving");
+        }
       } else {
         this._isPanning = false;
       }
diff --git a/app/assets/javascripts/discourse/app/mixins/pan-events.js b/app/assets/javascripts/discourse/app/mixins/pan-events.js
index b40fd68..0134647 100644
--- a/app/assets/javascripts/discourse/app/mixins/pan-events.js
+++ b/app/assets/javascripts/discourse/app/mixins/pan-events.js
@@ -10,6 +10,7 @@ export default Mixin.create({
   //velocity is pixels per ms
 
   _panState: null,
+  _animationPending: false,
 
   didInsertElement() {
     this._super(...arguments);
@@ -71,9 +72,7 @@ export default Mixin.create({
     //calculate delta x, y, distance from START location
     const deltaX = e.clientX - oldState.startLocation.x;
     const deltaY = e.clientY - oldState.startLocation.y;
-    const distance = Math.round(
-      Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2))
-    );
+    const distance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
 
     //calculate velocity from previous event center location
     const eventDeltaX = e.clientX - oldState.center.x;
@@ -87,7 +86,7 @@ export default Mixin.create({
 
     return {
       startLocation: oldState.startLocation,
-      center: { x: Math.round(e.clientX), y: Math.round(e.clientY) },
+      center: { x: e.clientX, y: e.clientY },
       velocity,
       velocityX,
       velocityY,
@@ -102,7 +101,7 @@ export default Mixin.create({
 
   _panStart(e) {
     const newState = {
-      center: { x: Math.round(e.clientX), y: Math.round(e.clientY) },
+      center: { x: e.clientX, y: e.clientY },
       startLocation: { x: e.clientX, y: e.clientY },
       velocity: 0,
       velocityX: 0,
@@ -122,6 +121,7 @@ export default Mixin.create({
       this._panStart(e);
       return;
     }
+
     const previousState = this._panState;
     const newState = this._calculateNewPanState(previousState, e);
     if (previousState.start && newState.distance < MINIMUM_SWIPE_DISTANCE) {
@@ -137,7 +137,17 @@ export default Mixin.create({
     ) {
       this.panEnd(newState);
     } else if (e.type === "pointermove" && "panMove" in this) {
-      this.panMove(newState);
+      if (this._animationPending) {
+        return;
+      }
+      this._animationPending = true;
+      window.requestAnimationFrame(() => {
+        if (!this._animationPending) {
+          return;
+        }
+        this.panMove(newState);
+        this._animationPending = false;
+      });
     }
   },
 });
diff --git a/app/assets/stylesheets/mobile/menu-panel.scss b/app/assets/stylesheets/mobile/menu-panel.scss
index e3351ef..1e5f59d 100644
--- a/app/assets/stylesheets/mobile/menu-panel.scss
+++ b/app/assets/stylesheets/mobile/menu-panel.scss
@@ -27,12 +27,20 @@
 }
 
 .menu-panel.slide-in {
-  transform: translate(var(--offset), 0);
+  transform: translateX(var(--offset));
   @media (prefers-reduced-motion: no-preference) {
     &.animate {
       transition: transform 0.1s linear;
     }
   }
+  &.moving,
+  &.animate {
+    // PERF: only render first 20 items in a list to allow for smooth
+    // pan events
+    li:nth-child(n + 20) {
+      display: none;
+    }
+  }
 }
 
 .user-menu .quick-access-panel.quick-access-profile li:not(.show-all) {

GitHub sha: f12551afd329a7476e0f5d0eaf782e586fb0dc38

This commit appears in #13337 which was approved by pmusaraj. It was merged by featheredtoast.