Section 22.6. Graphics with Flash


22.6. Graphics with Flash

Each vector-graphics technology discussed so far in this chapter has limited availability: the <canvas> tag is only in Safari 1.3, Firefox 1.5, and Opera 9, VML is (and will always be) IE-only, and SVG is supported natively only in Firefox 1.5. Plug-in support for SVG is available, but the plug-in is not widely installed.

One powerful vector-graphics plug-in is widely (almost universally) installed, however: the Flash player from Adobe (formerly Macromedia). The Flash player has its own scripting language, called ActionScript (actually a dialect of JavaScript). Since Flash 6, the player has exposed a simple but powerful drawing API to ActionScript code. Flash 6 and 7 also provide limited communication channels between client-side JavaScript and ActionScript, making it possible for client-side JavaScript to send drawing commands to the Flash plug-in to be executed by the plug-in's ActionScript interpreter.

This chapter relies on Flash 8, which is brand new at the time of this writing. Flash 8 includes an ExternalInterface API that makes it trivial to export ActionScript methods so that they can be transparently invoked by client-side JavaScript. Chapter 23 illustrates how Flash drawing methods can be invoked in Flash 6 and 7.

To create a Flash-based drawing canvas, you need a .swf file that does no drawing of its own but just exports a drawing API to client-side JavaScript.[*] Let's begin with the ActionScript file shown in Example 22-12.

[*] The Flash-based pie chart code in Example 22-13 uses this Flash drawing API, but I don't document it here. You can find documentation at the Adobe web site.

