Sometimes it is not possible to produce the desired animation using the declarative animation elements defined in the SVG standard. For instance, you might want to animate a non-scalar attribute of an SVG element, or change an attribute's value randomly or based on a non-linear formula. In such cases, you can still create the effect using the combination of JavaScript and DOM access to the SVG document.
Below is an example of a JavaScript animation. If the image does not animate, click here.
The animation above is achieved by changing the "d" attribute of the purple <path> element over time. All the JavaScript code required for the animation is defined within the SVG document itself. This makes it easier to incorporate the animated image in any Web page. The animation is started when the onload event of the <svg> tag is triggered. The onload handler saves a pointer to the SVG document in a global variable, then calls the system function setInterval to make the browser call next_frame repeatedly. function on_load (event) { // Save a pointer to the SVGDocument object // so that we can use it to retrieve various // named elements inside the animation function. svgdoc = event.getCurrentNode().getOwnerDocument(); // Start the animation loop. setInterval ('next_frame()', 100); } Note that this is a simplistic approach to animation: There is no guarantee that the next_frame function will be called at exactly every 100 milliseconds; the actual elapsed time between each invocation varies depending on the client system's capabilities and resource availability. Note also that the interval value can be set to any number of milliseconds; larger numbers will make the animation slower and rougher, while smaller numbers will make it faster and smoother. The above forms the basis of most JavaScript-driven animation. Inside the next_frame function, using the svgdoc variable, you can access and modify any of the elements in the SVG document as desired. See below for an in-depth explanation of the next_frame function for our particular example. The portion of the path being animated is a cubic Bezier curve stretching across the width of the SVG document. The cubic Bezier requires two control points. The animation is performed by constantly changing these two control points while keeping the end-points constant. We randomly generate the "target" values for the control points' coordinates, then we gradually increase or decrease the current coordinates until they match the target values. Inside the next_frame function, we use 4 global variables to keep track of the current coordinates of the control points: x0 & y0 for the 1st control point, and x1 & y1 for the second. We also use 4 other global variables to hold the target values: tx0, ty0, tx1 & ty1. The first step in the next_frame function is to retrieve the handle to the <path> element being animated using DOM methods and the svgdoc handle to the SVG document set during the on-load event: var linenode = svgdoc.getElementById ('line'); if (!linenode) return; Next, if necessary, we generate new target values for the control points' x,y coordinates. This is done either at the first invocation (target values are -1) or when all current coordinates are the same as the target coordinates: if (tx0 < 0 || (tx0 == x0 && ty0 == y0 && tx1 == x1 && ty1 == y1)) { tx0 = Math.floor (400*Math.random()); ty0 = Math.floor (300*Math.random()); tx1 = Math.floor (400*Math.random()); ty1 = Math.floor (300*Math.random()); } Next we change the current coordinates by up to +/-10 pixels towards the target values. This is done through a separate function to make the code easier to read and maintain (see the SVG source): x0 = change_coord (x0, tx0); y0 = change_coord (y0, ty0); x1 = change_coord (x1, tx1); y1 = change_coord (y1, ty1); Finally, we change the path element's "d" attribute to use the new coordinates. Remember that this attribtue contains the path's complete set of coordinates, i.e. the start-point, the two control points, and the end-point of the cubic Bezier, plus all other points: linenode.setAttribute ('d', 'M0,300L0,150C'+x0+','+y0 +','+x1+','+y1+',400,150L400,300z'); Next lesson: Mouse events Copyright ©2000 Adobe Systems Incorporated. All rights reserved. Terms of Use Online Privacy Policy
The animation above is achieved by changing the "d" attribute of the purple <path> element over time.
d
<path>
All the JavaScript code required for the animation is defined within the SVG document itself. This makes it easier to incorporate the animated image in any Web page.
The animation is started when the onload event of the <svg> tag is triggered. The onload handler saves a pointer to the SVG document in a global variable, then calls the system function setInterval to make the browser call next_frame repeatedly.
onload
<svg>
setInterval
next_frame
function on_load (event) { // Save a pointer to the SVGDocument object // so that we can use it to retrieve various // named elements inside the animation function. svgdoc = event.getCurrentNode().getOwnerDocument(); // Start the animation loop. setInterval ('next_frame()', 100); }
Note that this is a simplistic approach to animation: There is no guarantee that the next_frame function will be called at exactly every 100 milliseconds; the actual elapsed time between each invocation varies depending on the client system's capabilities and resource availability. Note also that the interval value can be set to any number of milliseconds; larger numbers will make the animation slower and rougher, while smaller numbers will make it faster and smoother.
The above forms the basis of most JavaScript-driven animation. Inside the next_frame function, using the svgdoc variable, you can access and modify any of the elements in the SVG document as desired. See below for an in-depth explanation of the next_frame function for our particular example.
svgdoc
The portion of the path being animated is a cubic Bezier curve stretching across the width of the SVG document. The cubic Bezier requires two control points. The animation is performed by constantly changing these two control points while keeping the end-points constant. We randomly generate the "target" values for the control points' coordinates, then we gradually increase or decrease the current coordinates until they match the target values.
Inside the next_frame function, we use 4 global variables to keep track of the current coordinates of the control points: x0 & y0 for the 1st control point, and x1 & y1 for the second. We also use 4 other global variables to hold the target values: tx0, ty0, tx1 & ty1. The first step in the next_frame function is to retrieve the handle to the <path> element being animated using DOM methods and the svgdoc handle to the SVG document set during the on-load event: var linenode = svgdoc.getElementById ('line'); if (!linenode) return; Next, if necessary, we generate new target values for the control points' x,y coordinates. This is done either at the first invocation (target values are -1) or when all current coordinates are the same as the target coordinates: if (tx0 < 0 || (tx0 == x0 && ty0 == y0 && tx1 == x1 && ty1 == y1)) { tx0 = Math.floor (400*Math.random()); ty0 = Math.floor (300*Math.random()); tx1 = Math.floor (400*Math.random()); ty1 = Math.floor (300*Math.random()); } Next we change the current coordinates by up to +/-10 pixels towards the target values. This is done through a separate function to make the code easier to read and maintain (see the SVG source): x0 = change_coord (x0, tx0); y0 = change_coord (y0, ty0); x1 = change_coord (x1, tx1); y1 = change_coord (y1, ty1); Finally, we change the path element's "d" attribute to use the new coordinates. Remember that this attribtue contains the path's complete set of coordinates, i.e. the start-point, the two control points, and the end-point of the cubic Bezier, plus all other points: linenode.setAttribute ('d', 'M0,300L0,150C'+x0+','+y0 +','+x1+','+y1+',400,150L400,300z'); Next lesson: Mouse events Copyright ©2000 Adobe Systems Incorporated. All rights reserved. Terms of Use Online Privacy Policy
Inside the next_frame function, we use 4 global variables to keep track of the current coordinates of the control points: x0 & y0 for the 1st control point, and x1 & y1 for the second. We also use 4 other global variables to hold the target values: tx0, ty0, tx1 & ty1.
x0
y0
x1
y1
tx0
ty0
tx1
ty1
The first step in the next_frame function is to retrieve the handle to the <path> element being animated using DOM methods and the svgdoc handle to the SVG document set during the on-load event:
var linenode = svgdoc.getElementById ('line'); if (!linenode) return;
Next, if necessary, we generate new target values for the control points' x,y coordinates. This is done either at the first invocation (target values are -1) or when all current coordinates are the same as the target coordinates:
if (tx0 < 0 || (tx0 == x0 && ty0 == y0 && tx1 == x1 && ty1 == y1)) { tx0 = Math.floor (400*Math.random()); ty0 = Math.floor (300*Math.random()); tx1 = Math.floor (400*Math.random()); ty1 = Math.floor (300*Math.random()); }
Next we change the current coordinates by up to +/-10 pixels towards the target values. This is done through a separate function to make the code easier to read and maintain (see the SVG source):
x0 = change_coord (x0, tx0); y0 = change_coord (y0, ty0); x1 = change_coord (x1, tx1); y1 = change_coord (y1, ty1);
Finally, we change the path element's "d" attribute to use the new coordinates. Remember that this attribtue contains the path's complete set of coordinates, i.e. the start-point, the two control points, and the end-point of the cubic Bezier, plus all other points:
linenode.setAttribute ('d', 'M0,300L0,150C'+x0+','+y0 +','+x1+','+y1+',400,150L400,300z');
Next lesson: Mouse events