Adding a Simple Loading Spinner

Adding a Simple Loading Spinner

In the previous chapter, we implemented an online synchronization function. The only visual feedback we had was an info banner telling us the process was successful. But what about during the process itself? For example, if we have thousands of records to synchronize, it will take some time before this process is done. In this case, it would be nice to have some visual feedback during the synchronization, like a loading spinner.

In the old-fashioned way, you would use a semitransparent animated GIF and control it with some JavaScript. The downside of this approach is that it requires an extra resource with a limited number of frames (to keep the image size as small as possible), which reduces the smoothness of the animation; and, because the image is semitransparent with its hardcoded foreground and background color, you also add a dependency to the application’s color chart. If you decide to change the background color of your application, you also have to generate your animated GIF again.

For these reasons, we won’t use an image; instead, we’ll “draw” and animate the spinner using CSS3 animations and transitions. The spinner will consist of 12 bars rotating around an axis and fading out. Let’s first define the main spinner style:

div.spinner {

position: absolute; top: 50%; left:70%; margin: -100px 0 0 -100px; height: 54px; width: 54px; text-indent: 250px; white-space: nowrap; overflow: hidde;

} Then we define the inner div style. Here, we set the common styles that will be shared

by all the bars. Basically, we create a bar by styling a div, playing with the corner radius and shadow properties. We also attach an animation to a bar—a fade animation that will

be defined later. div.spinner div {

width: 12%; height: 26%; background: #000; position: absolute; left: 50%; top: 50%; opacity: 0; -webkit-animation: fade 1s linear infinite; -webkit-border-radius: 50px; -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.2);

} Finally, we define the 12 bars that will be used in the animation, increasing the rotation

angle for each of them by 30 degrees using the –webkit-transform:rotate attribute. The fade effect, combined with a different start delay using the –webkit-animation-delay attribute for each bar, will create the illusion of a rotation effect.

CHAPTER 6: Competing with Native Apps

div.spinner div.bar1 { -webkit-transform:rotate(0deg) translate(0, -142%); -webkit-animation-delay: 0s; }

div.spinner div.bar2 { -webkit-transform:rotate(30deg) translate(0, -142%); -webkit-animation-delay: 0.9176s; }

[..] div.spinner div.bar12 {

-webkit-transform:rotate(330deg) translate(0, -142%); -webkit-animation-delay: -0.0833s; }

We also define our fade animation: @-webkit-keyframes fade {

from {opacity: 1;} to {opacity: 0.25;}

} Before we try out the spinner, let’s introduce some new CSS3 selectors: -webkit-animation: Defines the name of your animation, which will be

declared in a separate style block starting with @-webkit-keyframes. Notice the values that follow the name of the animation: we have a duration value, a transition-timing function that defines how the animation should proceed over the duration (here we are using a linear function, but there are a lot of different options—ease-in, ease-out, etc.), and finally a value defining the animation’s frequency (the animation will run infinitely in our case).

-webkit-transform: Can transform any HTML element. Its possible values are translate, rotate, and scale. Notice that you can chain transform values like we did in the previous code sample—we first rotate the div and translate it to the upper-left corner to make it rotate around an axis.

-webkit-animation-delay-count: Defines the delay before your animation starts. This is useful when you want to chain a lot of different animations, like our 12 bars.

NOTE: A linear transition function will time your animation equally over the duration you provide; for example, if you are moving an image by 200 pixels with a duration of 2 seconds, after 1 second your image will have moved by 100 pixels. But maybe there are situations where you want to have another type of timing, like rotating an image very slowly in the beginning and finishing with a fast rotation.

To be able to test our loading spinner, we have to add a div containing all the bars’ divs on the main page:

CHAPTER 6: Competing with Native Apps

<div id="spinner">

<div class="bar1"></div> <div class="bar2"></div> <div class="bar3"></div> <div class="bar4"></div> <div class="bar5"></div> <div class="bar6"></div> <div class="bar7"></div> <div class="bar8"></div> <div class="bar9"></div> <div class="bar10"></div> <div class="bar11"></div> <div class="bar12"></div>

</div> Refresh your application and you will see the loading spinner, as shown in Figure 6–1.

Figure 6–1. Displaying a loading spinner on the main view This is a good first step, but we only want to see the spinner when we are

synchronizing—not all the time, even if it’s a beautiful spinner. It should appear at the moment we press the Synchronize button and disappear when we show the info banner displaying that the process was successful. To do this, we update the main spinner style with display:none; and we control the container visibility with some JavaScript.

The best place to hook in is probably the synchronizeOnline function; we set the visibility of the spinner container to true when entering the function and revert it to false just before we exit the function:

CHAPTER 6: Competing with Native Apps

function synchronizeOnline () { $(“spinner”). .show(); [...] $(“spinner”). .hide();

} That’s all we have to do. Notice the handy jQuery’s hide and show functions, which

encapsulate some CSS manipulation for us.