Animation and Dynamic Creation of SVG Elements

   



Animation and Modifying Quadratic Bezier Curves

Consider the Bezier-based animation in Figure 13.3.

click to expand
Figure 13.3: A dynamically modified quadratic Bezier curve.

The SVG document dynamicQBezier1.svg in Listing 13.3 demonstrates how to define an ECMAScript function in order to dynamically update a Bezier curve and the values of its attributes.

Listing 13.3 dynamicQBezier1.svg

start example
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"   "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="100%" height="100%" onload="init(evt)"      xmlns="http://www.w3.org/2000/svg">   <script type="text/ecmascript">     <![CDATA[     var basePointX      = 300.;     var basePointY      = 100.;     var endPointX       = 600.;     var endPointY       = 400.;     var middlePointX    = (basePointX+endPointX)/2.;     var middlePointY    = (basePointY+endPointY)/2-100.;     var xOffset         = 0.0;     var yOffset         = 0.0;     var multiplier1     = 2.0;     var multiplier2     = 3.0;     var theta           = 0.0;     var startTheta      = 0.0;     var shiftTheta      = 1.0;     var maxTheta        = 2*Math.PI;     var displayCount    = 0.;     var shortPause      = 100.;     var constant1       = 200.0;     var constant2       = -80.0;     var fillColor       = "";     var fillColors      = ['red','green',                            'blue','yellow'];     var colorCount      = 4.;     var strokeColor     = "";     var strokeWidth     = 1.;     var strokeDelta     = 2.;     var strokeDirection = 1.;     var minStrokeWidth  = 2.;     var maxStrokeWidth  = 12.;     var pathString      = "";     var pathNode        = null;     var theTimeout      = null;     var svgDocument     = null;     var target          = null;     var gcNode          = null;     function init(event)     {        target   = event.getTarget();        svgDocument = target.getOwnerDocument();        gcNode   = svgDocument.getElementById("gc");        pathNode = svgDocument.createElement("path");        pathNode.setAttribute("style",               "stroke-width:4; stroke:red; fill:none");        gcNode.appendChild(pathNode);        theTimeout = setTimeout("window.renderBezier()",                                shortPause);     }     function updateCoordinates()     {        displayCount += 1;        strokeWidth += strokeDelta*strokeDirection;        if( strokeWidth > maxStrokeWidth )        {           strokeWidth = maxStrokeWidth;           strokeDirection *= -1;        }        if( strokeWidth < minStrokeWidth )        {           strokeWidth = minStrokeWidth;           strokeDirection *= -1;        }     } // updateCoordinates     function renderBezier()     {        pathNode = svgDocument.getElementById("thePath");        updateCoordinates();        /////////////////////////////////////////////        // sample string for quadratic Bezier curves:        // d="m0,0 Q100,0 200,200 T300,200 z"        /////////////////////////////////////////////        // construct the string for the path points        pathString = "M"+basePointX+","+basePointY;        xOffset    = basePointX+constant1*Math.cos(                          multiplier1*(theta+startTheta));        yOffset    = basePointY+constant2*Math.sin(                          multiplier2*(theta+startTheta));        pathString += " Q" + xOffset + "," + yOffset;        pathString += " "+middlePointX+","+middlePointY;        pathString += " T"+endPointX+","+endPointY+"z";        startTheta += shiftTheta;        pathNode.setAttribute("d", pathString);        fillColor   = fillColors[displayCount%colorCount];        pathNode.setAttribute("fill", fillColor);        strokeColor = "stroke-width:"+                        strokeWidth+";stroke:";        strokeColor += fillColors[                        (displayCount+1)%colorCount];        pathNode.setAttribute("style", strokeColor);        theTimeout = setTimeout("window.renderBezier()",                                shortPause);        if( ++theta >= maxTheta )        {           theta = 0;        }     }     function stopAnimation()     {        window.clearTimeout(theTimeout);     }   ]]> </script>     <!-- ============================ -->   <g  transform="translate(10,10)">     <!-- render outer rectangle -->     <rect x="0" y="0"           width="800" height="500"           fill="none" stroke="none"/>     <!-- render mouse-handling rectangle -->     <rect            x="50" y="200"           width="100" height="50"           onclick="stopAnimation()"           fill="green"/>     <!-- render the polar equation -->     <path            onclick="stopAnimation()"           d="m200,100 300,100 300,200 200,200 z"           fill="blue"/>     <!-- display text message -->     <text x="300" y="50"           font-family="Verdana"           font-size="25" text-anchor="middle">       Click inside the rectangle to stop animation     </text>   </g>   </svg>
end example

Remarks

The SVG code in Listing 13.3 renders a quadratic Bezier curve that is updated dynamically in order to produce an oscillating effect. You can stop the animation by clicking on the blue rectangle rendered to the left of the Bezier curve.

The code in this example starts with the definition of a number of ECMAScript global variables. The first set of global variables is given below:

var basePointX      = 300.; var basePointY      = 100.; var endPointX       = 600.; var endPointY       = 400.; var middlePointX    = (basePointX+endPointX)/2.; var middlePointY    = (basePointY+endPointY)/2-100.;

The global variables basePointX and basePointY specify the x-coordinate and the y-coordinate of the upper-left corner of the set of rendered ellipses.

The global variables endPointX and endPointY specify the x-coordinate and the y-coordinate of the end point of the quadratic Bezier curve.

The global variables middlePointX and middlePointY specify the x-coordinate and the y-coordinate of the middle point of the quadratic Bezier curve.

The second set of global variables is:

var xOffset         = 0.0; var yOffset         = 0.0; var multiplier1     = 2.0; var multiplier2     = 3.0; var theta           = 0.0; var startTheta      = 0.0; var shiftTheta      = 1.0; var maxTheta        = 2*Math.PI; var displayCount    = 0.; var shortPause      = 100.; var constant1       = 200.0; var constant2       = -80.0;

The global variables xOffset and yOffset specify the x-coordinate and the
y-coordinate of the Q point in the SVG path element that defines the current quadratic Bezier curve.

The global variable theta is used for computing trigonometric quantities that are in turn used for updating the current values of the variables xOffset and yOffset as given below:

xOffset = basePointX+constant1*Math.cos(                    multiplier1*(theta+startTheta)); yOffset = basePointY+constant2*Math.sin(                    multiplier2*(theta+startTheta));

The global variables startTheta, shiftTheta, and maxTheta specify the initial value, increment value, and maximum value of the variable theta.

The global variable displayCount is incremented each time a quadratic Bezier curve is displayed, and its value is used as an index into the array fillColors, which contains a set of colors.

The third set of global variables is given below:

var fillColor       = ""; var fillColors      = ['red','green',                        'blue','yellow']; var colorCount      = 4.; var strokeColor     = ""; var strokeWidth     = 1.; var strokeDelta     = 2.; var strokeDirection = 1.; var minStrokeWidth  = 2.; var maxStrokeWidth  = 12.; var pathString      = "";

The global variable fillColor is used for specifying the color of the current Bezier curve.

The global variable fillColors is an array that consists of the colors red, green, blue, and yellow.

The value of the global variable colorCount equals the number of elements in the array fillColors.

The global variable strokeDelta specifies the increment value for the variable strokeWidth.

The global variable strokeDirection is either 1 or -1, which is used for either increasing or decreasing the value of the variable strokeWidth.

The global variables minStrokeWidth and maxStrokeWidth specify the minimum and maximum allowable values for the variable strokeWidth.

The global variable pathString is a string that stores the actual points for the current quadratic Bezier curve, and it is used for setting the value of the d attribute.

The fourth and final set of global variables is given below:

var pathNode        = null; var theTimeout      = null; var document        = null; var target          = null; var gcNode          = null;

The global variable pathNode is a reference to a dynamically created SVG path element that represents the current quadratic Bezier curve.

The variables theTimeout, svgDocument, target, and gcNode are assigned their usual values in the ECMAScript function init().

In addition, the init() function does two important things. First, it creates an SVG path element that is added to the current SVG document by means of the following code fragment:

pathNode = svgDocument.createElement("path"); pathNode.setAttribute("style",          "stroke-width:4; stroke:red; fill:none"); gcNode.appendChild(pathNode); theTimeout = setTimeout("window.renderBezier()",                         shortPause);

Second, the init() function invokes the ECMAScript function renderBezier(), which contains the code for dynamically updating the quadratic Bezier curve. The code in the function renderBezier() begins by assigning a reference to the variable pathNode with the following line of code:

pathNode = svgDocument.getElementById("thePath");

Next, the function renderBezier() invokes the ECMAScript function updateCoordinates(), which updates the value of the variables displayCount and strokeWidth, with the following line of code:

updateCoordinates();

In order to better understand how the function renderBezier() constructs the value of the d attribute, look at the sample string given below:

// d="M0,0 Q100,0 200,200 T300,200 z" 

The code for constructing the initial point associated with the M term consists of the following line:

pathString = "M"+basePointX+","+basePointY;

The code for constructing the Q term contains the following lines of code:

xOffset    = basePointX+constant1*Math.cos(                     multiplier1*(theta+startTheta)); yOffset    = basePointY+constant2*Math.sin(                     multiplier2*(theta+startTheta)); pathString += " Q" + xOffset + "," + yOffset;

The code for constructing the 'middle' point contains one line of code:

pathString += " "+middlePointX+","+middlePointY;

The code for constructing the T term contains one line of code:

pathString += " T"+endPointX+","+endPointY+"z";

Next, the renderBezier() function sets the value of the d attribute, determines the color of the current quadratic Bezier curve, determines the stroke color, and sets the style attribute, all of which is performed in the following code fragment:

path.NodesetAttribute("d", pathString); fillColor   = fillColors[displayCount%colorCount]; pathNode.setAttribute("fill", fillColor); strokeColor = "stroke-width:"+strokeWidth+";stroke:"; strokeColor += fillColors[(displayCount+1)%colorCount]; pathNode.setAttribute("style", strokeColor);

The renderBezier() function invokes the following line of code in order to call itself after a delay of shortPause milliseconds:

theTimeout = setTimeout("window.renderBezier()",                         shortPause);

The last ECMAScript function is stopAnimation(), which stops the animation:

function stopAnimation() {    window.clearTimeout(theTimeout); }

The following SVG 'mouse-aware' rectangle is rendered to the left of the dynamically updated quadratic Bezier curve, and the ECMAScript function stopAnimation() is invoked when you click inside this rectangle with your mouse:

<rect        x="50" y="200"       width="100" height="50"       onclick="stopAnimation()"       fill="green"/>



   



Fundamentals of SVG Programming. Concepts to Source Code
Fundamentals of SVG Programming: Concepts to Source Code (Graphics Series)
ISBN: 1584502983
EAN: 2147483647
Year: 2003
Pages: 362

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