]> source.dussan.org Git - vaadin-framework.git/commitdiff
Use requestAnimationFrame when scrolling in Grid (#20294)
authorArtur Signell <artur@vaadin.com>
Sun, 18 Sep 2016 20:00:58 +0000 (23:00 +0300)
committerArtur Signell <artur@vaadin.com>
Tue, 20 Sep 2016 07:14:22 +0000 (07:14 +0000)
Chrome no longer (since version 5x) always fire deferred commands
immediately during scrolling but can delay them with several hundred
milliseconds, making grid really unresponsive.

So far, nobody has been able to provide a reliable test case.

Change-Id: Ide80aef2d661c9e27b67c8e62e85734af7a38cab

client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java

index 7443b5d31578dd712e0666e7d77653c984788d85..c8bc8462e9f16eb80510a4ca5fd4c07c944d5310 100644 (file)
@@ -16,6 +16,9 @@
 
 package com.vaadin.client.widget.escalator;
 
+import com.google.gwt.animation.client.AnimationScheduler;
+import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
+import com.google.gwt.animation.client.AnimationScheduler.AnimationSupportDetector;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.dom.client.Element;
@@ -47,12 +50,14 @@ import com.vaadin.client.widget.grid.events.ScrollHandler;
  * @see HorizontalScrollbarBundle
  */
 public abstract class ScrollbarBundle implements DeferredWorker {
+    private static final boolean supportsRequestAnimationFrame = new AnimationSupportDetector()
+            .isNativelySupported();
 
     private class ScrollEventFirer {
+
         private final ScheduledCommand fireEventCommand = new ScheduledCommand() {
             @Override
             public void execute() {
-
                 /*
                  * Some kind of native-scroll-event related asynchronous problem
                  * occurs here (at least on desktops) where the internal
@@ -92,7 +97,23 @@ public abstract class ScrollbarBundle implements DeferredWorker {
                  * We'll gather all the scroll events, and only fire once, once
                  * everything has calmed down.
                  */
-                Scheduler.get().scheduleDeferred(fireEventCommand);
+                if (supportsRequestAnimationFrame) {
+                    // Chrome MUST use this as deferred commands will sometimes
+                    // be run with a 300+ ms delay when scrolling.
+                    AnimationScheduler.get()
+                            .requestAnimationFrame(new AnimationCallback() {
+                                @Override
+                                public void execute(double timestamp) {
+                                    fireEventCommand.execute();
+
+                                }
+                            });
+                } else {
+                    // Does not support requestAnimationFrame and the fallback
+                    // uses a delay of 16ms, we stick to the old deferred
+                    // command which uses a delay of 0ms
+                    Scheduler.get().scheduleDeferred(fireEventCommand);
+                }
                 isBeingFired = true;
             }
         }
@@ -894,7 +915,10 @@ public abstract class ScrollbarBundle implements DeferredWorker {
 
     @Override
     public boolean isWorkPending() {
+        // Need to include scrollEventFirer.isBeingFired as it might use
+        // requestAnimationFrame - which is not automatically checked
         return scrollSizeTemporaryScrollHandler != null
-                || offsetSizeTemporaryScrollHandler != null;
+                || offsetSizeTemporaryScrollHandler != null
+                || scrollEventFirer.isBeingFired;
     }
 }