16.3. One-Second MotionCopy, Displace, Duplicate, Jump, Leap, Move, Movement, Motion, Rearrange, Transfer Figure 16-7. One Second Motion16.3.1. Goal StoryBill is adding a new monthly bank order. The existing orders are shown in the usual wayas a table with one row per order, sorted by cost. Once he is verified the new order form, it morphs to become a table row, then slowly drifts down the table. It soon reaches its rightful place in the sorted table, which is ordered by amount, and comes to rest after bouncing up and down a little due to reverberation. 16.3.2. ProblemHow can you communicate that an element is shifting from one position to another? 16.3.3. Forces
16.3.4. SolutionIncrementally move an element from one location to another, or temporarily move it, to communicate that an event has occurred. In most cases, the motion of the element involves a permanent change in its position. It can also be used to show a temporary displacement or gesture, such as a vibration effect. There are several benefits of showing the motion explicitly:
The effect combines Page Rearrangement (Chapter 5) with Scheduling (Chapter 7). A loop runs for the duration of progresses, with each transition occurring perhaps once every 50 milliseconds. Each transition will likely involve a gradual change to the positioning style settings, usually to top and left. The position style can be set as absolute or relative, depending on the overall application design. When an element has to move from point A to point B, in most cases it's logical for the trajectory to be the shortest distance from A to B, i.e., for the element to move as the crow flies. The algorithm in this case uses interpolationfor example, one-quarter of the time into the effect, an element will be one-quarter of the way between A and Bso, when moving from left to right, the left style of the element will be (0.25*x(A) + 0.75*x(B)), where x( ) represents the source and destinations' horizontal coordinate. This assumes a linear interpolation. You can also experiment with other algorithms, e.g., you might like to accelerate the element as it proceeds, which is often a more realistic model. Note that you probably won't have to hand code motion, because libraries like Scriptaculous (discussed in the "Real-World Examples") are quite flexible and usually easy to incorporate into typical scripts. 16.3.5. Decisions16.3.5.1. What events will trigger a motion effect?One-Second Motion is not very common (yet), but there are several potential applications. First, a permanent movement can show any of the following:
A temporary movement has its own applications:
Since motion can be distracting, you will likely want to limit its usage to the following situations:
Also consider whether you should use motion at all. The conventional wisdom is that motion is more natural as a transition because it's based on the physical world. But how about the massive population that grew up with computers and might be perfectly comfortable with the sudden jumps that are only possible in a digital realm? Maybe not everyone will appreciate motion effects. 16.3.5.2. What will the element do when it reaches its destination?In every example I've seen, the element stops suddenly at its destination. However, it might appear more natural if the element reverberates when stacked against another element. 16.3.6. Real-World Examples16.3.6.1. Scriptaculous libraryAs mentioned in One-Second Spotlight (see earlier in this chapter), Scriptaculous is a general-purpose JavaScript library. The visual effects demo (http://script.aculo.us/visual-effects) supports motion-based effects. 16.3.6.2. TiddlyWikiAs detailed in One-Second Mutation (see earlier in this chapter), clicking on a TiddlyWiki Microlink (Chapter 15; see http://tiddlywiki.com) causes the entire content to "leap out" from the link and form in a new position. 16.3.6.3. Backbase PortalThe Backbase Portal Demo (http://projects.backbase.com/RUI/portal.html) contains a page full of Portlets (Chapter 15) arranged in three columns, each with its own menu. The menu contains all of the Portlets on the page, and choosing a Portlet causes it to move over to the top of the column. One-Second Motion is used to animate the Portlet's movement, allowing users to see that thePortlet has "flown in" to the top of a column from elsewhere on the page. 16.3.6.4. DHTML LemmingsAs detailed in Sprite (Chapter 15), DHTML Lemmings involves the movement of Lemming creatures through a game space. Each Lemming is represented as a DOM element. 16.3.6.5. MS-WindowsMS-Windows uses a form of One-Second Motion. When minimizing a window, the whole window appears to leap downward to its handle in the taskbar, like a large object being packed into a small container. The reverse process occurs upon activating the window. This is not an Ajax App, but is still significant, as it's frequently cited as a rationale for the kind of animation this pattern details. 16.3.7. Code Example: Scriptaculous EffectsMotion is one of the effects offered by the Scriptaculous effects library (http://script.aculo.us/visual-effects). Examining its implementation gives us an opportunity to look at the overall Scriptaculous effects engine, which also provides One-Second Spotlight- and One-Second Mutation-style effects.[*]
The generic engine component controls the flow by continuously delegating to an individual effect object to perform an incremental animation. This is an example of the Strategy pattern (Gamma et al., 1995). The initialization sequence clears the frame count, computes the total effect time, and kicks off the loop: start: function(options) { ... this.currentFrame = 0; this.startOn = new Date().getTime( ); this.finishOn = this.startOn + (this.options.duration*1000); ... if(!this.options.sync) this.loop( ); } The loop runs until the predicted finish time, at which point the animation cleans up and terminates. The most important thing here is the pos calculation, which determines how far along the animation is. The calculation is essentially timeSoFar/timeRemaining. So, one-quarter of the way through the animation, it will be 0.25. Next, a calculation takes place to support the fps option, which lets the caller state the maximum number of animation frames per second. If an animation is indeed required, the engine's render( ) function is called: loop: function( ) { var timePos = new Date().getTime( ); if(timePos >= this.finishOn) { this.render(1.0); ... return; } var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); frame = Math.round(pos * this.options.fps * this.options.duration); if(frame > this.currentFrame) { this.render(pos); this.currentFrame = frame; } this.timeout = setTimeout(this.loop.bind(this), 10); }, The main purpose of render( ) is to delegate to the effect strategy to perform the update. The strategy will receive a value between 0 and 1 to tell it how far the animation has proceeded. The MoveBy effect takes a DOM element and tracks its start and end positions. The element's style is set to relative using a call to the effect engine's makePositioned( ) function. Because positioning is relative, you construct a MoveBy effect with relative arguments. To move an object 5 right and 10 down, you'd pass in 5 and 10 as parameters. The effect is to increase left by 5 and top by 10: initialize: function(element, toTop, toLeft) { this.originalTop = parseFloat(this.element.style.top || '0'); this.originalLeft = parseFloat(this.element.style.left || '0'); this.toTop = toTop; this.toLeft = toLeft; Element.makePositioned(this.element); ... } Remember that the effects engine delegates to update( ) for effect-specific behavior, passing in a progress ratio between 0 and 1. In the case of MoveBy, the algorithm performs the necessary interpolation calculation to see how far along the object should be (topd and leftd). Having made the calculation, all that remains is to update the DOM element's style: update: function(position) { topd = this.toTop * position + this.originalTop; leftd = this.toLeft * position + this.originalLeft; this.setPosition(topd, leftd); }, setPosition: function(topd, leftd) { this.element.style.top = topd + "px"; this.element.style.left = leftd + "px"; } The MoveBy effect in itself is useful for getting an object from A to B. But you can build on it to create effects such as motion displacements. One such effect, included in the Scriptaculous library, is Shake( ), which swings an element left and right a few times. With the framework in place, the effect is easily defined as a sequence of moves: Effect.Shake = function(element) { return new Effect.MoveBy(element, 0, 20, { duration: 0.05, afterFinish: function(effect) { new Effect.MoveBy(effect.element, 0, -40, { duration: 0.1, afterFinish: function(effect) { new Effect.MoveBy(effect.element, 0, 40, { duration: 0.1, afterFinish: function(effect) { ... } 16.3.8. Alternatives16.3.8.1. One-Second Spotlight and One-Second MutationOne-Second Spotlight and One-Second Mutation (see both earlier in this chapter) are also used to draw attention to a significant event. One-Second Motion is suited for indicating that an object's state has changed in the case where there is some geometric mapping to each object's state. When used as a temporary displacement effect, One-Second Motion is sometimes an alternative to these other patterns. 16.3.9. Related Patterns16.3.9.1. SpriteA Sprite (Chapter 15) often undergoes motion similar to One-Second Motion and can make use of similar interpolation calculations. 16.3.9.2. GuesstimateIn some cases, the motion is a form of Guesstimate (Chapter 13). When an object is moving around according to state information, the motion effect is effectively an estimate of what's happening between positions. 16.3.10. MetaphorUntil "Beam Me Up" teleportation technology hits the markets, every visible movement in the physical world is an illustration of this pattern. |