1 /** 2 * Returns a {@link pv.Tree} operator for the specified array. This is a 3 * convenience factory method, equivalent to <tt>new pv.Tree(array)</tt>. 4 * 5 * @see pv.Tree 6 * @param {array} array an array from which to construct a tree. 7 * @returns {pv.Tree} a tree operator for the specified array. 8 */ 9 pv.tree = function(array) { 10 return new pv.Tree(array); 11 }; 12 13 /** 14 * Constructs a tree operator for the specified array. This constructor should 15 * not be invoked directly; use {@link pv.tree} instead. 16 * 17 * @class Represents a tree operator for the specified array. The tree operator 18 * allows a hierarchical map to be constructed from an array; it is similar to 19 * the {@link pv.Nest} operator, except the hierarchy is derived dynamically 20 * from the array elements. 21 * 22 * <p>For example, given an array of size information for ActionScript classes: 23 * 24 * <pre>{ name: "flare.flex.FlareVis", size: 4116 }, 25 * { name: "flare.physics.DragForce", size: 1082 }, 26 * { name: "flare.physics.GravityForce", size: 1336 }, ...</pre> 27 * 28 * To facilitate visualization, it may be useful to nest the elements by their 29 * package hierarchy: 30 * 31 * <pre>var tree = pv.tree(classes) 32 * .keys(function(d) d.name.split(".")) 33 * .map();</pre> 34 * 35 * The resulting tree is: 36 * 37 * <pre>{ flare: { 38 * flex: { 39 * FlareVis: { 40 * name: "flare.flex.FlareVis", 41 * size: 4116 } }, 42 * physics: { 43 * DragForce: { 44 * name: "flare.physics.DragForce", 45 * size: 1082 }, 46 * GravityForce: { 47 * name: "flare.physics.GravityForce", 48 * size: 1336 } }, 49 * ... } }</pre> 50 * 51 * By specifying a value function, 52 * 53 * <pre>var tree = pv.tree(classes) 54 * .keys(function(d) d.name.split(".")) 55 * .value(function(d) d.size) 56 * .map();</pre> 57 * 58 * we can further eliminate redundant data: 59 * 60 * <pre>{ flare: { 61 * flex: { 62 * FlareVis: 4116 }, 63 * physics: { 64 * DragForce: 1082, 65 * GravityForce: 1336 }, 66 * ... } }</pre> 67 * 68 * For visualizations with large data sets, performance improvements may be seen 69 * by storing the data in a tree format, and then flattening it into an array at 70 * runtime with {@link pv.Flatten}. 71 * 72 * @param {array} array an array from which to construct a tree. 73 */ 74 pv.Tree = function(array) { 75 this.array = array; 76 }; 77 78 /** 79 * Assigns a <i>keys</i> function to this operator; required. The keys function 80 * returns an array of <tt>string</tt>s for each element in the associated 81 * array; these keys determine how the elements are nested in the tree. The 82 * returned keys should be unique for each element in the array; otherwise, the 83 * behavior of this operator is undefined. 84 * 85 * @param {function} k the keys function. 86 * @returns {pv.Tree} this. 87 */ 88 pv.Tree.prototype.keys = function(k) { 89 this.k = k; 90 return this; 91 }; 92 93 /** 94 * Assigns a <i>value</i> function to this operator; optional. The value 95 * function specifies an optional transformation of the element in the array 96 * before it is inserted into the map. If no value function is specified, it is 97 * equivalent to using the identity function. 98 * 99 * @param {function} k the value function. 100 * @returns {pv.Tree} this. 101 */ 102 pv.Tree.prototype.value = function(v) { 103 this.v = v; 104 return this; 105 }; 106 107 /** 108 * Returns a hierarchical map of values. The hierarchy is determined by the keys 109 * function; the values in the map are determined by the value function. 110 * 111 * @returns a hierarchical map of values. 112 */ 113 pv.Tree.prototype.map = function() { 114 var map = {}, o = {}; 115 for (var i = 0; i < this.array.length; i++) { 116 o.index = i; 117 var value = this.array[i], keys = this.k.call(o, value), node = map; 118 for (var j = 0; j < keys.length - 1; j++) { 119 node = node[keys[j]] || (node[keys[j]] = {}); 120 } 121 node[keys[j]] = this.v ? this.v.call(o, value) : value; 122 } 123 return map; 124 }; 125