Example 22-12. Canvas.as

 import flash.external.ExternalInterface; class Canvas {     // The open source mtasc ActionScript compiler automatically invokes     // this main( ) method in the compiled .swf file it produces. If you use     // the Flash IDE to create a Canvas.swf file, you'll need to call     // Canvas.main( ) from the first frame of the movie instead.     static function main( ) { var canvas = new Canvas( ); }     // This constructor contains initialization code for our Flash Canvas     function Canvas( ) {         // Specify resize behavior for the canvas         Stage.scaleMode = "noScale";         Stage.align = "TL";         // Now simply export the functions of the Flash drawing API         ExternalInterface.addCallback("beginFill", _root, _root.beginFill);         ExternalInterface.addCallback("beginGradientFill", _root,                                       _root.beginGradientFill);         ExternalInterface.addCallback("clear", _root, _root.clear);         ExternalInterface.addCallback("curveTo", _root, _root.curveTo);         ExternalInterface.addCallback("endFill", _root, _root.endFill);         ExternalInterface.addCallback("lineTo", _root, _root.lineTo);         ExternalInterface.addCallback("lineStyle", _root, _root.lineStyle);         ExternalInterface.addCallback("moveTo", _root, _root.moveTo);         // Also export the addText( ) function below         ExternalInterface.addCallback("addText", null, addText);     }     static function addText(text, x, y, w, h, depth, font, size) {         // Create a TextField object to display text at the specified location         var tf = _root.createTextField("tf", depth, x, y, w, h);         // Tell it what text to display         tf.text = text;         // Set the font family and point size for the text         var format = new TextFormat( );         format.font = font;         format.size = size;         tf.setTextFormat(format);     } } 

The ActionScript code shown in the Canvas.as file of Example 22-12 must be compiled into a Canvas.swf file before it can be used with the Flash player. Details on doing this are beyond the scope of this book, but you can use a commercial Flash IDE from Adobe or an open source ActionScript compiler.[*]

[*] I used the open source mtasc compiler (http://www.mtasc.org) and compiled the code with this command:

 mtasc -swf Canvas.swf -main -version 8 -header 500:500:1 Canvas.as 

After compilation, the resulting Canvas.swf file is a mere 578 bytes longsmaller than most bitmap images.

Unfortunately, Flash offers only a low-level API. In particular, the only function for drawing curves is curveTo( ), which draws a quadratic Bezier curve. All circles, ellipses, and cubic Bezier curves must be approximated with simpler quadratic curves. This low-level API is well-suited to the compiled SWF Flash format: all the computation required for more complex curves can be done at compilation time, and the Flash player need only know how to draw simpler curves. A higher-level drawing API can be built on top of the primitives provided by the Flash player, and it's possible to do this in ActionScript or in JavaScript (Example 22-13 is in JavaScript).

Example 22-13 begins with a utility function for embedding the Canvas.swf file into the HTML document. This is done differently in different browsers, and the insertCanvas( ) utility simplifies things. Next comes a wedge( ) function, which uses the simple Flash drawing API to draw a wedge of the pie chart. The pieChart( ) function follows and calls wedge( ) to draw its slices of pie. Finally, the example defines an onload handler to insert the Flash canvas into the document and draw into it.

Example 22-13. Drawing a pie chart with JavaScript and Flash

 <html> <head> <script> // Embed a Flash canvas of the specified size, inserting it as the sole // child of the specified container element. For portability, this function // uses an <embed> tag in Netscape-style browsers and an <object> tag in others // Inspired by FlashObject from Geoff Stearns. // See http://blog.deconcept.com/flashobject/ function insertCanvas(containerid, canvasid, width, height) {     var container = document.getElementById(containerid);     if (navigator.plugins && navigator.mimeTypes&&navigator.mimeTypes.length){         container.innerHTML =             "<embed src='/books/2/427/1/html/2/Canvas.swf' type='application/x-shockwave-flash' " +             "width='" + width +             "' height='" + height +             "' bgcolor='#ffffff' " +             "id='" + canvasid +             "' name='" + canvasid +             "'>";     }     else {         container.innerHTML =             "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' "+             "width='" + width +             "' height='" + height +             "' id='"+ canvasid + "'>" +             "  <param name='movie' value='Canvas.swf'>" +             "  <param name='bgcolor' value='#ffffff'>" +             "</object>";     } } // The Flash drawing API is lower-level than others, with only a simple // bezier-curve primitive. This method draws a pie wedge using that API. // Note that angles must be specified in radians. function wedge(canvas, cx, cy, r, startangle, endangle, color) {     // Figure out the starting point of the wedge     var x1 = cx + r*Math.sin(startangle);     var y1 = cy - r*Math.cos(startangle);     canvas.beginFill(color, 100); // Fill with specified color, fully opaque     canvas.moveTo(cx, cy);        // Move to center of circle     canvas.lineTo(x1, y1);        // Draw a line to the edge of the circle     // Now break the arc into pieces < 45 degrees and draw each     // with a separate call to the nested arc( ) method     while(startangle < endangle) {         var theta;         if (endangle-startangle > Math.PI/4) theta = startangle+Math.PI/4;         else theta = endangle;         arc(canvas,cx,cy,r,startangle,theta);         startangle += Math.PI/4;     }     canvas.lineTo(cx, cy);        // Finish with a line back to the center     canvas.endFill( );             // Fill the wedge we've outlined     // This nested function draws a portion of a circle using a Bezier curve.     // endangle-startangle must be <= 45 degrees.     // The current point must already be at the startangle point.     // You can take this on faith if you don't understand the math.     function arc(canvas, cx, cy, r, startangle, endangle) {         // Compute end point of the curve         var x2 = cx + r*Math.sin(endangle);         var y2 = cy - r*Math.cos(endangle);         var theta = (endangle - startangle)/2;         // This is the distance from the center to the control point         var l = r/Math.cos(theta);         // angle from center to control point is:         var alpha = (startangle + endangle)/2;         // Compute the control point for the curve         var controlX = cx + l * Math.sin(alpha);         var controlY = cy - l * Math.cos(alpha);         // Now call the Flash drawing API to draw the arc as a Bezier curve.         canvas.curveTo(controlX, controlY, x2, y2);     } } /**  * Draw a pie chart in the Flash canvas specified by element or id.  * data is an array of numbers: each number corresponds to a wedge of the chart.  * The pie chart is centered at (cx, cy) and has radius r.  * The colors of the wedges are Flash color values in the colors[] array.  * A legend appears at (lx,ly) to associate the labels in the labels[]  * array with each of the colors.  */ function pieChart(canvas, data, cx, cy, r, colors, labels, lx, ly) {     // Get the canvas if specified by id     if (typeof canvas == "string")         canvas = document.getElementById(canvas);     // All the lines we draw are 2 pixels wide, black, and 100% opaque.     canvas.lineStyle(2, 0x000000, 100);     // Figure out the total of the data values     var total = 0;     for(var i = 0; i < data.length; i++) total += data[i];     // And compute the angle (in radians) for each one.     var angles = []     for(var i = 0; i < data.length; i++) angles[i] = data[i]/total*Math.PI*2;     // Now, loop through the wedges of the pie     startangle = 0;     for(var i = 0; i < data.length; i++) {         // This is the angle where the wedge ends         var endangle = startangle + angles[i];         // Draw a wedge: this function is defined earlier         wedge(canvas, cx, cy, r, startangle, endangle, colors[i]);         // The next wedge starts where this one ends.         startangle = endangle;         // Draw a box for the legend         canvas.beginFill(colors[i], 100);         canvas.moveTo(lx, ly+30*i);         canvas.lineTo(lx+20, ly+30*i);         canvas.lineTo(lx+20, ly+30*i+20);         canvas.lineTo(lx, ly+30*i+20);         canvas.lineTo(lx, ly+30*i);         canvas.endFill( );         // Add text next to the box         canvas.addText(labels[i], lx+30, ly+i*30, 100, 20, // Text and position                        i, // each text field must have a different depth                        "Helvetica", 16);                   // Font info     } } // When the document loads, insert a Flash canvas and draw on it // Note that colors in Flash are integers instead of strings window.onload = function( ) {     insertCanvas("placeholder", "canvas", 600, 400);     pieChart("canvas", [12, 23, 34, 45], 200, 200, 150,              [0xff0000, 0x0000ff, 0xffff00, 0x00ff00],              ["North", "South", "East", "West"],              400, 100); } </script> </head> <body> <div ></div> </body> </html> 




JavaScript. The Definitive Guide
JavaScript: The Definitive Guide
ISBN: 0596101996
EAN: 2147483647
Year: 2004
Pages: 767

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net