# Canvas 2D Web Apps/Transitions

This chapter extends the chapter on pages by adding animated transition effects between pages (“transitions” for short). To this end, it also relies on the animation system introduced in the chapter on animations.
The implementation is encapsulated in a function with many arguments. Thus, on the one hand, it is possible to implement a wide range of transitions just by changing the arguments without even looking at the implementation of the function; on the other hand, it might be difficult to understand the meaning of all the arguments and how to use them to implement certain effects. Therefore, a list of 24 implementations of popular transitions is included below. Furthermore, a few guidelines about how to design and choose transitions in web apps are also presented.

### The Example

The example of this chapter (which is available online; also as downloadable version) adds four animated transition effects to the transitions between three pages. The following sections will discuss how to use the functions to create these transitions and how these functions were implemented. See the chapters on pages, animations and responsive buttons for other parts.

### Using Transitions

In order to initiate a transition between two pages, the function cuiPlayTransition has to be called. In the example, an animated transition between the first and the second page is started this way:
The appearance of the transition is completely controlled be the 19 arguments of cuiPlayTransition, which are discussed in the next section.

### Configuring Transitions

The function cuiPlayTransition(previousPage, nextPage, isPreviousOverNext, isFrontMaskAnimated, animationInitialSpeed, animationFinalSpeed, animationLength, previousFinalPositionX, previousFinalPositionY, previousFinalScaleX, previousFinalScaleY, previousFinalRotation, previousFinalOpacity, nextInitialPositionX, nextInitialPositionY, nextInitialScaleX, nextInitialScaleY, nextInitialRotation, nextInitialOpacity) configures everything about a transition — including the timing and the appearance of the transition. The arguments are:
* previousPage: the cuiPage object of the previous page; the transition is from the previous page to the next page
* nextPage: the cuiPage object of the next page
* isPreviousOverNext: whether the previousPage is rendered over the nextPage or vice versa; one possibility has to be chosen for the whole transition
* isFrontMaskAnimated: whether an opacity mask of the page in front is animated instead of the page itself (if isPreviousOverNext is true then previousPage is the page in front, otherwise it is nextPage); animation of an opacity mask is useful mainly for wipe transitions
* animationInitialSpeed: initial speed of change of the animated values at the beginning of the transition; 0.0 for slow start, 1.0 for linear interpolation, larger values for faster start; since a cubic Hermite curve is used for interpolation, larger values than about 3 can result in overshoots
* animationFinalSpeed: final speed of change of the animated values at the end of the transition (see animationInitialSpeed)
* animationLength: duration of the transition in seconds (usually, this should be at most 0.25; in some cases 0.33 might be OK; longer durations are likely to annoy at least expert users on mobile devices)
* arguments specifying the final appearance of the previousPage at the end of the transition (the initial appearance is always the same):
** previousFinalPositionX and previousFinalPositionY: final position of the center of previousPage where the left/top edge of the screen is specified by -1 and the right/bottom edge by +1, thus, the center of the screen is at 0. (The initial position is always (0,0); i.e., previousPage is initially centered.)
** previousFinalScaleX and previousFinalScaleY: final scale factors for width and height of previousPage. (The initial scaling is always 1; i.e., initially there is no scaling.)
** previousFinalRotation: final clockwise rotation of previousPage in degrees. (The initial rotation is always 0; i.e., there is no rotation.)
** previousFinalOpacity: final opacity of previousPage. (The initial opacity is always 1; i.e., the page is completely opaque.)
* arguments specifying the initial appearance of the nextPage at the beginning of the transition (the final appearance is always the same):
** nextInitialPositionX and nextInitialPositionY: initial position of the center of nextPage where the left/top edge of the screen is specified by -1 and the right/bottom edge by +1, thus, the center of the screen is at 0. (The final position is always (0,0); i.e., nextPage is finally centered.)
** nextInitialScaleX and nextInitialScaleY: initial scale factors for width and height of nextPage. (The final scaling is always 1; i.e., initially there is no scaling.)
** nextInitialRotation: initial clockwise rotation of nextPage in degrees. (The final rotation is always 0; i.e., there is no rotation.)
** nextInitialOpacity: initial opacity of nextPage. (The final opacity is always 1; i.e., the page is completely opaque.)
Since it is not easy to find suitable values, the following list contains examples of calls to cuiPlayTransition for popular transition effects. Each effect has a reverse effect, which should be used for the transition between the same pages in the opposite order:
The maximize and minimize transition should use the method transformPageToTransitionCoordinates of cuiPage to compute suitable coordinates for cuiPlayTransition from the (page) coordinates that are used to position buttons etc.
Many of the transitions and their names might be familiar to you from software for slide presentations. Actually, the included transitions tend to be the more subtle transitions offered by this kind of software. Most apps on mobile devices, on the other hand, rely almost exclusively on this kind of transitions. Some of the reasons for this are discussed in the next section about guidelines for choosing and designing transitions.

