Chapter 11

Special Effects and Animation

WHAT YOU WILL LEARN IN THIS CHAPTER:

  • Creating gradients using CSS and JavaScript
  • Adding shadows and reflections
  • Creating animations with JavaScript

The strengths of Safari on IOS as a development platform are evident when you begin to explore the capabilities you have with advanced graphics, animation, and other special effects. You can utilize some of the more advanced capabilities of JavaScript, HTML 5, and CSS to create cool effects in your web apps. In this chapter, I explore how to work with effects and animation.

GRADIENTS

A gradient is a coloring effect you can add to your web page in which a color gradually changes to another color over the surface of a canvas or other element. A linear gradient is applied to a rectangular block surface whereas a radial gradient is displayed as a circle. You can specify the start and end colors as well as color values in between (known as color stops). You can create gradients in both CSS and JavaScript. Read on to find out how.

Creating CSS Gradients

You can use the Safari-supported function -webkit-gradient() to create a “virtual” gradient image and define it as an image URL parameter. Here’s the syntax for a linear gradient:

-webkit-gradient(linear, startPoint, endPoint, from(color),
  color-stop(percent, color), to(color))

The linear parameter defines the type of gradient. The startPoint and endPoint parameters define the start and end points of the gradient and are typically represented by constants: left top, left bottom, right top, right bottom.

The from() and to() functions indicate the starting and ending colors, and the color-stop() function defines a color at a particular point on the gradient.

