1 /**
  2  * Constructs a new, empty grid layout. Layouts are not typically constructed
  3  * directly; instead, they are added to an existing panel via
  4  * {@link pv.Mark#add}.
  5  *
  6  * @class Implements a grid layout with regularly-sized rows and columns. The
  7  * number of rows and columns are determined from their respective
  8  * properties. For example, the 2×3 array:
  9  *
 10  * <pre>1 2 3
 11  * 4 5 6</pre>
 12  *
 13  * can be represented using the <tt>rows</tt> property as:
 14  *
 15  * <pre>[[1, 2, 3], [4, 5, 6]]</pre>
 16  *
 17  * If your data is in column-major order, you can equivalently use the
 18  * <tt>columns</tt> property. If the <tt>rows</tt> property is an array, it
 19  * takes priority over the <tt>columns</tt> property. The data is implicitly
 20  * transposed, as if the {@link pv.transpose} operator were applied.
 21  *
 22  * <p>This layout exports a single <tt>cell</tt> mark prototype, which is
 23  * intended to be used with a bar, panel, layout, or subclass thereof. The data
 24  * property of the cell prototype is defined as the elements in the array. For
 25  * example, if the array is a two-dimensional array of values in the range
 26  * [0,1], a simple heatmap can be generated as:
 27  *
 28  * <pre>vis.add(pv.Layout.Grid)
 29  *     .rows(arrays)
 30  *   .cell.add(pv.Bar)
 31  *     .fillStyle(pv.ramp("white", "black"))</pre>
 32  *
 33  * The grid subdivides the full width and height of the parent panel into equal
 34  * rectangles. Note, however, that for large, interactive, or animated heatmaps,
 35  * you may see significantly better performance through dynamic {@link pv.Image}
 36  * generation.
 37  *
 38  * <p>For irregular grids using value-based spatial partitioning, see {@link
 39  * pv.Layout.Treemap}.
 40  *
 41  * @extends pv.Layout
 42  */
 43 pv.Layout.Grid = function() {
 44   pv.Layout.call(this);
 45   var that = this;
 46 
 47   /**
 48    * The cell prototype. This prototype is intended to be used with a bar,
 49    * panel, or layout (or subclass thereof) to render the grid cells.
 50    *
 51    * @type pv.Mark
 52    * @name pv.Layout.Grid.prototype.cell
 53    */
 54   (this.cell = new pv.Mark()
 55       .data(function() {
 56           return that.scene[that.index].$grid;
 57         })
 58       .width(function() {
 59           return that.width() / that.cols();
 60         })
 61       .height(function() {
 62           return that.height() / that.rows();
 63         })
 64       .left(function() {
 65           return this.width() * (this.index % that.cols());
 66         })
 67       .top(function() {
 68           return this.height() * Math.floor(this.index / that.cols());
 69         })).parent = this;
 70 };
 71 
 72 pv.Layout.Grid.prototype = pv.extend(pv.Layout)
 73     .property("rows")
 74     .property("cols");
 75 
 76 /**
 77  * Default properties for grid layouts. By default, there is one row and one
 78  * column, and the data is the propagated to the child cell.
 79  *
 80  * @type pv.Layout.Grid
 81  */
 82 pv.Layout.Grid.prototype.defaults = new pv.Layout.Grid()
 83     .extend(pv.Layout.prototype.defaults)
 84     .rows(1)
 85     .cols(1);
 86 
 87 /** @private */
 88 pv.Layout.Grid.prototype.buildImplied = function(s) {
 89   pv.Layout.prototype.buildImplied.call(this, s);
 90   var r = s.rows, c = s.cols;
 91   if (typeof c == "object") r = pv.transpose(c);
 92   if (typeof r == "object") {
 93     s.$grid = pv.blend(r);
 94     s.rows = r.length;
 95     s.cols = r[0] ? r[0].length : 0;
 96   } else {
 97     s.$grid = pv.repeat([s.data], r * c);
 98   }
 99 };
100 
101 /**
102  * The number of rows. This property can also be specified as the data in
103  * row-major order; in this case, the rows property is implicitly set to the
104  * length of the array, and the cols property is set to the length of the first
105  * element in the array.
106  *
107  * @type number
108  * @name pv.Layout.Grid.prototype.rows
109  */
110 
111 /**
112  * The number of columns. This property can also be specified as the data in
113  * column-major order; in this case, the cols property is implicitly set to the
114  * length of the array, and the rows property is set to the length of the first
115  * element in the array.
116  *
117  * @type number
118  * @name pv.Layout.Grid.prototype.cols
119  */
120