SVG DOM Helper

Author: Domenico Strazzullo
nst@dotuscomus.com
Creative Commons License
This work is licensed under a Creative Commons Attribution-No Derivative Works 3.0 Unported License.
  1. Description
  2. SVG DOM Helper function
  3. Use
  4. Examples
  5. HTML DOM Helper function
  6. HTML DOM Helper function for use with <foreignObject>
Download DOMjs.zip

DESCRIPTION

This progressive SVG DOM Helper, like the two HTML derivatives, is a universal node builder. Universal in the sense that it will work for any SVG element, eliminating the need for defining individual classes for SVG elements, with their necessarily limited and arbitrary collection of n properties/attributes.

It expects 1 object and returns a reference to the SVG element in the DOM. The object literal or reference passed as argument contains the definition of any attribute that needs to be set, including the style attribute, without any artifact or appendices, in one pass. It does not arbitrarily set any SVG attributes with initial values, except when these are specifically defined in the object.

The basic concept behind its design is that of interfacing the SVG library (the implementation) directly, using the library's language, thus skipping the need for cumbersome and redundant pseudo-languages.

Also provided are two derivatives: HTML DOM Helper for use with <foreignObject>, and "regular" HTML DOM Helper with no namespace.

SVG DOM Helper function

var svgNS = "http://www.w3.org/2000/svg",
    xlinkNS = "http://www.w3.org/1999/xlink";


var SVG = function(o) {
  for (var p in o) {
    var value = o[p];
    switch(p) {
      case "element" : var element = document.createElementNS(pergola.ns.svg, value);
      break;
      case "textNode" : element.appendChild(document.createTextNode(value));
      break;
      case "appendTo" : value.appendChild(element);
      break;
      default : element.setAttributeNS((p == "xlink:href") ? xlinkNS : null, p, value);
    }
  }
  return element;
};

USE

The function expects 1 argument of type object.

The property/value pairs of the object can be any SVG attribute name/attribute value.

Property names designating SVG attribute names that contain illegal JavaScript characters for variable/property names must be of type string. Ex: 'fill-opacity'; 'xlink:href' ...

The function is designed to evaluate 3 properties whose names are not in the SVG namespace. These are:
element; textNode; appendTo.

element. Required. It gets a string specifying the name of the element to create. This must be the first property defined in the object. If it is not enumerated as first or if it is absent you will get a runtime error.

textNode. Optional. It can be used while creating a text element. The text node is automatically created and appended to the text element.

appendTo. Optional. Specifies the parent node to which the element is to be appended. The element can be appended manually or programmatically at a later stage in your program. A generic value for the appendTo property can be document.documentElement. If you set this property its value must be an existing and valid container, whether defined in loco or referenced.

All the other properties representing SVG attribute names are not evaluated (this is done by the browser's parser), and is your responsibility to see that they are coherent and conformant, just like when coding SVG.

The call can be referenced or not. The function returns the element itself, meaning that whenever the call is assigned to a variable or property, this is then a pointer to the element in the DOM tree.

Note that, contrary to a certain mythology, the order of the enumeration of array elements or object properties in the for in loop IS guaranteed as long as the object is not manipulated by array methods or the delete operator in case of objects. It is a mistake to interpret the javascript specification warning about the order not being guaranteed, as meaning that the array indices or object properties (as labeled indices) are not stored sequentially contiguous in memory. The confusion may come from the fact that the indices are not required to be ordinally contiguous. The table has a base address (the address of the first index) and the address of the indices is calculated on that. The addresses to which the indices point contain the values of the elements and can be anywhere in memory. For further and probably better explanations you can consult literature on processors or assembly language. The for in loop is perfectly safe and a good habit as long as it is handled with care.

EXAMPLES

Note that some of these examples are out of their context and would produce errors, that is, those using undefined variables or the this keyword.

An <svg> element:

this.control = createSVGElement({
  element: "svg",
  id: this.id,
  x: this.x,
  y: this.y,
  width: this.width,
  height: this.height,
  appendTo: document.documentElement
});

A <g> element:

createSVGElement({element: "g", transform: "translate(100 100)", appendTo: this.control});

A <linearGradient> element:

var gradient = createSVGElement({
  element: "linearGradient",
  id: "buttonMaskGrad",
  x1: "0%",
  y1: "0%",
  x2: "0%",
  y2: "100%",
  gradientUnits: "objectBoundingBox",
  appendTo: defs
});
createSVGElement({element: "stop", offset: "...", "stop-color": "...", appendTo: gradient});
createSVGElement({element: "stop", offset: "...", "stop-color": "...", appendTo: gradient});

A <circle> element:

createSVGElement({
  element: "circle",
  r: 9,
  fill: "none",
  stroke: "red",
  appendTo: someParentNode
});

A <text> element:

createSVGElement({
  element: "text",
  x: 80,
  y: 40,
  'font-family': "'Trebuchet MS'",
  'font-size': "18pt",
  'text-anchor': "middle",
  textNode: "COOL",
  'pointer-events': "none",
  appendTo: document.documentElement
});

A <rect> element:

var myRect = createSVGElement({
  element: "rect",
  x: 40,
  y: 40,
  width: 400,
  height: "3in",
  transform: "scale(.5)"
  fill: "blue",
  stroke: "gray",
  'stroke-width': 8,
  'stroke-dasharray': "4,5",
  'fill-opacity': .5,
  appendTo: someParentNode
});

HTML DOM Helper function

var HTML = function(o) {
  for (var p in o) {
    var value = o[p];
    switch(p) {
      case "element" : var element = document.createElement(o.element);
      break;
      case "textNode" : element.appendChild(document.createTextNode(value));
      break;
      case "appendTo" : value.appendChild(element);
      break;
      default : element.setAttribute(p, value);
    }
  }
  return element;
};

Note that unlike the SVG DOM Helper, where we can use the textNode property only when creating a <text> or <tspan> element, with the HTML DOM Helper we can set it for practically any element, <body>, <div>, <p>, <span>, etc.

HTML DOM Helper function for use with <foreignObject>

Use this code to produce html code in <foreignObject> (first create a <foreignObject> element with the SVG DOM Helper).

var HTMLFO = function(o) {
  for (var p in o) {
    var value = o[p];
    switch(p) {
      case "element" : var element = document.createElementNS("http://www.w3.org/1999/xhtml", o.element); 
      break;
      case "textNode" : element.appendChild(document.createTextNode(value));
      break;
      case "appendTo" : value.appendChild(element);
      break;
      default : element.setAttribute(p, value);
    }
  }
  return element;
};

Note that unlike the SVG DOM Helper, where we can use the textNode property only when creating a <text> or <tspan> element, with the HTML DOM Helper we can set it for practically any element, <body>, <div>, <p>, <span>, etc.

Note: This works well with Firefox only, but only partially with Opera and Webkit. IE9 does not implement <foreignObject>. You are free to experiment with and modify the HTML DOM Helper function for use with <foreignObject>.