For example, the following style can be added to a div or other block element to create a gradient that starts with light green at the top left and ends with black on the lower left. A color stop of dark green is added at the 50% mark. Here’s the style:

  .simpleLinear
  {
    width:100px;
    height:100px;
    border:1px solid black;
    background: -webkit-gradient( linear, left top, left bottom,
     from(#a1f436), color-stop(0.5, #668241), to(rgb(0, 0, 0)));
    }

As you can see, the color can be defined using a hex value or using the rgb() function.

The results are shown in Figure 11-1.

You can add multiple color-stop() functions to a gradient to have more complex effect. The following style begins with maroon and ends with white, but also has green and blue color stops defined at the 30% and 80% points along the gradient (see Figure 11-2):

  .complexLinear
  {
    width:100px;
    height:100px;
    border:1px solid black;
    background: -webkit-gradient(linear, left top, left bottom,
    from(#a21c47), to(#f9f9f9), color-stop(0.3, #564fb5),color-stop(0.8, #66cc00));
  }

To create a radial gradient, you use the following syntax:

-webkit-gradient(radial, innerCenter, innerRadius, outerCenter,
   outerRadius, from(color), color-stop(percent, color), to(color));

The innerCenter defines the x, y coordinate of the center of the inner circle that starts the gradient. The innerRadius defines the width of the radius for the inner circle. The outerCenter and outerRadius define the same thing for the outer circle that ends the gradient. The from(), to(), and color-stop() functions work the same way as the linear gradient.

The following style example defines a small gradient 10-radial circle starting at coordinates 30, 30 and ending with a 30-radial circle at coordinates 50, 50. It has one color stop, midway through the gradient (see Figure 11-3):

  .radial
  {   
    width:100px;
    height:100px;
    border:1px solid black;
    background: -webkit-gradient(radial, 30 30, 10, 50 50, 30,
      from(#a1f436), to(rgba(1,0,0,0)), color-stop(50%, #668241));
  }

You can also combine multiple gradients onto a single surface simply by listing one after the other. The following style example defines two radial gradients for a 200 × 200-sized div:

.radial2
  {   
    width:200px;
    height:200px;
    border:1px solid black;
    background: -webkit-gradient(radial, 20 20, 10, 25 25, 40, from(#a1f436),
     to(rgba(1,0,0,0)), color-stop(50%, #668241)),
     -webkit-gradient(radial, 100 100, 20, 20 20, 40,
      from(#a21c47), to(#f9f9f9), color-stop(50%, #66cc00));
  }

The result is a cone-like object as shown in Figure 11-4.

Creating Gradients with JavaScript

If you prefer scripting, you can also create both linear and radial gradients by using the following methods of the context object:

  • createLinearGradient(x1,y1,x2,y2) creates a gradient from the starting point (x1,y1) to the end point (x2, y2).
  • createRadialGradient(x1,y1,r1,x2,y2,r2) creates a gradient circle. The first circle is based on the x1, y1, and r1 values and the second circle based on the x2, y2, and r2 values.

Both of these methods return a canvasGradient object that can have colors assigned to it with the addColorStop(position, color) method. The position argument is a float number between 0.0 and 1.0 that indicates the position of the color in the gradient. The color argument is any CSS color.

TRY IT OUT: Creating a JavaScript Gradient

The following is an example of creating a gradient using JavaScript.

1. Create the following HTML document in your text editor and then save the document as BIDHJ-Ch11-Ex1.html.

image
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Draw Gradient</title>
<meta name="viewport" content="width=320; initial-scale=1.0;
   maximum-scale=1.0; user-scalable=0;">
</head>
<body>
<canvas id="myCanvas" width="300" height="300"
   style="position:absolute; left:0px; top:0px; z-index:1"/>
</body>
</html>

Code snippet BIDHJ-Ch11-Ex1.html

2. Add the following JavaScript code inside the document head:

image
<script type="application/x-javascript">
function drawGradient()
{
  var canvas = document.getElementById('myCanvas'),
  var context = canvas.getContext('2d'),
  var lg = context.createLinearGradient(0,125,250,125);
  context.globalAlpha="0.8";
  lg.addColorStop(0,'white'),
  lg.addColorStop(0.75,'blue'),
  lg.addColorStop(1,'red'),
  context.fillStyle = lg;
  context.strokeStyle="#666666";
  context.lineWidth=".5";
  context.fillRect(10,10,250,250);
  context.strokeRect(10,10,250,250);
}
</script>

Code snippet BIDHJ-Ch11-Ex1.html

3. Add an onload event handler to the body tag and save the file:

image
<body onload="drawGradient ()">

Code snippet BIDHJ-Ch11-Ex1.html

How It Works

A linear gradient is added to a square box on the canvas. The gradient starts on the left side, transitions to blue, and ends on the right in red. The first color stop is set to white, the second is set to blue, and the third is red. After you assign the color stops using the addColorStop() method, you assign the lglinearGradient object as the fillStyle for the context. You then call the fillRect() method to paint the block and add a gray border using the strokeRect() method. Figure 11-5 shows the results.

Now that you have linear gradients under your belt, you can create radial gradients using a similar methodology. You create a radial gradient by using the createRadialGradient() method and then adding color stops at the appropriate positions. For example:

function drawRadialGradient()
{
  var canvas = document.getElementById('myCanvas'),
  var context = canvas.getContext('2d'),
  var rg = context.createRadialGradient(45,45,10,52,50,35);
  rg.addColorStop(0, '#95b800'),
  rg.addColorStop(0.9, '#428800'),
  rg.addColorStop(1, 'rgba(220,246,196,0)'),
  context.fillStyle = rg;
  context.fillRect(0,0,250,250);
}

The createRadialGradient() method defines two circles, one with a 10px radius and the second with a 35px radius. You add three color stops using addColorStop(), and then you assign the rg radialGradient object to the fillStyle property. See Figure 11-6.

ADDING SHADOWS

Shadow effects are a common visual technique you can use to enhance the look of your page element. Using JavaScript, the context object provides four properties that you can use for defining shadows on the canvas:

  • shadowColor defines the CSS color of the shadow.
  • shadowBlur specifies the width of the shadow blur.
  • shadowOffsetX defines the horizontal offset of the shadow.
  • shadowOffsetY specifies the vertical offset of the shadow.

Let me show you how to use them. The following code uses these properties to define a blurred shadow for an image:

function drawImg(){
  var canvas = document.getElementById('myCanvas'),
  var context = canvas.getContext('2d'),
  context.shadowColor = "black";
  context.shadowBlur = "10";
  context.shadowOffsetX = "5";
  context.shadowOffsetY = "5";
   var img3 = new Image();
   img3.src = 'images/nola.jpg';
   img3.onload = function()
{
     context.drawImage( img3, 20, 30 );
   }
  }

The four bold lines of code define a blurred black shadow that is offset 5px from the canvas. Figure 11-7 shows the result.

ADDING REFLECTIONS

If you have used the CoverFlow view in the Music app, you may have noticed the use of reflections. In fact, image reflections are an increasingly popular effect for images. Using CSS techniques, you can add reflections to your images or block elements.

To create a reflection, use the -webkit-box-reflect property:

-webkit-box-reflect : directionoffsetmaskImage|-webkit-gradient;

The direction parameter specifies the direction of the reflection relative to the object: above, below, left, or right. The offset parameter defines the offset distance (in pixels or as a percentage) that the reflection should be offset from the block. The maskImage parameter specifies a mask image. Or, as shown, you can also use a -webkit-gradient() function instead. For example, suppose you want to add a bottom reflection to an image using a gradient, you could use the following style rule:

<style>
 
  .reflectedImage
  {
    border:1px solid black;
    -webkit-box-reflect:below 3px -webkit-gradient(linear, left top,
     left bottom, from(transparent), color-stop(0.5, transparent), to(white));
  }
 
</style>
</head>
<body>
 
<img src="images/nola.jpg" class="reflectedImage"/>
 
</body>

Notice that the -webkit-gradient() function defines a linear gradient as the reflection. It begins fully transparent and ends fully white to blend into the background. Figure 11-8 shows the result.

Reflections on black backgrounds can be especially visually compelling on an IOS viewport. The following example shows a reflection on black (see Figure 11-9):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reflections</title>
<meta name="viewport" content="width=320; initial-scale=1.0;
   maximum-scale=1.0; user-scalable=0;">
 
<style>
 
  .reflectedImage
  {
    -webkit-box-reflect:below 3px -webkit-gradient(linear, left top,
     left bottom, from(transparent), color-stop(0.5, transparent), to(black));
  }
 
  body
  {
    background-color:#000000;
  }
 
</style>
</head>
<body>
 
<img src="images/nola.jpg" class="reflectedImage"/>
 
</body>
</html>

If you want to add reflections using JavaScript, I recommend checking out several open source libraries that use canvas programming to create sophisticated charts and image effects, such as reflections. Two particularly noteworthy libraries are PlotKit and Reflection.js. PlotKit is a JavaScript Chart Plotting library (available at www.liquidx.net/plotkit), and Reflection.js (available at http://cow.neondragon.net/stuff/reflection) enables you to add reflections to your images. The Reflection.js library uses canvas to render the reflection, but it enables you to use it simply by adding a reflect class to an image.

WORKING WITH MASKS

Masks are a common designer technique used to hide parts of an image. Typically you use a mask to create a blurred border around an image. You can use the CSS property -webkit-mask-image to add masks to images. Its syntax is shown below:

-webkit-mask-box-image: uritop right bottom left xRepeat yRepeat;

The uri is used to specify the mask image, such as one shown in Figure 11-10. The top, right, bottom, and left parameters are used to define the distance the mask is from the edge of the image. The repeat parameters specify x, y repeat styles. You can also use the constants as well: repeat (tiled), stretch, or round (which stretches all parts of the image slightly so that there are no partial tiles at any end).

For example, to create a vignette mask around an image that uses the mask image shown in Figure 11-10, you could use the following style definition:

  .vignetteMask
  {
    -webkit-mask-box-image: url(images/mask.png) 25 stretch;
  }

The 25 parameter specifies a 25 pixel distance around the full image, and stretch stretches the mask (which is smaller than the image it is applied to) to equally match the size of the image it is applied to. Figure 11-11 shows the results.

You are not limited to using a masked image, however. You can also use a -webkit-gradient() function to achieve a faded mask effect. For example, consider this style:

  .fadeToWhite
  {
    -webkit-mask-image:-webkit-gradient(linear, left top,
      left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));
  }

A linear gradient provides a masking effect for the image that uses this style. Notice how the bottom of the image in Figure 11-12 fades into the background.

Or, to achieve a rounded masking effect, you can combine the use of a -webkit-border-radius declaration with a -webkit-mask-image property. Consider the following:

   .roundedImage
   {
      -webkit-border-radius: 12px;
      -webkit-mask-image:-webkit-gradient(linear, left top,
        left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));
   }

The mask is applied to an image with rounded corners.

CREATING TRANSFORM EFFECTS

You can use three methods of a canvas context object to transform the state of a canvas:

  • translate(x, y) changes the origin coordinate (0, 0) of the canvas.
  • rotate(angle) rotates the canvas around the current origin of a specified number of radians.
  • scale(x, y) adjusts the scale of the canvas. The x parameter is a positive number that scales horizontally, and the y parameter scales vertically.

The following example uses translate() and scale() as it draws a circle successive times onto the canvas. Each time these methods are called, their parameters are adjusted:

function transform()
{
  var canvas = document.getElementById('myCanvas'),
  var context = canvas.getContext('2d'),
  var s=1;
  for (i=1;i<6;i++)
  {
    var t=i*8;
    context.translate(t,t);
    context.scale(s,s);
    context.fillStyle = "rgba(" + t*4 + ","+ t*6 + "," + t*8 + ", 0.3)";
    context.beginPath();
    context.arc(50,50,40,0,2*pi, false);
    context.fill();
    s=s-0.05;
  }
}

The t variable is eight times the current iteration of the for loop, and then is used as the parameter for translate(). The scale() method uses the s variable, which is decremented by 0.05 after each pass. The fillStyle() method also uses the t variable to adjust the rgb color values for each circle drawn. Figure 11-13 shows the result of the transformation.

The rotate() method rotates the canvas based on the specified angle. For example, in the following code, an image is drawn on the canvas three times, and each time the translate() and rotate() parameter’s values and the globalAlpha property are changed:

function rotateImg(){
  var canvas = document.getElementById('myCanvas'),
  var context = canvas.getContext('2d'),
  context.globalAlpha="0.5";
     var r=1;
  var img = new Image();
  img.src = 'images/jared.jpg';
  img.onload = function() {
    for (i=1;i<4;i++) {
      context.translate(50,-15);
      context.rotate(.15*r);
      context.globalAlpha=i*.33;
      context.drawImage(img, 20, 20);
      r+=1;
    }
  }
}

Figure 11-14 shows the layered result. Note the difference in transparency of the bottommost image to the topmost.

Note that as you begin to work with more advanced drawings on the canvas, you need to manage the drawing state. A drawing state includes the current path, the values of the major context properties (such as fillStyle and globalAlpha), and any transformations (such as rotating) that have been applied. To this end, you can use the save() and restore() methods. The save() method saves a snapshot of the canvas, which can then be retrieved later using the restore() method. The save() and restore() methods enable you to return to a default drawing state with minimal additional code and without needing to painstakingly re-create every setting.

CREATING ANIMATIONS

You can use the context drawing capabilities discussed earlier in combination with JavaScript timer routines to create animations on the canvas. On first take, the potential for creating canvas-based animation sounds like a perfect light-weight substitute for Flash animation. For some purposes, it can be ideal. However, any such excitement needs to be kept in check. Perhaps the chief shortcoming of canvas drawing in JavaScript is that you need to repaint the entire canvas for each frame of your animation. As a result, complex animations are at risk for being jerky on the mobile device. That being said, canvas animation can be a powerful tool to add to your development toolbox.

Like a motion picture or video clip, an animation is a series of frames that, when viewed one after the other, gives the appearance of movement. Therefore, when you code, your job is to show a drawing, clear it, draw the next frame in the series, clear it, and so on until your animation is completed or it loops back to the start. If you are changing any context settings and need to reset them for each new frame, you need to use the save() and restore() methods.

TRY IT OUT: Creating a JavaScript-based Animation

The following example shows how to animate an object using JavaScript.

1. Create the following HTML document in your text editor and then save the document as BIDHJ-Ch11-Ex2.html.

image
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Animate</title>
<meta name="viewport" content="width=320; initial-scale=1.0;
    maximum-scale=1.0; user-scalable=0;">
</head>
<body bgcolor="black">
<canvas id="myCanvas" width="300" height="300"
   style="position:absolute; left:0px; top:0px"/>
</body>
</html>

Code snippet BIDHJ-Ch11-Ex2.html

2. Add the following script code inside the document head:

image
<script type="application/x-javascript">
 
function init() {
  setInterval( animate, 1 );
}
 
var p = 0;
 
function animate(){
  var canvas = document.getElementById('myCanvas'),
  var context = canvas.getContext('2d'),
  context.globalCompositeOperation = "copy";
  context.fillStyle = "rgba(0,0,255, 0.3)";
  context.beginPath();
  context.arc(50+p,50+p,30,0, 360, false);
  context.fill();
  p+=1;
}
</script>

Code snippet BIDHJ-Ch11-Ex2.html

3. Add an onload event handler to the body tag and save the file:

image
onload="init()"

Code snippet BIDHJ-Ch11-Ex2.html

How It Works

The HTML page shows a simple animation program in which a circle moves diagonally from the top left to the bottom right part of the canvas. The init() function is called when the document is loaded, which sets off a timer to call animate() every 100 milliseconds. The animate() function clears the canvas, moves the orientation point, and draws a filled circle. The p variable is then incremented by one before repeating.

Figures 11-15 and 11-16 show the start and finish of the animation effect.

EXERCISES

1. When you draw onto a canvas, what is the key object that you work with?

2. What CSS property do you use to create a reflection?

3. What do the context object’s save() and restore() methods do?

Answers to the Exercises can be found in the Appendix.

• WHAT YOU LEARNED IN THIS CHAPTER

TOPIC KEY CONCEPTS
Creating gradients With CSS, use -webkit-gradient() function
With JavaScript, use createLinearGradient() or createRadialGradient()
Adding shadows Use the following context object properties: shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY
Creating reflections Use CSS property -webkit-box-reflect
Adding a mask to an image Use CSS property -webkit-mask-image
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset