SVG 2 DOM

From SVG
Revision as of 01:32, 26 March 2012 by Bbirtles (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Background

It has been recognized for a long time that there are serious issues with the existing SVG DOM interfaces. The SVG WG will be taking a hard look at these issues to see what can be done to resolve or improve the situation in SVG 2.0. This page documents the known issues and acts as a collection point for DOM ideas and proposals for SVG 2.0.

SVG 1.1 DOM Issues

Performance issues

One of the things that's more attractive about Canvas than SVG is that immediate-mode graphics typically render much quicker than retained-mode graphics. It is evident that there exists a requirement for speed as well as interactivity. Where the SVG DOM seems to fall is when SVG needs to be built and changed dynamically.

As per the previous topic, issues with implementing the SVG 1.1 DOM API have been raised by browser vendors. One such example is;

In SVG:

var c = document.createElementNS(http://www.w3.org/2000/svg, "circle");
c.cx.baseVal.value = 20;
c.cy.baseVal.value = 20;
c.r.baseVal.value = 20;
c.style.fill = "lime";
svgContainer.appendChild(c);

In the above SVG example Setting the three circle attributes via the SVG API requires 9 round trips (6 getters and 3 setters) from JavaScript to browser and back. Additionally, it requires creation of at least 6 temporary objects.

However, for Canvas:

ctx.fillStyle = "lime";
ctx.beginPath();
ctx.arc(20, 20, 20, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();

The above Canvas example does appear to be less verbose. Both APIs (or a similar Canvas one) should be implemented such that they construct the same DOM to test the speed difference in changing DOM object construction.

One suggestion is to have an interface that allows the following:

c.cx = 20;
c.cy = 20;
c.r = 20;

Notes:

  • There are hacks that exist to get around the verbosity problem.
  • The SVG Working Group has a proposal to simplify these SVG DOM accessors in SVG 2.0.
Summary of links

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0015.html

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0019.html

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0021.html

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0022.html

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0023.html

Making Improvements

After discussing DOM improvements in an SVG telephone conference the SVG Working Group received feedback from the community on how the SVG 1.1 DOM could be improved in SVG 2.0.

  • Experimenting APIs before committing to them is something that should be done. An API similar to Canvas would be desirable, however access to segments is not provided when they are created in Canvas. The SVG Tiny 1.2 SVGPath API is similar to what the Canvas path methods offer.
  • Much of the SVG DOM overhead (and complexity) of the PathSegList interfaces come from the keep-lists-in-sync-at-all-times requirement. The SVG Working Group should check this requirement to see if it is absolutely necessary and if there are compelling use cases. If not then, it could probably be dropped.
    • The combination of the SVGPath interface and the SVGPathSegList interfaces could be a solution possibly, use the path creation methods from SVGPath, then inspect and change segments with the methods given in the SVGPathSeg\* interfaces.
    • birtles 2012-03-26: An API to get the points as an array of floats would be really useful (and is a fairly common feature for such APIs). The operation would be basically be similar to normalizedPathSegList except straight line segments and close path segments would also be converted to cubic beziers. The return value would be an array of subpaths, each being an array of floats. A similar API to create / update a path from such an array would also be needed. This allows complex path operations to be performed on arbitrary paths efficiently (rather than testing the type of each segment).
  • Whatever simpler API is devised, it should be serialisable (i.e. convertible into a DOM upon request). Both E4X and Web DOM might be worth studying.
  • Performance measurements of the DOM as well as other parts of SVG (SMIL, use, non-native text layout) should be taken to determine the overhead of each. However, it is expected that;
    • a large portion of the overhead is bookkeeping and DOM management,
    • SMIL can be slow, and this largely due to the bookkeeping it has to do,
    • complex text layout can be slower than aligned text, but not by much.


General Applicability

Obviously, any new methods that improve SVG could be used for non-graphical content as well, including other languages like HTML, MathML, etc. If other Working Groups are interested in the ideas here, it may be advisable to develop this as part of a joint task force with the WebApps WG.


Summary of links

http://www.w3.org/2009/07/15-svg-minutes.html

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0030.html

http://lists.w3.org/Archives/Public/www-svg/2009Jul/0032.html

SVG 2.0 DOM

The SVG Working Group is looking at improving the DOM for SVG 2.0. Suggestions on how to carry out the improvements are:

  • Leave the majority of the SVG 1.1 DOM intact. Changes would include rearranging some stuff, clarify loose wording, and dropping unimplemented features
  • Complete rewrite: develop a new DOM for SVG 2.0.

Clearly there are advantages and disadvantages of each approach. Given the above information, there are a number of questions:

  • What is the best way to improve the DOM API for SVG 2.0?
  • What features should be kept?
  • What features should be dropped?
    • Should any new features be added? (note: use cases and requirements for suggesting new features is a must)

Most likely, the best solution would be somewhere between adherence to legacy and a complete rewrite.

Ideas

Here are a collection of random ideas. Split them out into a separate page (linked to from here) if they start to become more concrete proposals.

Array getters and setters

The SVG*List interfaces should all support the normal array syntax used in other DOM specs, that is: list.length, list[i]. See http://www.w3.org/Graphics/SVG/WG/track/issues/2323. (This has been already been implemented by Opera)

Global ECMAScript constructors

See the Global ECMAScript Constructors proposal.

Simple SVG API

Many of the ideas on this page have been expanded and implemented as a simple prototype in the Simple SVG API proposal.

valueOf

Another ECMAScript only idea.

See Issue 2044. This would work by specifying a valueOf function on relevant prototype objects such as SVGAnimatedLength, or by specifying a value for these object's DefaultValue internal property (the internal DefaultValue method by default in ES232 calls valueOf on the object). The latter method would not work for SVGAnimatedBoolean objects though, since the ECMAScript ToBoolean() operator doesn’t invoke DefaultValue like ToNumber() does. Also, unary ! won’t invoke valueOf on an object (it just evaluates to true for all objects). Even more troublesome would be == and !=. If you had rect.x and rect.y both be SVGAnimatedLengths whose values were 10, then rect.x == rect.y will evaluate to false, since == will check for object identity (jwatt: is that correct? isn't that what === is for? Hmm, integrate in http://www.w3.org/mid/4A693CFE.1060009@mit.edu once we've figured out what that means for us). You’d need to do rect.x == +rect.y or something instead.

The advantage of this idea is that it could work without breaking the existing baseVal stuff though, and that's important as there's likely too much content out there that relies on that now. (jwatt: is that true? are there no circumstances under which the existing DOM stuff could be broken?)

jwatt: heycam, it would be great if you could expand on the details here of how this would work, and how and where it would break down.

Getter and setter for groups of attributes

In ECMAScript, it would be very nice to be able to do:

element.setAttributes( { x:10, y:20, width:"100%", height:"2em", fill:"lime" } );

Likewise, it would be nice to be able to do something similar with getters. For more, see Simple SVG API.

Get rid of the need to explicitly specify a new element's namespace

It would be good to have a createElement method to the Element interface that would create an element in the same namespace as the element on which it's called (and would not require you to get a Document object). For more see Simple SVG API.

Constructors for Elements

One option for making the SVG DOM faster and more convenient for authors would be element constructors, either on a per-element basis, or a generic constructor. These can already be simulated in JavaScript libraries as convenience methods, but the chief benefit, making fewer DOM calls and increasing the speed of script, would be lost.

Note that all of the following constructors assume an implicit namespace mechanism (as proposed above), where the element created takes on the same namespace as the element it is called on. For explicitly creating an element in a namespace other than that of the parent document or element (for example, creating an HTML p element inside an SVG context), there could be namespace-aware versions of all of these methods. For namespaced attributes, the traditional namespace-aware setAttributeNS() could be used, or some syntax could be devised for the constructor. The proposal below suggests that namespaced attributes should pass an array as the value, with the first item being the attribute namespace, and the second item the attribute value.

Note also that for all object parameters, the attribute value names must be quoted if they contain a dash ("-"); other attribute value names may optionally be quoted.

Element-Specific Constructors

Having well-defined and specific constructors for individual elements might be better for languages such as Java, and might appeal more to people just learning SVG, since it could give more detailed error messages, but would increase implementation size and time.

var r = document.createRectangle( string id, length x, length y, length width, length height, length rx, length ry,  object style );
document.documentElement.appendChild( r );
var c = document.createCircle( string id, length cx, length cy, length r, object style );
document.documentElement.appendChild( c );
var p = document.createPath( string id, string d, object style );
document.documentElement.appendChild( c );
var lg = document.createLinearGradient( string id, length x1, length y1,  length x2, length y2 );
lg.appendChild( document.createColorStop( string id, length offset, string stop-color,  length stop-opacity ) );
document.documentElement.appendChild( c );

Generic Constructors

A generic constructor would offer less specific functionality, but would be more extensible, and easier to remember. It would require authors to use more explicit object notation than the element-specific constructors, but would also allow them to omit unwanted values, which would default to the lacuna value.

Note: This proposal is expanded in more detail and with more features, with a simple prototype, at Simple SVG API.

Insertion Constructors

Both proposals above assume that the element will be returned as a object, which is then appended to the DOM in the usual way. However, creating the element in the same single step as it is constructed would be even easier for authors in most instances. The would require that the constructor method is available on the Element object, so that the newly minted element is appended to the DOM in the right location. A pointer to the new element would still be returned by the method, but would not need to be added separately.

Note: This proposal is expanded in more detail and with more features, with a simple prototype, at Simple SVG API.

Insertion Constructors for Specific Elements

A less general form of the above would be methods that insert particular graphical elements as children of a given element.

element.drawRect(10, 20, '100%', '2em', { fill: 'cornflowerblue' });
element.drawCircle('50%', 100, 30, { stroke: 'red', 'stroke-width': 5, fill: 'none' });
element.drawPath("M150,150 L200,100 H250 V170 Q350,90 375,150 T400,150 C500,100 575,300 560,150 
                  S650,160 550,300 Z M500,200 A25,35 -80 1,1 450,220 Z", { stroke:"blue", 
                  stroke-width:"1", fill:"yellow", fill-rule:"evenodd" });
Specific Commands for Paths

Canvas has specific methods for its path commands, which would often be easier than composing the string for a path element's @d attribute. The Canvas commands are roughly equivalent to SVG, so it should be simple to add these to the path element interface:

  • ctx.beginPath() // would use var el = element.drawPath() instead
  • el.moveTo(x, y)
  • el.lineTo(x, y)
  • el.arc(x, y, radius, startAngle, endAngle, anticlockwise) // this is different than SVG's path arc command, could include both
  • el.quadraticCurveTo(x1, y1, x2, y2) // the first pair of points are the control point, the last pair of points is the end point
  • el.bezierCurveTo(x1, y1, x2, y2, x3, y3) // the first two pairs of points are the control points, the last pair of points is the end point

Common Graphical API

This last two approaches are roughly similar to the Canvas API, but any of these approaches could be specified to return either a DOM or draw directly to a buffer and return a a reference to that, depending on whether it was called in a document/vector context ("document", "<svg>") or a raster image context ("<canvas>", "<image>"). This way, authors would only have to learn one syntax, and could use the same API for both, modulo differences in underlying rendering models.

(Doug: I call this idea of a single syntax to use create and manipulate both SVG and Canvas COG: Common Open Graphics.)

Backwards Compatibility and Deployment

Note: This proposal is expanded in more detail and with more features, with a simple prototype, at Simple SVG API.

innerHTML type facilities

It would be good if XML had an innerHTML-like feature. Writing markup in an ECMAScript string can be a bit of a pain, but it can also simplify things a lot, and to get better that that for the types of scenario in which it's useful probably means E4X-like capabilities.

Calling this facility innerHTML would make it seem like the markup should be parsed as being in the XHTML namespace, so maybe innerMarkup or insertCode would be a better name, or, for symmetry with textContent, maybe markupContent.

Construct DOM trees from JSON

One proposal for making the creation of SVG content using ECMAScript easier is to have a method that will create an SVG DOM tree from JSON. This does not seem very promising however. See JSON Constructors for more.

HTML canvas API

There has been some talk of allowing SVG content to be build up using the HTML canvas API, and at least one JS lib allows this (see Canvas-SVG Bridge). Of course this doesn't address the issues of reading or manipulating the DOM, but it could be useful at least for creating.

Simpler SVGAnimatedLength access

One idea floated during the Auckland 2011 F2F was to give SVGAnimatedLength and SVGLength objects properties that expose the length's value in particular units, like CSS OM is going to. You would be able to do:

myCircle.cx.px = 100;
myCircle.cy.em *= 2;

These would be shorthands for manipulating the SVGAnimatedLength's base value. We would provide these properties on the actual SVGLength objects, too:

var animatedCircumference = 2 * Math.PI * myCircle.animVal.r.px;

This could be extended to other SVGAnimatedBlah interfaces.

Other APIs

E4X

E4X has a lot of attractive features, but it has proved to be a very poorly designed specification, and there is no bridge between E4X and the DOM in implementations. (See Brendan and Jeff's comment's.) While you can create XML using E4X, there is no way to insert that XML into an existing DOM tree. (Why is that??) Maybe E4X can be used for ideas though.

HTML canvas wrapper APIs

A number of APIs have been built on top of the canvas API (which is quite low level) that could be investigated (Processing.js etc). (These also have animation APIs that might be worth looking at too.)

"simpler DOM" efforts

For example, Web DOM.

Script Libraries

We should look at successful script libraries like jQuery, RaphaelJS, dojo.gfx, prototype, YUI and others for inspiration on functionality and syntax. We should investigate author feedback on the benefits and downsides to those languages, and if possible, talk to the folks behind them for lessons learned.

HTML canvas API

There has been some talk of allowing SVG content to be build up using the HTML canvas API, and at least one JS lib allows this (see Canvas-SVG Bridge). Of course this doesn't address the issues of reading or manipulating the DOM, but it could be useful at least for creating.