### Choosing and Designing Transitions

It is easy to annoy users with transitions by deterring, disorienting, and/or distracting users. Make sure you don't. At the very least, users should prefer your transition compared to instantly cutting from one page to another. (This is not as easy as it might sound.) Here is a check list to avoid annoying transitions:
* make them quick: don't deter users from whatever they want to do on the next page (there has to be a good reason if a transition takes longer than about 1/4 second; there has to be a very good reason (e.g., you are sure the user wants it) if a transition takes longer than about 1/3 second; make sure to test your transition on the smallest applicable display because the smaller size will result in lower physical velocities; thus, the transition will appear slower)
* make them consistent: don't disorient users by
** inconsistencies between transitions of the same type (e.g. transitions to the next (or previous) page in a list, transitions to a page on a lower (or higher) level of a hierarchical structure, transitions to (or from) dialog boxes, etc.)
** inconsistencies between the transition from page A to page B and the transition from page B back to page A (they should be visually reversed unless a transition is its own reverse transition, e.g. dissolve)
** inconsistencies between a transition and the position of the user action that activated it (e.g. if a click or touch on a graphical element at the right edge of the screen activated the transition, then the main direction of the transition should be from right to left — whatever kind of transition is used)
** inconsistencies between a transition and the gesture that activated it (e.g. a flick in one direction should result in a transition in the same direction without ease-in but with ease-out)
* make them subtle: don't distract users from the content of the pages (which should be more important than any transition); remember that users see the same transitions over and over again (at least if you use them consistently); thus, transitions can grow old very quickly even if they were fun to watch the first 40 times.
This is just to avoid annoying transitions that deter, disorient, and/or distract users. In addition, good transitions should be meaningful and communicate information:
    4. use transitions to communicate as much as possible:
      * communicate the relation between the pair of pages (e.g. use push transitions in appropriate directions in order to communicate that two pages are neighbors in a list)
      * communicate the type of one or both pages (e.g. reserve cover from top to bottom for notifications or dialog boxes)
      * communicate the structure in which the pages are organised (e.g. use push up/down to move on the same level in a hierarchy and push left/right to move up or down in the hierarchy)
      * communicate the function of pages (e.g. use transitions from film (in particular dissolve and wipe) for telling a story; or use maximize to provide detail information about a certain location)
      * communicate the type and position of the user action that has activated the transition (e.g. use a push transition in a similar direction as the flick gesture that activated it)
And as always with design guidelines: break them if you have a good reason.

### Implementing Transitions

This section discusses the implementation of the two functions cuiPlayTransition and cuiDrawTransition in cui2d.js. cuiDrawTransition is called by the process function of a special page in the global variable cuiPageForTransitions. The function cuiPlayTransition performs four main tasks:
* If necessary, it creates a canvas for the previous page and a canvas for the next page.
* Then it stores a snapshot of the previous page in one canvas and a snapshot of the next page in the other canvas.
* Furthermore, it sets the properties of the global variable cuiAnimationForTransitions for the animated transition.
* Lastly, it starts the animation, specifies to ignore events until its end, and requests a repaint of the canvas.
To understand the code, you should know that the 12 animated values in the 2 keyframes are: previousPositionX, previousPositionY, previousScaleX, previousScaleY, previousRotation, previousOpacity, nextPositionX, nextPositionY, nextScaleX, nextScaleY, nextRotation, nextOpacity. The values of the previous page of the 1st keyframe and the values of the next page of the 0th keyframe are specified by the user while the rest are default values, which specify that the previous page starts without any changes in the 0th keyframe and the next page ends without any changes in the 1st keyframe. The code is:
The actual rendering of the animation is performed by cuiDrawTransition. First, it computes the animated values with animateValues and extracts the 12 animated parameters. Depending on isPreviousOverNext it then either renders the canvas of the previous page over the canvas of the next page or vice versa. (Since we use the composite operation "destination-over" the front page has to be rendered first.) If isFrontMaskAnimated is false, the front page is rendered directly (with drawImage), otherwise an animated mask is rendered (with fillRect) and the static front page is rendered only in the region of the mask by using the composite operation "source-in". (Animated masks are useful for wipe transitions.) The animation of the canvases and the masks is mainly achieved by the animated value of the opacity and by geometric transformations which use the animated values as parameters. Lastly, cuiDrawTransition checks whether the transition is complete and in that case it sets cuiCurrentPage to nextPage and requests a repaint.
If you look at the code, you will notice that there is a lot of repetition, and in fact, it is possible to shorten the code significantly; however, it's left in this long form for the sake of readability.
< Canvas 2D Web Apps