1 2 Previous Next 15 Replies Latest reply: Oct 8, 2010 8:03 AM by 567740 RSS

    kinetic Scrolling

    843807
      Does someone has an example how to create knetic scrolling lists and images like on iPhone?
      I'm creating a software to use with a touchscreen display.

      thanks
        • 1. Re: kinetic Scrolling
          Darryl Burke
          Are touch screen events the same as mouse pressed / dragged / released? If so, you can use a MouseListener and MouseMotionListener along with with getvisibleRect() and scrollRectToVisible(...). Here's a handler I threw together:
          import java.awt.Point;
          import java.awt.Rectangle;
          import java.awt.event.MouseAdapter;
          import java.awt.event.MouseEvent;
          import javax.swing.JComponent;
          import javax.swing.SwingUtilities;
          
          public class DragScrollHandler extends MouseAdapter {
          
            private JComponent component;
            private Point pressed, here;
            private Rectangle visiRect;
          
            public DragScrollHandler(JComponent component) {
              this.component = component;
              component.addMouseListener(this);
              component.addMouseMotionListener(this);
            }
          
            public static void createDragScrollHandlerFor(JComponent component) {
              new DragScrollHandler(component);
            }
            
            public void dispose() {
              component.removeMouseListener(this);
              component.removeMouseMotionListener(this);
            }
          
            @Override
            public void mousePressed(MouseEvent e) {
              pressed = e.getPoint();
              visiRect = component.getVisibleRect();
            }
          
            @Override
            public void mouseDragged(MouseEvent e) {
              here = e.getPoint();
              visiRect.x += (pressed.x - here.x);
              visiRect.y += (pressed.y - here.y);
              component.scrollRectToVisible(visiRect);
              SwingUtilities.invokeLater(new Runnable() {
          
                public void run() {
                  Rectangle newRect = component.getVisibleRect();
                  pressed.x += newRect.x - visiRect.x;
                  pressed.y += newRect.y - visiRect.y;
                  visiRect = newRect;
                }
              });
            }
          }
          db
          • 2. Re: kinetic Scrolling
            843807
            This code works and help-me a lot! But I expected the scrolling effect (inertia) as we can see on iphone. Dou you know how to do it?

            thanks a lot
            • 3. Re: kinetic Scrolling
              Darryl Burke
              I expected the scrolling effect (inertia)
              I've never tried anything like that but I would expect you might need to make use of a physics library or write your own.

              db
              • 4. Re: kinetic Scrolling
                843807
                danielbrocco wrote:
                Dou you know how to do it?
                I am no expert in Swings but have an idea to show the intertia effect. Suppose the user scrolled for say X pixels, scroll the view in addition by, say, X/10 pixels programatically. For example if the user has scrolled 50 pixels, scroll 10 more pixels in the same direction; and dont scroll all of the 10 pixels at a time, but scroll one pixel at a time with a delay of say 50 milli seconds.
                If you more closely want to give mimic the inertia effect, scroll each of these ten pixels with increasing delays; something like scroll first pixel after 50 millis delay, next pixel after 100 milli seconds of delay and so on.

                To truly mimic the inertia effect you might want to get into the fundamentals of physics like DarrylBurke has suggested.

                As I said, I am no expert in Swings, I once read an article programatically scrolling in swings, so this should be verymuch feasible if you give a try in those lines.
                • 5. Re: kinetic Scrolling
                  Darryl Burke
                  if the user has scrolled 50 pixels, scroll 10 more pixels in the same direction
                  There's more to it than that. Have you actually used a touch screen device that has this feature? I have.

                  -- The 'inertia' effect is only seen if you drag and release while still moving and is dependent not on the distance scrolled, but on the drag velocity at the moment of release. This would require a continual computation of the magnitude and direction of drag velocity, probably best done with the help of a Timer.
                  -- The 'deceleration' is visibly non-linear, being more rapid just after release. Hence my suggestion for a physics engine.
                  -- If the resulting movement makes the component scroll 'too far', it 'bounces' back. This would be even more tricky to implement.

                  An alternative, simplified scheme might be to continue to scroll the component with the same velocity as at the moment of release, until halted by reaching the limit of its boundaries or another mousePressed. Here's an implementation that does that.
                  import java.awt.Point;
                  import java.awt.Rectangle;
                  import java.awt.event.ActionEvent;
                  import java.awt.event.ActionListener;
                  import java.awt.event.MouseAdapter;
                  import java.awt.event.MouseEvent;
                  import javax.swing.JComponent;
                  import javax.swing.SwingUtilities;
                  import javax.swing.Timer;
                  
                  public class DragScrollHandler extends MouseAdapter {
                  
                    private JComponent component;
                    private Point pressedPoint, draggedPoint, lastPoint;
                    private Rectangle visiRect;
                    private Timer timer;
                    private boolean pressed;
                    private int deltaX, deltaY;
                  
                    public DragScrollHandler(JComponent c) {
                      component = c;
                      c.addMouseListener(this);
                      c.addMouseMotionListener(this);
                  
                      timer = new Timer(50, new ActionListener() {
                  
                        public void actionPerformed(ActionEvent e) {
                          if (pressed) {
                            deltaX = draggedPoint.x - lastPoint.x;
                            deltaY = draggedPoint.y - lastPoint.y;
                            lastPoint = new Point(draggedPoint);
                          } else {
                            visiRect.x -= deltaX;
                            visiRect.y -= deltaY;
                            component.scrollRectToVisible(visiRect);
                            SwingUtilities.invokeLater(new Runnable() {
                  
                              public void run() {
                                final Rectangle newRect = component.getVisibleRect();
                                if (newRect.x != visiRect.x && newRect.y != visiRect.y) {
                                  timer.stop();
                                }
                              }
                            });
                          }
                        }
                      });
                    }
                  
                    public static void createDragScrollHandlerFor(JComponent component) {
                      new DragScrollHandler(component);
                    }
                  
                    public void dispose() {
                      component.removeMouseListener(this);
                      component.removeMouseMotionListener(this);
                      timer.stop();
                    }
                  
                    @Override
                    public void mousePressed(MouseEvent e) {
                      pressed = true;
                      pressedPoint = e.getPoint();
                      draggedPoint = e.getPoint();
                      lastPoint = e.getPoint();
                      timer.start();
                      visiRect = component.getVisibleRect();
                    }
                  
                    @Override
                    public void mouseDragged(MouseEvent e) {
                      draggedPoint = e.getPoint();
                      visiRect.x += (pressedPoint.x - draggedPoint.x);
                      visiRect.y += (pressedPoint.y - draggedPoint.y);
                      component.scrollRectToVisible(visiRect);
                      SwingUtilities.invokeLater(new Runnable() {
                  
                        public void run() {
                          Rectangle newRect = component.getVisibleRect();
                          pressedPoint.x += newRect.x - visiRect.x;
                          pressedPoint.y += newRect.y - visiRect.y;
                          visiRect = newRect;
                        }
                      });
                    }
                  
                    @Override
                    public void mouseReleased(MouseEvent e) {
                      pressed = false;
                    }
                  }
                  db
                  • 6. Re: kinetic Scrolling
                    843807
                    DarrylBurke wrote:
                    if the user has scrolled 50 pixels, scroll 10 more pixels in the same direction
                    There's more to it than that. Have you actually used a touch screen device that has this feature? I have.
                    Yes I did, but did not want to put all of the mechanics out in the first post :) I was not sure whether the idea I've presented is correct or not. It seems to be a reasonable.
                    -- The 'inertia' effect is only seen if you drag and release while still moving and is dependent not on the distance scrolled, but on the drag velocity at the moment of release.
                    Exactly, so we first need to compute the velocity with which the user has scrolled. Suppose, 100 pixels were scrolled in 10 seconds by the user. So the velocity would be distance/ time; in this case it would be number of pixels scrolled/ time. Swings should be able to derive this.
                    This would require a continual computation of the magnitude and direction of drag velocity, probably best done with the help of a Timer.
                    I dont think continuous compuation is required, we'll have to compute the velocity only when dragged. I dont know if it can be identified in the current context that the screen is being scrolled/ dragged. Once this drag is stopped, the program should drag some more distance, and stop with a deceleration.
                    -- The 'deceleration' is visibly non-linear, being more rapid just after release.
                    So, now it is to be derived howmuch distance should be further scrolled to mimic the inertia effect before comming to a halt. Like you said, decelaration is anyhow present, but if the application is developed using fixed deceleration, then it might take 2 sec to stop when scrolled gently, and 20 sec when scrolled harshly. So, it is best to absorb the inertia within a given time, say 2 sec. This means that once the user drags and leaves, the screen would stop in 2 sec with the inertia effect. And one more point is deceleration should not be non linear, deceleration would be constant; else a jerk would be experienced. For example, if you continuously vary the pressure on your break pad, that would be an illustration of non linear deceleration, and we feel jerks in motion. A real physics expert (use physics engine as already suggested) is required with so many parameters varying. Why not sacrifice some perfection and assume constant deceleration? It would be hardly 15 to 30 pixels motion that should exhibit the inertia effect.
                    I'll try to do some homework and come up with formula here.
                    Hence my suggestion for a physics engine.
                    -- If the resulting movement makes the component scroll 'too far', it 'bounces' back. This would be even more tricky to implement.
                    I think that would be required if developing some game on that touch screen, but is a nice to have feature though.
                    • 7. Re: kinetic Scrolling
                      Darryl Burke
                      DynamicBasics wrote:
                      DarrylBurke wrote:
                      if the user has scrolled 50 pixels, scroll 10 more pixels in the same direction
                      There's more to it than that. Have you actually used a touch screen device that has this feature? I have.
                      Yes I did, but did not want to put all of the mechanics out in the first post :) I was not sure whether the idea I've presented is correct or not. It seems to be a reasonable.
                      -- The 'inertia' effect is only seen if you drag and release while still moving and is dependent not on the distance scrolled, but on the drag velocity at the moment of release.
                      Exactly, so we first need to compute the velocity with which the user has scrolled. Suppose, 100 pixels were scrolled in 10 seconds by the user. So the velocity would be distance/ time; in this case it would be number of pixels scrolled/ time. Swings should be able to derive this.
                      This would require a continual computation of the magnitude and direction of drag velocity, probably best done with the help of a Timer.
                      I dont think continuous compuation is required, we'll have to compute the velocity only when dragged. I dont know if it can be identified in the current context that the screen is being scrolled/ dragged. Once this drag is stopped, the program should drag some more distance, and stop with a deceleration.
                      I don't agree. Consider an extreme case where the user holds the mouse button down for several seconds, then moves it fast and releases the button while still moving. Your algorithm would result in an unintuitive slow additional movement.
                      -- The 'deceleration' is visibly non-linear, being more rapid just after release.
                      So, now it is to be derived howmuch distance should be further scrolled to mimic the inertia effect before comming to a halt. Like you said, decelaration is anyhow present, but if the application is developed using fixed deceleration, then it might take 2 sec to stop when scrolled gently, and 20 sec when scrolled harshly. So, it is best to absorb the inertia within a given time, say 2 sec. This means that once the user drags and leaves, the screen would stop in 2 sec with the inertia effect.
                      Fixing the 'glide' time doesn't mimic inertia too well.
                      And one more point is deceleration should not be non linear, deceleration would be constant; else a jerk would be experienced. For example, if you continuously vary the pressure on your break pad, that would be an illustration of non linear deceleration, and we feel jerks in motion.
                      Nope. If you hold down the brake pedal right until the vehicle stops, that will cause a jerk at the moment of stopping. For a smooth halt, any seasoned driver actually releases the pedal gradually as the vehicle slows down, so that the braking/deceleration is actually very low just before stopping.
                      A real physics expert (use physics engine as already suggested) is required with so many parameters varying. Why not sacrifice some perfection and assume constant deceleration? It would be hardly 15 to 30 pixels motion that should exhibit the inertia effect.
                      Agreed that too much striving for perfection for this triviality would be overkill. However, many physics engines (never used one, just guessing here) probably expose an API that makes it simple.
                      I'll try to do some homework and come up with formula here.
                      Looking forward to that!
                      Hence my suggestion for a physics engine.
                      -- If the resulting movement makes the component scroll 'too far', it 'bounces' back. This would be even more tricky to implement.
                      I think that would be required if developing some game on that touch screen, but is a nice to have feature though.
                      My Samsung i8000 phone has that feature. However, I find both the 'inertia' and 'bouncing' to be a pain ;-) and I would turn it off if I could do that without reverting to a clunky GUI (WinMobile)

                      @OP: On further thought, I would expect the touchscreen device to natively provide this functionality to all applications, much as most laptop touchpads provide inertial scrolling when the 'scrollbar' part is released while moving OR touched-dragged to an edge of the touchpad.

                      Thanks for the discussion.

                      db
                      • 8. Re: kinetic Scrolling
                        Kleopatra
                        can't add much, just a link:

                        http://www.pushing-pixels.org/?p=1593

                        that's part of Kirill's series about animation physics earlier this year. No code, though, couldn't nudge him into ;-)

                        CU
                        Jeanette
                        • 9. Re: kinetic Scrolling
                          843807
                          What you want is a constant jerk - that may sound wrong, but it's only because jerk has been used in this thread in layman's terms and not as what the physics definition implies. Jerk is the rate of change of acceleration. With a constant (negative) jerk, you'll get the smooth slow to a stop as db has described.

                          The velocity, acceleration, and jerk are all related as derivatives. The velocity is the 1st derivative of position wrt time, acceleration is the 2nd derivative of position wrt time, and jerk is the 3rd derivative of position wrt time.

                          So you want:
                          jerk = a
                          where a is an unknown coefficient, therefore:
                          acceleration = a * t + b
                          
                          velocity = a * t * t / 2 + b * t + c
                          
                          position = a * t * t * t / 6 + b * t * t / 2 + c * t + d
                          You can define position to be 0 where the finger/mouse stops "dragging", the velocity can simply be calculated by tracking the position upon each dragged event and the time between each event (hint: MouseEvent.getWhen()) and the acceleration can be tracked similarly by calculating the difference between velocity and the said time interval. You can define the jerk to be whatever you like (well, as long as what you like is negative). And now it is just a simply algebra problem solving for a, b, c, and d.

                          Good Luck.
                          • 10. Re: kinetic Scrolling
                            843807
                            Aephyr wrote:
                            What you want is a constant jerk
                            I'm sorry, but I'm currently not available.

                            Seriously though, I though of myself as being well-versed in physics, but I've never heard of jerk use in this context before, and find it interesting: [Wikipedia: Jerk (physics)|http://en.wikipedia.org/wiki/Jerk_%28physics%29]

                            The article even mentions the "Jerk-Meter", something I hope my wife never purchases.

                            Aephyr: thanks for the education!
                            • 11. Re: kinetic Scrolling
                              843807
                              Aephyr wrote:
                              What you want is a constant jerk -
                              Yes, nothing but constant deceleration, to further complicate things, I thought integral would be required; but I'll stick to my non complicated version :) It should not be tough though. To keep the problem simple for now, let us assume constant deceleration (but if more true physics is to be ensured, I think [with my wague knowledge of integrals] this quickly becomes second degree integral equation)

                              and here is what I came up with.
                              v = u+at
                              where 
                              v = final velocity, 
                              u = initial velocity
                              a = acceleration,
                              t = time.
                              
                              If deceleration is to be used, the formula becomes
                              v = u - at
                              Suppose user scrolled 100 pixels in 10 sec and left the scrollbar the final velocity would be
                              velocity = s/t where 
                              s = displacement (number of pixes scrolled)
                              t = time taken to scroll.
                              velocity = 100/10 = 10 pixels per second.
                              User has just left the scrollbar and so now the scroll should decelerate. - Now this 10 pixels per second would become initial velocity, and final velocity would be ZERO. Here is the approximation that I'm making I'll assume constant deceleration. suppose +5 pixels per second square+ again with
                              v=u-at
                              0=10-5t
                              t = 2 seconds.
                              So the scroll should stop in 2 seconds once the user has left the scroll bar.
                              Now we'll have to derive the number of pixles to be scrolled in these 2 seconds
                              s = ut+(1/2)at^2
                              s - displacement (number of pixes to be scrolled). 
                              u - initial velocity (10 pixels per second)
                              s = 10*2+(1/2)*5*2^2
                                = 20+10
                                = 30 (pixels)
                              So, once the user has left the scrollbar, the scroll should last for 2 seconds and should cover 30 pixels in 2 seconds. This means that (30/2) i.e. 15 pixels per second, or 2 pixels per 100 milliseconds, or 1 pixel per 50 milli seconds for this approximate inertia effect to appear smooth.

                              A seasoned driver might put off the pressure on the break pedal to have a smooth final stop so that we in the car do not feel the inertia in turn; it might not be required here, as this cascading inertia effect would not be visible on the current view port of the scroll pane (I think I've used the correct teminology); again it is a nice-to-have feature.
                              DarrylBurke wrote:
                              I don't agree. Consider an extreme case where the user holds the mouse button down for several seconds, then moves it fast and releases the button while still moving. Your algorithm would result in an unintuitive slow additional movement.
                              and you said the answer too! feed the algorithm with only that time during which the user was last scrolling.

                              Edited by: DynamicBasics on Aug 16, 2010 9:34 AM
                              Corrected math for calculating the displacement.
                              • 12. Re: kinetic Scrolling
                                843807
                                DarrylBurke wrote:
                                And one more point is deceleration should not be non linear, deceleration would be constant; else a jerk would be experienced. For example, if you continuously vary the pressure on your break pad, that would be an illustration of non linear deceleration, and we feel jerks in motion.
                                Nope. If you hold down the brake pedal right until the vehicle stops, that will cause a jerk at the moment of stopping.
                                What we feel just before stopping is inertia.
                                For a smooth halt, any seasoned driver actually releases the pedal gradually as the vehicle slows down, so that the braking/deceleration is actually very low just before stopping.
                                To keep the inertia force as low as possible.

                                Jerk would be felt if we are, say, bouncing our foot on the break pedal while in motion. Current context does not have this inertia effect. I mean, the elements on the screen need not/ will not exhibit this inertia effect. So, even if the deceleration is violent/ smooth elements on the screen have no relation with it. So, assuming constant deceleration is not that bad approximation :)
                                And the alogorithm suggested does not have fixed time to stop, based on the drag speed of the end user, the distace to stop and time to stop are varying.
                                • 13. Re: kinetic Scrolling
                                  843807
                                  DynamicBasics wrote:
                                  A seasoned driver might put off the pressure on the break pedal to have a smooth final stop so that we in the car do not feel the inertia in turn; it might not be required here, as this cascading inertia effect would not be visible on the current view port of the scroll pane (I think I've used the correct teminology); again it is a nice-to-have feature.
                                  Or maybe it might not be a nice feature. Come to think of it, a slow stopping scroll is probably quite annoying. When I hit the arrow or page keys on the keyboard, I would not be too pleased if it took several seconds for the scroll to finally settle. Comparison to a car stop is probably the wrong way to think about it. Constant deceleration is probably good enough. Though I would calculate the velocity as I described earlier. The only velocity that matters is the velocity at the very end - not the average velocity of the entire drag.
                                  • 14. Re: kinetic Scrolling
                                    843807
                                    Aephyr wrote:
                                    When I hit the arrow or page keys on the keyboard, I would not be too pleased if it took several seconds for the scroll to finally settle.
                                    The math illustration above suggests that if 10 sec is scrolled, the inertia effect would be for 10 pixels 2 seconds. The arrow key scrolling would be 3 pixels (setting in windows XP control panel) say in 500 milli seconds; I guess (without the math) that it should stop in <50 milliseconds. This should be acceptable. One immediate illustration of the same would be trying to scroll in IE browser with smooth scrolling turned on versus turned off. The inetia effect would not be that irritating for the down arrow key.
                                    Comparison to a car stop is probably the wrong way to think about it.
                                    It was just an attempt to understand the long forgotten physics terminology :)
                                    Though I would calculate the velocity as I described earlier. The only velocity that matters is the velocity at the very end - not the average velocity of the entire drag.
                                    Does this account non linear deceleration?
                                    1 2 Previous Next