1 /**
  2  * Returns a new stack layout.
  3  *
  4  * @class A layout for stacking marks vertically or horizontally, using the
  5  * <i>cousin</i> instance. This layout is designed to be used for one of the
  6  * four positional properties in the box model, and changes behavior depending
  7  * on the property being evaluated:<ul>
  8  *
  9  * <li>bottom: cousin.bottom + cousin.height
 10  * <li>top: cousin.top + cousin.height
 11  * <li>left: cousin.left + cousin.width
 12  * <li>right: cousin.right + cousin.width
 13  *
 14  * </ul>If no cousin instance is available (for example, for first instance),
 15  * the specified offset is used. If no offset is specified, zero is used. For
 16  * example,
 17  *
 18  * <pre>new pv.Panel()
 19  *     .width(150).height(150)
 20  *   .add(pv.Panel)
 21  *     .data([[1, 1.2, 1.7, 1.5, 1.7],
 22  *            [.5, 1, .8, 1.1, 1.3],
 23  *            [.2, .5, .8, .9, 1]])
 24  *   .add(pv.Area)
 25  *     .data(function(d) d)
 26  *     .bottom(pv.Layout.stack())
 27  *     .height(function(d) d * 40)
 28  *     .left(function() this.index * 35)
 29  *   .root.render();</pre>
 30  *
 31  * specifies a vertically-stacked area chart.
 32  *
 33  * @returns {pv.Layout.stack} a stack property function.
 34  * @see pv.Mark#cousin
 35  */
 36 pv.Layout.stack = function() {
 37   /** @private */
 38   var offset = function() { return 0; };
 39 
 40   /** @private */
 41   function layout() {
 42 
 43     /* Find the previous visible parent instance. */
 44     var i = this.parent.index, p, c;
 45     while ((i-- > 0) && !c) {
 46       p = this.parent.scene[i];
 47       if (p.visible) c = p.children[this.childIndex][this.index];
 48     }
 49 
 50     if (c) {
 51       switch (property) {
 52         case "bottom": return c.bottom + c.height;
 53         case "top": return c.top + c.height;
 54         case "left": return c.left + c.width;
 55         case "right": return c.right + c.width;
 56       }
 57     }
 58 
 59     return offset.apply(this, arguments);
 60   }
 61 
 62   /**
 63    * Sets the offset for this stack layout. The offset can either be specified
 64    * as a function or as a constant. If a function, the function is invoked in
 65    * the same context as a normal property function: <tt>this</tt> refers to the
 66    * mark, and the arguments are the full data stack. By default the offset is
 67    * zero.
 68    *
 69    * @function
 70    * @name pv.Layout.stack.prototype.offset
 71    * @param {function} f offset function, or constant value.
 72    * @returns {pv.Layout.stack} this.
 73    */
 74   layout.offset = function(f) {
 75       offset = (f instanceof Function) ? f : function() { return f; };
 76       return this;
 77     };
 78 
 79   return layout;
 80 };
 81