
Extending SVG for XForms
Introduction
If you've read my previous columns, it should be clear that SVG provides what programmers and designers need to create interactive 2D graphics. What makes SVG a little special is the versatility it inherits from XML. XML vocabularies are meant to be extended and intermixed with one another. But despite some noteworthy efforts to create XML-aware browsers, like XSmiles, Amaya, and Mozilla, rock-solid SVG-centric browser applications are not quite ready. But it may be possible to start implementing XForms UI controls in SVG.
In previous columns we looked at SVG DOM in simple drag and
drop or event handling and remote animation control. This
month we're going to implement the XForms
<button> element with CSS support, which
will serve as an applied study on extending SVG's semantics
with foreign elements and attributes.
The Task at Hand
Our task has three parts: parsing, instantiating objects, and
interacting with them. Parsing is the part where we are going to
look up XForms content in our document and try to make some
sense of it. We will then use the gathered information to build
an internal EcmaScript object model and draw the form
controls. Interaction is the part where we use event handlers to
create the different states of the button and allow for
callbacks to be registered when it is pressed. This month, we'll
take care of the XForms <button> element
alone, concentrating on the process of integrating a new
namespace with SVG; we'll look at the the interactivity and
object modeling next month. So our first task is to read an
SVG+XForms document and draw a static button. Consider this
simple document:
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:a3="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
xmlns:forms="http://www.w3.org/2002/01/forms"
a3:scriptImplementation="Adobe"
xml:space="preserve"
onload="XForms.init(evt)">
<title>Simple implementation of the XForms <button> element</title>
<script a3:scriptImplementation="Adobe" type="text/ecmascript"
xlink:href="XFormsButton.es" />
<g transform="translate(50,50)">
<forms:button style=" color: blue;
border-color: red;
border-width: 1px;
background-color: pink;">
<forms:caption>This is a test</forms:caption>
</forms:button>
</g>
</svg>
View this example as (static) SVG
|
In addition to the Adobe-specific attributes, you'll notice
the declaration of the XForms namespace on the
<svg> element and the
<forms:button> element in that
namespace. You will also notice the use of CSS properties
straight out of the CSS 2 Box
Model. These are all things that we will need to parse to
draw a pink button.
Parsing XForms elements with the DOM
To get started, we have to navigate through the XML tree
looking for <forms:button> elements, which
hold the data we need. The fact that these elements are
described in a separate namespace make this easy. In fact,
getting a data structure (here, a NodeList)
holding all the buttons is done in a single line of code:
var buttonElements = root.getElementsByTagNameNS(XForms.ns, 'button');
If you look at the small EcmaScript
library I've built, you'll see that I've referenced the
XForms namespace in an object, so it is easy to reference. This
line of code was taken from the Button.init()
function, called by the XForms.init() that we
call when loading the SVG document is done. The rest of this
function will recurse through all the nodes in our NodeList
and call further initialization code on each element:
for (var i=0; i<buttonElements.length; i++) {
var elem = buttonElements.item(i);
var button = new Button(elem);
button._draw();
}
|
Related Reading
|
We have built a custom Button EcmaScript object
that can be constructed with a pointer to a
<forms:button> element as an
argument. Looking at that object we can see it has the
following methods defined: generateSVGStyle() and
generateSVG(). Both these methods will be called
from Button._draw(), which renders the button
as SVG.
In order to parse XML with the DOM we read the caption's text
from the <forms:caption> element. Text in
XML is a bit tricky to handle. We have something called text
nodes, but unfortunately, a text node might not be exactly
what you expect. Even though you printed out a
nicely-formatted line of text, you might end up with a heap of
text nodes that will be a pain to process. Here's how we took
a crack at it in the Caption.getText() method:
Caption.prototype.getText = function () {
this.element.normalize();
return this.element.firstChild.data;
}
The normalize() method (from the mother-of-all Node
interfaces) is a great help here, since calling it on our
<forms:caption> element will ensure we will
encounter only one text node for the whole string. After
calling it, we can safely return our first and only child's
data.
Pages: 1, 2 |
