The SVG Web library makes it possible to use SVG across all of the major browsers, including Internet Explorer. Where native SVG support is not available, such as on Internet Explorer, a full-featured Flash object is used to render and manipulate the SVG behind the scenes. Where native browser SVG support is available (every other recent browser but Internet Explorer) the SVG is rendered natively by the browser. A simple optional configuration is possible to force the use of SVG Web even on browsers with native SVG support, which can aide in deployment and using newer SVG features like SVG Video.
The library is meant to bring seamless SVG support to Internet Explorer using Flash as close to the SVG 1.1 Full standard as possible, using native browser SVG support in other browsers. The Flash renderer can be used on other browsers than Internet Explorer, though we default to only using Flash on IE automatically. The Flash SVG renderer in some cases supports SVG features that are not widely supported even with native support, such as SVG Video support, SVG Fonts, SVG SMIL animation, etc.
It is currently a non-goal of this library to fully support SVG 1.2; we will select specific elements from the SVG 1.2 spec where it makes sense, however, such as the SVG 1.2 Video and Audio tags.
Another goal of the library is to make direct embedding of SVG into normal non-XHTML HTML much easier, as was well as supporting using the OBJECT tag to easily bring in SVG files. Using SVG in backgrounds and with the IMAGE tag is not currently supported.
The SVG Web toolkit is currently in alpha. Please file issues if you run into problems.
The SVG Web library supports using either the Flash or Native SVG renderer for different browsers, including Internet Explorer 6+, Firefox 2+, Safari 3+, Opera, iPhone Version 2.1+ Webkit, and Chrome. Note that robust QA has not yet occurred for Opera and Chrome, and that there is currently a regression affecting usage on the iPhone. Android does not currently support either Flash or SVG so is not supported. The iPhone before version 2.1 does not natively support either Flash or SVG and therefore is not supported.
Flash 9+ is required for the Flash renderer; this has close to 97% installed base so it is safe to depend on.
The Adobe SVG Viewer (ASV) is not supported; it is a non-goal of this project to have support for the ASV viewer or its proprietary extensions.
First, you must bring in the svg.js file into your HTML page as the _first_ script on your page, before all others:
<script src="svg.js"></script>
Next, SVG markup can be embedded into your HTML in two ways, either using a SCRIPT tag or an OBJECT tag.
For the SCRIPT tag, set the 'type' attribute to "image/svg+xml" and simply place the tag in your HTML page where you want the SVG to appear:
<h1>Here is an example SVG image:</h1>
<script type="image/svg+xml">
<svg xmlns="http://www.w3.org/2000/svg"
width="200" height="200"
version="1.1" baseProfile="full">
<rect x="0" y="0" width="60" height="60" style="stroke: green;"/>
<rect x="25" y="25"
id="myRect"
rx="0.6" ry="0.6"
width="150" height="150"
fill="green"
stroke="yellow" stroke-width="8"/>
</svg>
</script>
Normal full-XML SVG can be used inside of the SCRIPT block. Adding an XML declaration and the SVG and XLink namespaces are all optional and will be added if not present (note: this differs from the SVG 1.1 spec and is added for ease of authoring). You can also include all of them. Note that you should not include the XML character encoding on the XML declaration tag, such as 'UTF-8' or 'ISO-8859-1', as this makes no sense since the overall document has its own encoding). Here's some example SVG with everything specified if you enjoy lots of typing:
<script type="image/svg+xml">
<?xml version="1.0"?>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" baseProfile="full"
width="466"
height="265"
id="svg11242">
</svg>
</script>
For simplicity of authoring this can also just be written as:
<script type="image/svg+xml">
<svg width="466" height="265" id="svg11242"></svg>
</script>
The SCRIPT SVG block is supported in both XHTML as well as normal HTML pages across all browsers, including Internet Explorer. If you are using XHTML you will probably want to wrap your embedded SVG with CDATA sections; these CDATA sections will also work directly in Internet Explorer without needing any further tricks:
<script type="image/svg+xml"><![CDATA[
<svg width="466" height="265" id="svg11242"></svg>
]]></script>
Note that direct embedding foreign markup using the SCRIPT tag + MIME type is a valid way to do things in HTML 5. We don't yet support the other, newer HTML 5 direct embed syntax for SVG due to some technical issues.
The second way to embed SVG is with the the OBJECT tag, which will work on Internet Explorer as well. Example:
<!--[if IE]>
<object id="testSVG" src="scimitar.svg"
classid="image/svg+xml" width="1250" height="750">
<![endif]-->
<!--[if !IE]>-->
<object id="testSVG" data="scimitar.svg"
type="image/svg+xml" width="1250" height="750">
<!--<![endif]-->
<h1>Put optional fallback content here</h1>
</object>
Notice the Internet Explorer conditional comments. The first OBJECT tag is for Internet Explorer, while the second one is for standards-compliant browsers. This format is necessary for robust IE support, including IE 6.
For the first OBJECT for Internet Explorer, you must specify a 'src' attribute pointing to your SVG file rather than using the standard 'data' attribute. Unfortunately again due to some limitations on Internet Explorer you should not include the 'type' attribute but rather must include a 'classid' attribute set to "image/svg+xml" for use with the SVG Web framework.
The second OBJECT works according to the standard, which has a 'type' set to "image/svg+xml" and a 'data' attribute set to "scimitar.svg".
Note that the URL given in the 'src' or 'data' attributes must be on the same domain as the web page and follows the same domain rule (i.e. same protocol, port, etc.); cross-domain object insertion is not supported for security reasons. You must also specify a width and height.
You must make sure that the library files svg.htc, svg.swf, and svg.js are located by default in the same directory as your HTML page. They must also be on the same domain as your HTML page and can not be on a separate domain, such as having your html on mydomain.example.com and those three files on static.example.com.
You can override where on your domain you keep svg.htc, svg.swf, and svg.js by using the optional data-path attribute to point to a different relative or absolute directory path. If you like to validate your HTML note that this custom attribute is HTML 5 valid, as all attributes that are prefixed with data- are:
<script src="../svg.js" data-path=".."></script>
It does not matter whether you have a trailing slash or not, such as .. versus ../
SVG Web has what is called an HTC file (svg.htc). For this to work you must make sure that your web server is configured to send the correct MIME type for HTC files (text/x-component). The page at http://support.microsoft.com/kb/306231 provides some details on configuring Apache correctly for this.
If you don't have the ability or background to add MIME types to your web server, three easy files have been provided that will do the work for you based on what you can run on your server (PHP, JSP, or ASP). Based on what you can run on your server, choose one of the following files:
svg-htc.php
- Will do the MIME work for you if you can run
PHP on your web server.svg-htc.jsp
- Will do the MIME work for you if you can run
JSP on your web server.svg-htc.asp
- Will do the MIME work for you if you can run
ASP on your web server.If you choose one of these, you must indicate so using the optional
data-htc-filename
attribute:
<script src="../svg.js" data-path=".." data-htc-filename="svg-htc.php"></script>
Only give the filename, such as svg-htc.jsp
, rather than a full
path, such as ../../svg-htc.jsp
http://example.com/svgweb/samples/demo.html?svg.htcFilename=svg-htc.php
Note that it is possible to host much of the bulk of SVG Web on a different domain than the page it is being used on; see the section "Cross Domain SVG Web" for details.
SVG Web comes bundled with a simple testing file to help you isolate MIME type issues. Simply upload the SVG Web distribution to your web server and then navigate to src/tools/config.html
; this page will report to you whether all your MIME types are set correctly.
By default, the Flash renderer will be used on Internet Explorer 6+; versions of Firefox before Firefox 3 (not yet supported); versions of Safari before Safari 3 (not yet supported); and versions of Opera before Opera 9 (not yet supported). The native SVG renderer will be used on Firefox 3+; Safari 3+; Chrome; and iPhone version 2.1+ Webkit.
In general, we will attempt to use native SVG abilities if they are present. To override this and force the Flash renderer to be used you can drop the following META tag into your page:
<meta name="svg.render.forceflash" content="true">
You can also force the Flash renderer through the URL with the following flag:
http://example.com/mypage.html?svg.render.forceflash=true
Just set 'svg.render.forceflash' to true or false after a query parameter.
Forcing the Flash renderer to be used on all platforms independent of native support can ease QA and deployment, as well as make it possible to use SVG features such as SMIL and SVG Video that might not be widely deployed yet. Note that forcing Flash support will do nothing on the iPhone, as that platform does not support Flash; on the iPhone the Native Renderer will always be used (TODO: Confirm that this is true for the iPhone if the Flash renderer is being forced).
SVG has a SCRIPT tag, which allows you to embed JavaScript inside of your SVG. SVG files brought in with the OBJECT tag can have SVG SCRIPT blocks that will execute as normal. However, if you directly embed SVG into your page using the SVG SCRIPT process but have nested SVG script tags, you should make sure that you namespace all of your SVG, such as having <svg:script>. (NOTE: having SVG SCRIPT tags inside of directly embedded SVG is not implemented yet; it works however with SVG brought in with the OBJECT tag).
For browsers with native SVG support, the SVG content inside of a SCRIPT tag shows up fully in the browser's DOM, with the SCRIPT tag thrown away after the page has finished loading, so you can manipulate it with normal JavaScript:
<script type="image/svg+xml">
<svg width="200" height="200">
<rect x="25" y="25"
id="myRect"
rx="0.6" ry="0.6"
width="150" height="150"
fill="green"
stroke="yellow" stroke-width="8"/>
</svg>
</script>
<script>
window.onload = function() {
var rect = document.getElementById('myRect');
rect.setAttribute('fill', 'red');
rect.style.strokeWidth = 20;
}
</script>
Manipulating an SVG OBJECT tag with browsers with native support is as normal following the standard; just use the contentDocument property on the OBJECT to get a document object and execute your standard DOM functions afterwards.
For the Flash renderer, scripting support is as follows.
If the Flash renderer is used on Internet Explorer, Firefox, and Safari, the SVG Web library does some magic to have the SVG inside of a SCRIPT block show up in the full DOM, fully manipulatable by JavaScript; the example code above this where 'myRect' is retrieved from the page and then manipulated would work the same, with document.getElementById('myRect') working as expected.
If you have a SCRIPT block inside of your SVG then it will work correctly on all browsers with the Flash renderer as well:
<!--[if IE]>
<object src="blocks_game.svg" classid="image/svg+xml" width="500" height="500">
<![endif]-->
<!--[if !IE]>-->
<object data="blocks_game.svg" type="image/svg+xml" width="500" height="500">
<!--<![endif]-->
</object>
(inside of blocks_game.svg):
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="init();">
<script><![CDATA[
function init() {
var board = document.getElementById("board");
}
]]></script>
<g id="board" stroke-width="0.02"/>
</svg>
On all browsers, including Internet Explorer, an SVG OBJECT tag can be manipulated by external JavaScript as normal by using the contentDocument property:
<!--[if IE]>
<object id="testSVG" src="scimitar.svg"
classid="image/svg+xml" width="1250" height="750">
<![endif]-->
<!--[if !IE]>-->
<object id="testSVG" data="scimitar.svg"
type="image/svg+xml" width="1250" height="750">
<!--<![endif]-->
</object>
<script>
if (window.addEventListener) {
window.addEventListener('load', function() {
var doc = document.getElementById('testSVG').contentDocument;
var rect = doc.getElementsByTagNameNS(svgns, 'rect')[0];
}, false);
} else { // IE
window.attachEvent('onload', function() {
var doc = document.getElementById('testSVG').contentDocument;
var rect = doc.getElementsByTagNameNS(svgns, 'rect')[0];
});
}
</script>
When doing DOM scripting on SVG elements, you should use the namespace aware DOM methods, including on Internet Explorer which is patched to support the standard:
var el = document.createElementNS(svgns, 'circle');
el.setAttribute('cx', 200);
el.setAttribute('cy', 200);
el.setAttribute('r', 5);
el.setAttribute('fill', '#223FA3');
el.setAttribute('stroke-width', '1px');
el.setAttribute('stroke', 'black');
var root = document.getElementsByTagNameNS(svgns, 'svg')[0];
root.appendChild(el);
Note that SVG attributes like 'stroke-width' aren't in the SVG namespace, so you can use setAttribute() instead of setAttributeNS(); using setAttributeNS is a common SVG mistake. You only need to do this for XLink attributes:
el.setAttributeNS(xlinkns, 'href');
If you like being pedantic and typing more you can use null for a namespace when working with SVG attributes:
el.setAttributeNS(null, 'fill', 'black');
Just using the following is also valid, and results in smaller code:
el.setAttribute('fill', 'black');
(Note: officially, the SVG 1.1 standard recommends setAttributeNS with a namespace of null, but setAttribute does the job and all the extra typing is silly. The DOM standard is already verbose enough as it is.)
For convenience, the svg.js file exports the global properties window.svgns and window.xlinkns with the correct namespaces to ease development (note: this is not part of the SVG 1.1 standard and is provided for convenience):
var circle = document.createElementNS(svgns, 'circle');
For events, you can use addEventListener/removeEventListener on SVG elements, including on Internet Explorer (instead of using IE's proprietary attachEvent):
circle.addEventListener('click', function(evt) {
// do something
}, false);
On Internet Explorer, the event object is passed into your listener, just like the standard says, so you should use this instead of window.event.
Controlling event bubbling with the final addEventListener argument is not supported; it is always automatically false. Also, event bubbling outside of the SVG root element does not occur (i.e. you can't add an event listener for mouse move events onto your HTML BODY tag and see them within the SVG. Just add it to the SVG root element itself if you want to intercept all these).
If you want to know when your SVG and the entire page is done loading, you can use window.onload, have an onload attribute on the BODY tag, or use window.addEventListener('load, ...) or window.attachEvent('onload' for IE. Example:
window.onload = function() {
// all SVG loaded and rendered
}
If you dynamically create SVG root elements _after_ the page has already finished loading, you must add an SVGLoad listener to the SVG root element before you can add further children (note: this is a divergence from the SVG 1.1 standard, and is needed due to the asynchronous Flash and Microsoft Behavior magic going on under the covers to bootstrap different parts of the library):
var root = document.createElementNS(svgns, 'svg');
root.setAttribute('width', 200);
root.setAttribute('height', 200);
root.addEventListener('SVGLoad', function(evt) {
console.log('SVG onload called');
// now you can do things with the SVG root element, like add more children
});
svgweb.appendChild(root, document.body);
'load' and 'SVGLoad' are synonomous and are both supported; they lead to the
same behavior when used. Notice also that when we append our newly created SVG
root that we must use the method svgweb.appendChild
. This method
has the following arguments:
svgweb.appendChild(newNode, parentNode);
If you are loading an SVG file using the OBJECT tag and have an onload="" attribute, such as:
Containing HTML page:
<!--[if IE]>
<object src="photos.svg" classid="image/svg+xml" width="500" height="500">
<![endif]-->
<!--[if !IE]>-->
<object data="photos.svg"
type="image/svg+xml" width="500" height="500">
<!--<![endif]-->
</object>
photos.svg:
<svg onload="doload()">
<script type="text/javascript"><![CDATA[
function doload() {
// developers onload handler
}
]]>
</svg>
Then you will have to modify your onload="" attribute a little bit to help the SVG Web framework; you must add some code telling SVG Web that you are loaded, and SVG Web will call you when things are truly ready to be used. You should change the above to:
<svg onload="loaded()">
<script type="text/javascript"><![CDATA[
function loaded() {
// change onloadFunc to point to your real onload function that you
// want called when the page is truly ready
var onloadFunc = doload;
if (top.svgweb) {
top.svgweb.addOnLoad(onloadFunc, true, window);
} else {
onloadFunc();
}
}
function doload() {
// developers original onload handler
}
]]>
</svg>
Note the new loaded() function above and that we've changed onload="" to run it instead of our own function; you should call loaded() instead, and copy the code in that function into your .svg file. Notice the following line:
// change onloadFunc to point to your real onload function that you
// want called when the page is truly ready
var onloadFunc = doload;
Change this variable to be your original onload function, such as doload in the example above. Notice that we pass a reference to the function and _don't_ have () at the end -- i.e. it is 'var onloadFunc = doload' NOT 'var onloadFunc = doload()'.
svgz (compressed SVG files) are not supported. However, it is recommended that you turn on GZip compression on your webserver for both SVG files and the svg.htc, svg.swf, and svg.js library files to have very significant size savings equal to an svgz file as well as to pull down the SVG Web library files faster.
For the Flash renderer, you should set the width and height of your SVG, either on the root SVG element inside of an SVG SCRIPT block or on an SVG OBJECT tag. The following different ways are supported to set this width and height for the Flash renderer:
* Directly setting the width and height attributes on the SVG root tag or the SVG OBJECT:
<script classid="image/svg+xml">
<svg width="30" height="30"></svg>
</script>
or
<!--[if IE]>
<object src="example.svg" classid="image/svg+xml" width="30" height="30">
<![endif]-->
<!--[if !IE]>-->
<object data="example.svg" type="image/svg+xml" width="30" height="30">
<!--<![endif]-->
</object>
* A viewBox attribute on the SVG root element:
<script type="image/svg+xml">
<svg viewBox="0 0 300 300"></svg>
</script>
* Leaving the width and height off the SVG OBJECT tag but having it set inside of the SVG file itself either with a width and height attribute
* If no width and height is specified, then we default to 100% for both.
Percentage values for the width and height for the SVG are supported, including the 'auto' keyword. We do not currently handle a width and height of 0 (FIXME: I believe according to the spec a width and height of 0 should have the SVG have a visibility of 'none'). TODO: I think we might support this now; double check.
This section only concerns the Flash renderer. Native SVG support works as normal.
For the Flash renderer, SVG STYLE elements inside of an SVG block are supported (Note: <style> tags inside of <svg> root elements is not yet implemented):
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="600px" height="388px">
<style type="text/css">
text {
font-size: 9pt;
font-family: sans-serif;
}
.percentage,
.date,
.title {
font-weight: bold;
}
</style>
</svg>
External style rules outside of the SVG _are not_ currently supported, such as the following style rule embedded into an HTML page which will not work:
<html>
<head>
<style>
@namespace svg url("http://www.w3.org/2000/svg");
svg\:rect,
svg|rect {
fill: green;
}
</style>
</head>
</html>
Note the svg\:rect trick to have Internet Explorer see namespaced SVG CSS rules. Currently you should directly set these on the SVG root element or SVG OBJECT tag which is supported:
<!--[if IE]>
<object src="scimitar.svg" classid="image/svg+xml"
id="testSVG" width="1250" height="750"
style="display: inline; float: right; border: 1px solid black;">
<![endif]-->
<!--[if !IE>-->
<object data="scimitar.svg" type="image/svg+xml"
id="testSVG" width="1250" height="750"
style="display: inline; float: right; border: 1px solid black;">
<!--<![endif]-->
</object>
These properties are copied directly to the Flash rendering object. Changing any style properties like display, float, etc. through JavaScript after page load on the SVG root element or an SVG OBJECT does not currently cause any dynamic behavior.
You can dynamically change the CSS values on SVG elements through JavaScript:
var rect = document.getElementById('myRect');
rect.style.strokeWidth = '5px'; // works!
rect.setAttribute('stroke-width', '5px'); // also works!
console.log('rect.style.strokeWidth='+rect.style.strokeWidth) // prints 5px
Inline style rules on SVG elements is also supported:
<rect
y="-1.7111325"
x="-2.2665024"
height="455.04538"
width="455.04538"
id="rect3926"
style="opacity:1;fill:#c1cfeb;fill-opacity:1;stroke:#555040;stroke-width:3;"/>
Note that Firefox natively has glitches around using the .style property on SVG objects; the SVG Web toolkit actually patches Firefoxes native implementation and fixes this.
If no background color for your SVG is specified with a CSS background-color attribute, the default is transparent (TODO: Confirm on non-IE browsers). If you specify a color, that will be used for your background:
<script type="image/svg+xml">
<svg width="200" height="200" style="background-color: red;">
</svg>
</script>
Setting the background using the 'background' CSS property is not currently supported, only with the 'background-color' property.
If neither native SVG nor Flash can be used, you can put fallback content inside of your OBJECT tag to be displayed; place it before the end </OBJECT> tag:
<!--[if IE]>
<object id="mySVG" src="embed1.svg"
classid="image/svg+xml" width="500" height="500">
<![endif]-->
<!--[if !IE]>-->
<object id="mySVG" data="embed1.svg"
type="image/svg+xml" width="500" height="500">
<!--<![endif]-->
<img src="scimitar.png" />
</object>
This will display the PNG file if SVG can't be used. (Note: Fallback content for SVG OBJECTs is not yet implemented).
You can achieve the same thing with SVG SCRIPT blocks by using a NOSCRIPT element directly following the SVG SCRIPT block. This NOSCRIPT element will get displayed if there is no JavaScript; it will also get executed if no SVG support is possible (note: executing the NOSCRIPT block if SVG support is not possible is a creative reuse of the NOSCRIPT block and is not part of the HTML 4.1 standard):
<script type="image/svg+xml">
<svg width="200" height="200">
</svg>
</script>
<noscript>
<img src="scimitar.png"></img>
</noscript>
This will display the given PNG file if JavaScript is turned off or if SVG support can't be bootstrapped. As a suggestion, if you want to generate nice PNG image files for your SVG for older browsers as fallback content, you can use the excellent free and open source utility/library Batik to render your SVG directly into image files (http://xmlgraphics.apache.org/batik/). Just plug Batik into your workflow (ant, makefiles, etc.) to automatically generate static images.
If there is not a NOSCRIPT element or fallback content inside of an SVG OBJECT tag then a message indicating no support is directly written into the block for the user to see by default.
You can detect from your JavaScript after the page has finished loading whether SVG is possible either natively or with Flash using the following:
<script>
window.addEventListener('load', function() {
if (document.implementation.hasFeature(
'http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1') == false) {
alert('SVG not supported!');
}
}, false);
</script>
This will return true on all browsers that natively support SVG; we also patch things so that true will be returned if we can use Flash to do all the SVG hard work.
When you create a text node that you know you will append to something within your SVG, you need to add an extra parameter to document.createTextNode:
var textNode = document.createTextNode('hello world', true);
var metadata = document.getElementsByTagNameNS(svgns, 'metadata');
metadata.appendChild(textNode);
The final argument should be 'true' to indicate that you will use this text node in your SVG. This is not part of the SVG 1.1 standard, but is necessary for some internal machinery to work correctly. If you don't give the final argument or set it to false then you will get a normal text node that you can use with HTML content.
In an XML document there can be whitespace, such as spaces and newlines, between tags. Example:
<mytag>text</mytag> <anothertag>foobar</anothertag>
Internet Explorer handles whitespace different than other browsers. In order to normalize things, when dealing with embedded SVG content using the SCRIPT tag we remove all the whitespace that is between tags. This will allow you to create JavaScript DOM code that works consistently between browsers. No empty whitespace text nodes will be in the SVG portion of the DOM.
Remember, though, that the rest of your HTML document will be using the whitespace behavior of the browser itself. For example, if you have a BODY tag with some nested SVG and are calling BODY.childNodes, whitespace elements will show up in the DOM on all browsers except for Internet Explorer.
When working with SVG files embedded using the OBJECT tag, however, we retain all whitespace nodes, including on Internet Explorer, to 'mimic' the SVG running in an XML environment (which by default retains whitespace nodes).
If you want to know from your JavaScript which renderer is being used, you can call svgweb.getHandlerType(). This will return the string 'flash' if the Flash renderer is being used and 'native' if the native renderer is being used.
You can also detect whether a given DOM node that you are using is a real browser DOM node or a 'fake' one created and maintained by the SVG Web toolkit. All of our fake SVG nodes have a 'fake' property that will return true. Other nodes will simply not have this property. For example:
var circle = document.createElementNS(svgns, 'circle');
alert(circle.fake); // will alert(true)
var h1 = document.createElement('h1');
alert(h1.fake); // will alert(undefined)
If you embed SVG objects into your page using the OBJECT element, you can navigate into the SVG inside the OBJECT element using contentDocument:
<!--[if IE]>
<object id="testSVG" src="embed1.svg"
classid="image/svg+xml" width="500" height="500">
<![endif]-->
<!--[if !IE]>-->
<object id="testSVG" data="embed1.svg"
type="image/svg+xml" width="500" height="500">
<!--<![endif]-->
</object>
var obj = document.getElementById('testSVG');
var doc = obj.contentDocument; // grab the document object inside your SVG file
var myCircle = doc.getElementById('myCircle');
Note that the getSVGDocument() method, introduced by the Adobe ASV plugin, is not currently supported due to technical limitations (it is impossible to support on Firefox); you should use contentDocument instead.
If you want to dynamically create a new SVG OBJECT on your page, you must do the following. First, when you create your object, you must pass in the value 'true' to signal that this object will be used for SVG:
var obj = document.createElement('object', true);
Note that this is a divergence from the standard and is needed for the SVG Web magic to happen.
After creating your object, set it's 'data', 'type', 'width', and 'height' values, then add an onload listener to know when its ready to use:
var obj = document.createElement('object', true);
obj.setAttribute('type', 'image/svg+xml');
obj.setAttribute('data', 'rectangles.svg');
obj.setAttribute('width', '500');
obj.setAttribute('height', '500');
obj.addEventListener('load', function() {
alert('loaded!');
}, false);
To append your new SVG OBJECT to the page, you must use the svgweb.appendChild() method instead of calling appendChild on the element you want to attach it to. So if you wanted to attach it to the BODY element, you would do the following:
svgweb.appendChild(obj, document.body);
rather than:
document.body.appendChild(obj).
The svgweb.appendChild() method takes the SVG OBJECT to append as its first argument, and the parent to attach it to as its second argument.
The parent that you attach your SVG OBJECT to must already be attached to the real DOM on your page (i.e. it can't be disconnected from the page).
Note that our svgweb.appendChild method is a divergence from the standard necessary for SVG Web to do its magic.
The 'data:' URL scheme is supported by SVG Web. Therefore, you can directly specify the content of the SVG object instead of specifying a source file. This could be done when creating an SVG image from scratch or from dynamic content or when the SVG content is small and can be embedded directly in javascript or html for the performance advantage (since another source file need not be retrieved from the network).
So, if you want to create an blank SVG document, you could do the following:
obj.setAttribute('data', 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"></svg>');
rather than specifying a source file:
obj.setAttribute('data', 'blank.svg');
In markup, this would look like this:
<!--[if IE]>
<object id="testSVG" src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"></svg>'
classid="image/svg+xml" width="500" height="500">
<![endif]-->
<!--[if !IE]>-->
<object id="testSVG" data='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"></svg>'
type="image/svg+xml" width="500" height="500">
<!--<![endif]-->
</object>
Dynamically creating an SVG Root element is similar for direct embedding into a web page. You don't have to create a SCRIPT tag like you would if you were direct embedding the SVG on page load:
<script type="image/svg+xml">
<svg>
...
</svg>
</script>
Instead, you follow a process similar to the above:
// create SVG root element
var svg = document.createElementNS(svgns, 'svg'); // don't need to pass in 'true'
svg.setAttribute('width', '300');
svg.setAttribute('height', '300');
// create an example circle and append it to SVG root element
var circle = document.createElementNS(svgns, 'circle');
svg.appendChild(circle);
// Must use a callback to know when SVG is appended to page (this is slight
// divergence from standard). The following are supported ways to do this:
svg.addEventListener('SVGLoad', function() {
svg = this; // this will correctly refer to your SVG root
alert('loaded!');
}, false);
// also supported:
svg.onload = function() {
alert('loaded!');
}
// now append the SVG root to our document
svgweb.appendChild(svg, document.body); // note that we call svgweb.appendChild
Note in the above code that we have to use an event listener to know when the SVG root is finished loading into the page; this is a slight divergence from the standard necessary for SVG Web's magic.
The parent that you attach either your SVG root must already be attached to the real DOM on your page (i.e. it can't be disconnected from the page).
To remove an SVG OBJECT or SVG root, you must similarly call a special method on svgweb:
svgweb.removeChild(mySVGObject, parentNode);
The first argument to svgweb.removeChild
is the SVG
OBJECT or SVG Root to remove from the page, while the second is the parent node of
this object. Note that you must directly remove an SVG OBJECT or SVG root using the
above method; if you remove a parent node that might have an SVG OBJECT or root
as a distant descendant than resources might not be cleaned up correctly.
For example, if you have a container DIV that then has an SVG OBJECT, the following might have the SVG OBJECT disappear from the page but resources will not get cleaned up correctly, and memory will get wasted over time:
containerDiv = ''; // bad!!
// or
containerDiv.parentNode.removeChild(mySVGObject); // bad!!
One final subtle note; when you remove an SVG OBJECT or SVG root from the page make sure to use the correct reference. Any of the following will work:
svg = document.createElementNS(svgns, 'svg');
svg.setAttribute('width', 100);
svg.setAttribute('height', 100);
svg.id = 'dynamicRoot2';
svg.addEventListener('SVGLoad', function() {
// these are good:
svg = this;
svg = document.getElementById('dynamicRoot2');
// if this is the second SVG root:
svg = document.getElementsByTagNameNS(svgns, 'svg')[1];
svgweb.removeChild(svg, svg.parentNode);
}, false);
Note that using the direct reference caught by the closure will not work as expected under all situations; this is a limitation of SVG Web:
svg = document.createElementNS(svgns, 'svg');
svg.setAttribute('width', 100);
svg.setAttribute('height', 100);
svg.id = 'dynamicRoot2';
svg.addEventListener('SVGLoad', function() {
// bad!!
svgweb.removeChild(svg, svg.parentNode);
}, false);
See here for more details on this issue.
SVG Web implements the SVG suspendRedraw
, unsuspendRedraw
, and unsuspendRedrawAll
methods, which can be called on an SVG root tag. forceRedraw
is not currently implemented and there are no plans to do so.
suspendRedraw
can significantly speed things up when doing DOM operations in a loop on many elements. An example:
var root = document.getElementsByTagNameNS(svgns, 'svg')[0];
var circles = document.getElementsByTagNameNS(svgns, 'circle');
var suspendID = root.suspendRedraw(5000);
// let's say there are 500 circles
for (var i = 0; i < circles.length; i++) {
circles[i].setAttribute('fill', 'red');
}
root.unsuspendRedraw(suspendID);
// could also do root.unsuspendRedrawAll() to clear out all suspended
// operations
The suspendRedraw method takes a timeout in milliseconds until redrawing is forced; higher numbers are recommended. Under the covers for the Flash renderer we batch all the changes up and send them only when an unsuspend redraw operation is called, which makes things much faster.
The DOM DocumentFragment API is a way to efficiently add many DOM nodes to a page quickly; it is highly recommended when you are adding many SVG elements to a page quickly. This will significantly speed things up, especially if you are creating these nodes on page load. To create a DocumentFragment for use with SVG, you should call document.createDocumentFragment(true)
. Note the extra true
parameter -- this is required by SVG Web to help us know that this DocumentFragment will be used with SVG, possibly going into our fake Flash backend. A small code example:
// note the extra 'true' argument
var frag = document.createDocumentFragment(true);
for (var i = 0; i < 100; i++) {
var circle = document.createElementNS(svgns, 'circle');
circle.setAttribute('x', i * 10);
circle.setAttribute('y', 10);
circle.setAttribute('r', 5);
circle.setAttribute('fill', 'red');
// append to DocumentFragment
frag.appendChild(circle);
}
// now append the DocumentFragment to the DOM
var svg = document.getElementsByTagNameNS(svgns, 'svg')[0];
svg.appendChild(frag); // DocumentFragment disappears leaving circles
A few notes:
true
argument to document.createDocumentFragment(true)
when using DocumentFragments with SVG. This is an extra, non-standard argument necessary for SVG Web.Many web sites store their static files on a different domain than where many of their pages reside, such as static.example.com
. To accomodate this use case SVG Web has a special set of data-
attributes that can be used on your script tag.
Before diving into this, please note that SVG Web basically consists of a JavaScript file (svg.js
); a Flash SWF file (svg.swf
); and a Microsoft Behavior HTC file (svg.htc
). Due to limitations in Internet Explorer you can safely place the svg.js
and svg.swf
files on third-party domains, but the svg.htc
file must be on the same domain as your web page itself. The HTC file is quite small, however, so hosting it on the same domain as the page itself is not a serious limitation.
To host things separately, simply point the src
attribute on your script
tag that pulls in svg.js
to the full URL. SVG Web will automatically detect that you are pulling things in cross-domain and will grab the svg.swf
from the same location as the svg.js
file. You must still provide the data-path
attribute however; in this case you should provide the absolute or relative path to where the svg.htc
is located on the same domain as the page, such as ../../../src
or /src/.
example.com
with the svg.htc
file at example.com/src/svg.htc
but have the SVG Web library over on http://codinginparadise.org/projects/svgweb/src/
you would provide the following script
tag:
<script
type="text/javascript"
src="http://codinginparadise.org/projects/svgweb/src/svg.js"
data-path="/src/">
</script>
SVG Web supports the currentTranslate
and currentScale
attributes on the SVG root tag. These can make it much easier to do scripted zooming and panning of the entire SVG image. To use currentScale
, simply change the value to a number greater than 1 to zoom in and a number smaller than one to zoom out:
svgRoot.currentScale = 0.5; // zoom out
svgRoot.currentScale = 1.5; // zoom in
When using currentTranslate
, we have to diverge slightly from the SVG 1.1 standard to accomodate limitations in Internet Explorer. The standard supports setting and getting the translation x and y value directly as x
and y
attributes; we don't support this syntax:
// not supported
svgRoot.currentTranslate.x = 5;
svgRoot.currentTranslate.y = -10;
Instead, these have to be formal getters and setters, as follows:
svgRoot.currentTranslate.setX(5);
svgRoot.currentTranslate.setY(-10);
alert(svgRoot.currentTranslate.getX()); // should print 5
alert(svgRoot.currentTranslate.getY()); // should print -10
We also support a small non-standard extension to set both the X and Y values at once, which can give a slight performance speedup when using the SVG Web renderer with Flash:
svgRoot.currentTranslate.setXY(5 /* x */, -10 /* y */);
Note that we patch these methods into the native SVG environment for consistency, so the above will be available even when using SVG Web in a native environment on Firefox, Safari, etc.
* currentTranslate
is supported on the SVG root tag (see the section "Zooming and Panning with currentTranslate and currentScale" for details). However, due to limitations in Internet Explorer the way to work with this is slightly different when using SVG Web than the SVG 1.1 standard. See the section for
Most of the known issues are pretty minor and tend to affect edge conditions you won't run into often, but they are documented here for reference if you find that you are running into an issue:
* If you use the Flash viewer, and embed some SVG into a SCRIPT tag, the Flash will show up directly in the DOM as an EMBED tag (non-IE browsers) or an OBJECT tag (IE) with the 'class' set to 'embedssvg'. You can get the SVG root element by calling 'documentElement' on the EMBED tag (this is non-standard and is not part of the SVG 1.1 spec).
For example, if your page had an SVG SCRIPT block right under the BODY tag, this would get transformed into an EMBED tag with the Flash viewer:
BODY EMBED (class='embedssvg') svg root
Using script you could get the svg root node as follows:
var embed = document.body.childNodes[0];
if (embed.className && embed.className.indexOf('embedssvg') != -1) {
var svg = embed.documentElement;
// now have root SVG element and can manipulate it as normal
}
* Scoping getElementsByTagNameNS on elements other than the document element is not implemented yet. For example, you can not currently do document.body.getElementsByTagNameNS(svgns, 'rect') or myDiv.getElementsByTagNameNS(svgns, 'ellipse').
* If you have no HTML TITLE element on the page when using the native renderer, Safari 3 will incorrectly pick up the first SVG TITLE element instead and set the page title at the top of the browser. To correct this, if you have no HTML TITLE, we automatically place an empty HTML TITLE into the HEAD of the page, which fixes the issue.
* DOM Mutation Events are not supported and will not fire for SVG nodes when the Flash viewer is used (i.e. if you create an SVG circle and then attach it to the document, a DOM Mutation event will not fire).
* You should declare all of the namespaces you want to use on one of your SVG root elements before calling createElementNS; unknown namespaces will not work afterwards. For example, if you have the following SVG:
<svg id="mySVG" width="500" height="500"><metadata/></svg>
You could not do the following:
var dc = document.createElementNS('http://purl.org/dc/elements/1.1/',
'dc:creator');
var metadata = document.getElementsByTagNameNS(svgns, 'metadata')[0];
metadata.appendChild(dc);
This is because the DC (Dublic Core) namespace is not declared. To make
this work, you should have the namespace on your SVG root markup:
<svg id="mySVG" width="500" height="500"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata/>
</svg>
Note that this limitation is done on purpose to support existing XHTML documents that want to use createElementNS for their own purposes. This is also a limitation imposed by the XML namespace model itself rather than a limitation of the SVG Web framework.
* On Internet Explorer we don't support wildcarding a given tag name across known namespaces and a given tag:
getElementsByTagNameNS('*', 'someTag');
We _do_ support wildcard calls of the following type:
getElementsByTagNameNS('*', '*');
getElementsByTagNameNS('someNameSpace', '*');
getElementsByTagNameNS(null, 'someTag');
The same limitation applies when using getElementsByTagNameNS scoped to a particular node, so the following would not work on Internet Explorer:
someNode.getElementsByTagNameNS('*', 'someTag');
* insertBefore and replaceChild only accepts DOM element nodes for now, not DOM text nodes
* Only DOM element, text, and document type nodes are supported across the framework; this means you can't dynamically work and insert processing instructions, comments, attributes, etc.
* The isSupported() method on SVG DOM Nodes is not natively supported by Firefox, so therefore doesn't work when the Native Handler is being used on that platform:
mySvgPath.isSupported('Core', '2.0')
It works on Safari and when the Flash Handler is being used on all browsers.
* On Internet Explorer, DOM text nodes created through document.createTextNode with the second argument given as 'true':
document.createTextNode('some text', true)
will have a .style property on them as an artifact of how we support various things internally. Changing this will have no affect. Technically DOM text nodes should not have a .style property.
* On Internet Explorer, the cssText property on an SVG node's style object should not be set or retrieved; it will have unreliable results. For example, calling myCircle.style.cssText will not correctly return the SVG CSS of that node; you will instead see some custom internal properties that we use to support some of the framework magic on Internet Explorer.
* The Firefox 3's native implementation of SVG doesn't correctly mirror inline style="" attributes into element.style.* values. For example, if I have the following SVG element:
<path id="myPath" style="display: block; fill: red; opacity: 0.5" />
and then I access it's style properties:
var myPath = document.getElementById('myPath');
console.log(myPath.style.fill); // does not print 'red' on Firefox!
Note that this is a bug in the Firefox browser itself and not from us. The native SVG renderer on Safari does not have this issue. We correctly parse and expose our style properties for the above case for the Flash renderer.
* By default the SVG root element has an overflow of hidden. If you make the overflow visible, when using the Flash renderer elements will not overflow outside of the containing Flash movie as we can't support rendering things outside of the Flash movie.
* If you are using the Flash renderer on a browser that has native SVG support, and use the OBJECT tag to embed an SVG file, the browser's native support might render the OBJECT tag first before we can get to it, followed by our Flash renderer taking over and then rendering things. This might result in a slight flash, or your embedded SVG file having it's onload() event fired twice.
* If you dynamically change the data attribute of an SVG OBJECT element after page load, the updated SVG will not load for the Flash Handler and certain patched functions for the Native Handler will no longer work.
* You should avoid IDs on your OBJECT, SVG root, or SVG elements that start with numbers, such as "32MyElement". The SVG Web framework will not work correctly with such IDs.
* If you are using OBJECT tags to embed your SVG into the page while using the Flash handler support:
<!--[if IE]>
<object id="mySVG" src="embed1.svg"
classid="image/svg+xml" width="500" height="500">
<![endif]-->
<!--[if !IE]>-->
<object id="mySVG" data="embed1.svg"
type="image/svg+xml" width="500" height="500">
<!--<![endif]-->
<img src="scimitar.png" />
</object>
and call document.getElementsByTagName('object'), note that on Firefox and Safari the OBJECT tag gets transformed into an EMBED tag by the browser itself beyond our control, so you must call document.getElementsByTagName('embed') instead of asking for objects in order to enumerate all the SVG OBJECTs on the page.
TODO: FIXME: Check to make sure this is still true.
* The 'this' keyword in an external SVG file when brought in with an SVG OBJECT tag when using the Flash renderer isn't always correct. For example, if you have the following SVG file:
<svg onload="loaded(this)">
<script><![CDATA[
function loaded(onloadThis) {
// onloadThis correctly points to our SVG root element
// call some other function
anotherFunc();
}
function anotherFunc() {
alert(this); // 'this' incorrectly points to the containing HTML pages
// window object
}
]]></script>
</svg>
If you use the 'this' keyword inside of an onload="" attribute on the SVG root tag, it will correctly point to the SVG root element. However, if you use the 'this' keyword later on inside of a script block, such as in a function, it will incorrectly point to the containing HTML page's window object. Correct behavior would be for it to point to the SVG object's own window object.
In general, though, you should not be using the 'this' keyword to grab a reference to a window object; this is bad programming. Instead, you should directly call and use window and only use 'this' when doing object-oriented JavaScript development:
<svg onload="loaded(this)">
<script><![CDATA[
function loaded(onloadThis) {
// onloadThis correctly points to our SVG root element
anotherFunc();
}
function anotherFunc() {
alert(window); // correctly points to just our SVG OBJECT window
}
function SomeClass() {
this.someProp = 'foo'; // 'this' correctly points to SomeClass instance
}
var instance = new SomeClass();
]]></script>
* If you are dynamically creating an SVG OBJECT with the Flash handler, after creation the SVG OBJECT will not correctly point to a reference to that OBJECT that might have been captured outside of a closure. For example, if you have the following code:
var obj = document.createElement('object', true);
obj.setAttribute('type', 'text/svg+xml');
obj.setAttribute('data', 'myfile.svg');
obj.addEventListener('load', function() {
alert(obj.parentNode); // will incorrectly return null!
}, false);
svgweb.appendChild(obj, myParentNode);
Notice that we access 'obj.parentNode' after the SVG OBJECT has finished loading, and this incorrectly returns 'null' instead of the actual 'myParentNode' value. 'obj' will not reference the actual Flash object as you would expect, so you should not continue using the value inside the closure or later on as a stored value.
There are two workarounds. First, 'this' inside your onload handler will correctly reference the actual Flash object so you can further manipulate it or store the value:
var obj = document.createElement('object', true);
obj.setAttribute('type', 'text/svg+xml');
obj.setAttribute('data', 'myfile.svg');
obj.addEventListener('load', function() {
obj = this;
alert(obj.parentNode); // correctly prints 'myParentNode'
}, false);
svgweb.appendChild(obj, myParentNode);
You can also of course use getElementById if you gave your SVG OBJECT an id:
var obj = document.createElement('object', true);
obj.setAttribute('type', 'text/svg+xml');
obj.setAttribute('data', 'myfile.svg');
obj.setAttribute('id', 'mySVG');
obj.addEventListener('load', function() {
obj = document.getElementById('mySVG');
alert(obj.parentNode); // correctly prints 'myParentNode'
}, false);
svgweb.appendChild(obj, myParentNode);
Note that similar issues pertain to svgweb.removeChild
when dealing with SVG OBJECT references. See here for more details.
* Inside of an SVG OBJECT for the Flash handler, if you access the window.location value for that file and try to change it, nothing will happen. You can, however, read the values off this object and they will correctly represent the URL of the object as given in the data or src attribute of the OBJECT. You could use this to pass parameters into your SVG file, for example.
* XML Comments (such as <!-- Hello World -->) will not show up in the DOM when using the Flash handler.
* If you have nested SVG elements (i.e. having an <svg> element nested in your document), these don't currently show up in the DOM correctly.
* On some installations of Internet Explorer depending on what patches might be present, if you have "Disable Script Debugging" unchecked, you might see the Eolas "Click to activate" box around your Flash movies before users can interact with them. This will only happen once. It is rare for computers to have this box unchecked plus not having the right patches (this issue was fixed in later patches by Microsoft). The issue is documented here: http://code.google.com/p/svgweb/issues/detail?id=153
* Be careful doing complicated styling directly on an SVG OBJECT during creation when using the Flash handler, as the values might not get correctly copied over on Internet Explorer or can cause unusual glitches on Firefox/Flash. Avoid this:
var obj = document.createElement('object', true);
obj.setAttribute('type', 'image/svg+xml');
obj.setAttribute('data', someURL);
obj.setAttribute('width', 300);
obj.setAttribute('height', 300);
obj.addEventListener('load', myObjLoaded, false);
// avoid this
obj.setAttribute('style', 'position: absolute; z-index: -1000; top: 0px; right: 0px')
// or this
obj.style.position = 'absolute';
obj.style.zIndex = -1000;
obj.style.top = '0px';
obj.style.right = '0px';
svgweb.appendChild(obj, myPage);
Instead, you should do your advanced styling on a div
or span
container and place the SVG OBJECT inside of that container:
var obj = document.createElement('object', true);
obj.setAttribute('type', 'image/svg+xml');
obj.setAttribute('data', someURL);
obj.setAttribute('width', 300);
obj.setAttribute('height', 300);
obj.addEventListener('load', myObjLoaded, false);
// position object using a DIV container to avoid
// strange style + OBJECT interactions
var container = document.createElement('div');
container.style.position = 'absolute';
container.style.zIndex = 1000;
container.style.top = '0px';
container.style.left = '0px';
myPage.appendChild(container);
svgweb.appendChild(obj, container);
* currentTranslate
is supported on the SVG root tag (see the section "Zooming and Panning with currentTranslate and currentScale" for details). However, due to limitations in Internet Explorer the way to work with this is slightly different when using SVG Web than the SVG 1.1 standard. See the section for details.
If you remove an SVG OBJECT with svgweb.removeChild
and then re-attach it, things will not work. You must create a fresh SVG OBJECT in this case.
If you do a cloneNode
on a node or group of nodes that have event listeners, these event listeners will not get copied over; this mimics the native behavior on Firefox and Safari which do not copy over event listeners from cloned nodes.
currentTranslate
and currentScale
will only work on the SVG root tags of SVG OBJECTs. If you apply them on directly embedded SVG the results will be unexpected (Safari/Native, for example, will scale the entire page). This makes sense as the SVG directly embedded into a page doesn't have its own translate or scale presence apart from the page itself.