1 // TODO don't populate default attributes?
  2 
  3 /**
  4  * @private
  5  * @namespace
  6  */
  7 pv.Scene = pv.SvgScene = {};
  8 
  9 /**
 10  * Updates the display for the specified array of scene nodes.
 11  *
 12  * @param scenes {array} an array of scene nodes.
 13  */
 14 pv.SvgScene.updateAll = function(scenes) {
 15   if (!scenes.length) return;
 16   if ((scenes[0].reverse)
 17       && (scenes.type != "line")
 18       && (scenes.type != "area")) {
 19     var reversed = pv.extend(scenes);
 20     for (var i = 0, j = scenes.length - 1; j >= 0; i++, j--) {
 21       reversed[i] = scenes[j];
 22     }
 23     scenes = reversed;
 24   }
 25   this.removeSiblings(this[scenes.type](scenes));
 26 };
 27 
 28 /**
 29  * Creates a new SVG element of the specified type.
 30  *
 31  * @param type {string} an SVG element type, such as "rect".
 32  * @return a new SVG element.
 33  */
 34 pv.SvgScene.create = function(type) {
 35   return document.createElementNS(pv.ns.svg, type);
 36 };
 37 
 38 /**
 39  * Expects the element <i>e</i> to be the specified type. If the element does
 40  * not exist, a new one is created. If the element does exist but is the wrong
 41  * type, it is replaced with the specified element.
 42  *
 43  * @param type {string} an SVG element type, such as "rect".
 44  * @return a new SVG element.
 45  */
 46 pv.SvgScene.expect = function(type, e) {
 47   if (!e) return this.create(type);
 48   if (e.tagName == "a") e = e.firstChild;
 49   if (e.tagName == type) return e;
 50   var n = this.create(type);
 51   e.parentNode.replaceChild(n, e);
 52   return n;
 53 };
 54 
 55 /** TODO */
 56 pv.SvgScene.append = function(e, scenes, index) {
 57   e.$scene = {scenes:scenes, index:index};
 58   e = this.title(e, scenes[index]);
 59   if (!e.parentNode) scenes.$g.appendChild(e);
 60   return e.nextSibling;
 61 };
 62 
 63 /**
 64  * Applies a title tooltip to the specified element <tt>e</tt>, using the
 65  * <tt>title</tt> property of the specified scene node <tt>s</tt>. Note that
 66  * this implementation does not create an SVG <tt>title</tt> element as a child
 67  * of <tt>e</tt>; although this is the recommended standard, it is only
 68  * supported in Opera. Instead, an anchor element is created around the element
 69  * <tt>e</tt>, and the <tt>xlink:title</tt> attribute is set accordingly.
 70  *
 71  * @param e an SVG element.
 72  * @param s a scene node.
 73  */
 74 pv.SvgScene.title = function(e, s) {
 75   var a = e.parentNode, t = String(s.title);
 76   if (a && (a.tagName != "a")) a = null;
 77   if (t) {
 78     if (!a) {
 79       a = this.create("a");
 80       if (e.parentNode) e.parentNode.replaceChild(a, e);
 81       a.appendChild(e);
 82     }
 83     a.setAttributeNS(pv.ns.xlink, "title", t);
 84     return a;
 85   }
 86   if (a) a.parentNode.replaceChild(e, a);
 87   return e;
 88 };
 89 
 90 /** TODO */
 91 pv.SvgScene.dispatch = function(e) {
 92   var t = e.target.$scene;
 93   if (t) {
 94     t.scenes.mark.dispatch(e.type, t.scenes, t.index);
 95     e.preventDefault();
 96   }
 97 };
 98 
 99 /** TODO */
100 pv.SvgScene.removeSiblings = function(e) {
101   while (e) {
102     var n = e.nextSibling;
103     e.parentNode.removeChild(e);
104     e = n;
105   }
106 };
107