1 pv.SvgScene.panel = function(scenes) {
  2   var parent = scenes.parent && this.group(scenes), marker = {};
  3   var previous;
  4 
  5   for (var i = 0; i < scenes.length; i++) {
  6     var s = scenes[i];
  7 
  8     /* visible */
  9     if (!s.visible) continue;
 10 
 11     /* svg */
 12     if (!scenes.parent) {
 13       s.canvas.style.display = "inline-block";
 14       if (s.canvas.firstChild) {
 15         var svg = s.canvas.firstChild;
 16         if (svg.marker != marker) {
 17           while (svg.lastChild) svg.removeChild(svg.lastChild);
 18           previous = null;
 19         }
 20       } else {
 21         var svg = s.canvas.appendChild(this.cache(s, "svg", "svg"));
 22         svg.setAttribute("width", s.width + s.left + s.right);
 23         svg.setAttribute("height", s.height + s.top + s.bottom);
 24         svg.onclick
 25             = svg.onmousedown
 26             = svg.onmouseup
 27             = svg.onmousemove
 28             = svg.onmouseout
 29             = svg.onmouseover
 30             = pv.SvgScene.dispatch;
 31         previous = null;
 32       }
 33       svg.marker = marker;
 34       parent = svg;
 35     }
 36 
 37     /* g */
 38     var g = parent;
 39     if (s.left || s.top) {
 40       if (previous
 41           && (previous.left == s.left)
 42           && (previous.top == s.top)) {
 43         g = previous.scene.g;
 44       } else {
 45         g = this.cache(s, "g", "panel");
 46         g.setAttribute("transform", "translate(" + s.left + "," + s.top + ")");
 47         previous = s;
 48       }
 49     }
 50     (s.scene || (s.scene = {})).g = g;
 51 
 52     /* fill */
 53     var fill = pv.color(s.fillStyle);
 54     if (fill.opacity || s.cursor || s.title) {
 55       var rect = this.cache(s, "rect", "fill");
 56       rect.setAttribute("width", s.width);
 57       rect.setAttribute("height", s.height);
 58       rect.setAttribute("cursor", s.cursor);
 59       rect.setAttribute("pointer-events", "all");
 60       rect.setAttribute("fill", fill.color);
 61       rect.setAttribute("fill-opacity", fill.opacity);
 62       this.listen(rect, scenes, i);
 63       g.appendChild(this.title(rect, s));
 64     }
 65 
 66     /* children */
 67     for (var j = 0; j < s.children.length; j++) {
 68       this.updateAll(s.children[j]);
 69     }
 70 
 71     /* stroke */
 72     var stroke = pv.color(s.strokeStyle);
 73     if (stroke.opacity) {
 74       var rect = this.cache(s, "rect", "stroke");
 75       rect.setAttribute("width", Math.max(1E-10, s.width));
 76       rect.setAttribute("height", Math.max(1E-10, s.height));
 77       rect.setAttribute("cursor", s.cursor);
 78       rect.setAttribute("fill", "none");
 79       rect.setAttribute("stroke", stroke.color);
 80       rect.setAttribute("stroke-opacity", stroke.opacity);
 81       rect.setAttribute("stroke-width", s.lineWidth);
 82       this.listen(rect, scenes, i);
 83       g.appendChild(this.title(rect, s));
 84     }
 85 
 86     /*
 87      * WebKit appears has a bug where images are not rendered if the g element
 88      * is appended before it contained any elements. Creating the child elements
 89      * first and then appending them solves the problem and is more efficient.
 90      */
 91     if (s.scene.panel) parent.appendChild(g);
 92   }
 93 };
 94