Is there a design pattern for dealing with overlapping UI actions and animations? A few examples:

  1. Let's say I have an interactive table row that expands to reveal an extra control when the user clicks on it, and vice versa if they click on it again. If the user clicks on the row while the expand animation is in progress, I want it to stop animating and shrink back to its original size from the place where it stopped.
  2. I have a set of rows from example 1 inside a group. When the last row is deleted, I want the group to shrink and then remove itself in a callback. However, while the group is shrinking, the user could still add another row to it. If that happens, I want the group to stop shrinking, expand to the correct size, and add the row.
  3. What if I have a sorting function for the UI in example 2? If the user clicks on the sort button, the rows shuffle and animate into their new positions. However, I still want the user to be able to click on table rows, delete rows, and do everything else that my UI allows. The UI should behave sensibly, with the shuffle animation taking precedence.

You could automatically fast-forward all animations for a UI element when a new action is performed on it, and/or block user input in all animating UI elements. But that seems inelegant to me. As a user, I really admire UIs that don't stutter or block me from doing what I want — UIs, in other words, that behave like real objects — and I'd like to do the same in my own applications.

It seems to me that you'd need to have constraints for each action/animation in order to make this a robust system. For example, you might need to ensure that any changes to your data/state/model happen only in the callback to your animation, not before. In example 2, you can't delete the group in your model as soon as the user clicks the button to delete the last row; it has to be done at the end of the animation, and at the end of the animation only. (Otherwise, if the user decides to add another row during the delete animation, reverting the group delete would be very difficult.) You might also need to design the animation system in such a way that if two animations from two different actions overlap, any mutually exclusive properties would continue animating as before. (In other words, if the user sorts the table while a row is expanding on click, the width expansion should not stop just because the row is moving to its new position.) And what about starting defaults for each animation? If a row fades out when deleted, and then another action implicitly cancels the delete, the fade out should stop and animate back in, even though the other action might not necessarily know about it.

There's also the higher-level issue of animations (visual property changes) vs. actions (sequences of events, with potential model changes, that include animations). In example 2, "delete last row" is clearly an action, since the end result is that a group gets removed. However, in most UI libraries, you'd add the callback to the animation, conflating the two. This is also an issue in games. If I need to trigger a grenade throw after my character's throw animation finishes, how do I represent that in my code? How do I place the grenade throw on my timeline without mixing model and view code, while still allowing the animation to slow down and speed up based on external factors?

The more I think about this, the more my head hurts, and the more I'm convinced that somebody has already thought this through a lot more carefully than me. Any ideas?

(At the moment, I'm mostly interested in this for web UI, but I'm also interested in a general approach for my future, non-web projects.)

  • The user's going to be the fastest this side of the Mississipi, in order to manipulate rows while animated :) – rucamzu Feb 9 '14 at 17:59
  • Yeah, in most cases, this isn't an issue. But that 1% is still really important. I often find myself annoyed at UIs that won't let me do anything while a view is finishing up its transition animation, for instance. Having a robust and well-abstracted action/animation system would also automatically fix a lot of edge-case bugs related to simultaneous user actions, and just tidy up our mental model of the code in general. – Archagon Feb 10 '14 at 1:30

You do want to attach animations to table rows while keeping their interaction capabilities untouched. A decorator fits in here: it'll manage the animation, while forwarding user interaction events to the decorated object. Note that the animation by itself isn't important here, and it'd suffice for it to be a (mere) parameter of the decorator object (thus letting us to reuse the same decorator class with arbitrary animations). Also, this way you can have an arbitrary number of animations simultaneously active over the same row, just by nesting decorators; the visual result is another story :)

If we take a step back and look for the big picture, though, even from the point of view of the user interface animations are only details -if well more or less tricky to deal with, and definitely of great relevance in order to provide a good user experience. But they aren't the focus. A generic scheme could be like this:

  1. The user asks the system for an action to be performed, by means of whatever predefined input event.
  2. The system schedules the user's command. Immediate execution should not be assumed here, unless explicit requirement.
  3. The system executes the user's command, and this takes an arbitrary amount of time and tasks (between whom animations can be counted) to be performed. Here, the system can (begin to) execute commands sequentially or concurrently, depending an the scheduler and the dependencies between the requested actions.

Design Patterns

As Rucamzu mentions a decorator pattern seems to fit. A visitor pattern seems like it also might fit as the object that runs the animation visits the DOM element multiple times throughout the course of an animation to update a DOM elements properties/styling to create the visual change.

Post spelling out the differences between the patterns.

Implementation within a Web UI (assuming JS/CSS/HTML)

There are several libraries that feature concurrent/successive asynchronous operation queuing. What to typically look for(in whatever target client one is programming for) should include:

  1. provide chaining functionality (helpful for move the player arm then throw the grenade)
  2. firing events/callbacks on a very granular level and also on a group based level (to know when the arm finishes and when the grenade animation finishes and when the grenade lands so that one can run the damage calculations and then)
  3. reverse their single actions or group actions (helpful for your open/close animations)

There's a couple of libraries that I could consider.

  1. Greensock TweenMax/TimelineMax
    Greensock has one of the most robust animation packages out there. It has options for being lightweight and paired back or full blown with its numerous plugins (and somewhere in between). TweenMax allows for single animations and TimelineMax allows for the more advanced chaining/sequences.
  2. CreateJS
    If there's crazy animation it might be best off being done using canvas. There's a library that has 2d tweening capabilities that can be backed by WebGL if a browser has it. Also supports sprite sheeting for more in-depth animations.
  3. Implementation as jQuery Deferred objects/promises.
    Deferred objects can take an arbitrary time to succeed. Most AJAX requests in jQuery implement the deferred objects for success and fail. Also these actions can be immediate as well. This helps for chaining multiple animations and function calls and asynchronous operations. I don't believe that Deferred's can reverse their operations nor can they be rerun again, new instances need to be created, but can be extremely powerful.

Selection will probably be based on how intense the animations need to be as well as the browsers and devices that need to be supported.

Web UI implementation recommendation

Even though you aren't probably building a flash project, they have been known for complicated animation in their day. The top two items above have roots from the flash world of things, so they've been around for more than a few years. I've implemented almost every flash project for a 6 year period with Greensock's library. His documentation is solid and there's plenty of examples too: Greensock JS getting started.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.