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