1 | define(["dojo/_base/array"], function(arr){ |
---|
2 | var utils = { |
---|
3 | group: function(/*Array*/items, /*Array*/groupingFunctions, /*Function*/measureFunction){ |
---|
4 | var response = { |
---|
5 | children: [] |
---|
6 | }; |
---|
7 | var merge = function(obj, entry){ |
---|
8 | if(!obj.__treeValue){ |
---|
9 | obj.__treeValue = 0; |
---|
10 | } |
---|
11 | obj.__treeValue += measureFunction(entry); |
---|
12 | return obj; |
---|
13 | }; |
---|
14 | // we go over each entry in the array |
---|
15 | arr.forEach(items, function(entry){ |
---|
16 | var r = response; |
---|
17 | // for this entry, for each rowField we |
---|
18 | // look at the actual value for this rowField |
---|
19 | // and create a holding object for this |
---|
20 | // value in response if it does not exist |
---|
21 | arr.forEach(groupingFunctions, function(groupingFunction, j){ |
---|
22 | // actual value for the rowField |
---|
23 | var data = groupingFunction(entry); |
---|
24 | // create child if undefined |
---|
25 | var child = utils.find(r.children, function(item){ |
---|
26 | return (item.__treeName == data); |
---|
27 | }); |
---|
28 | if(!child){ |
---|
29 | r.children.push(child = { |
---|
30 | __treeName: data, |
---|
31 | __treeID: data+Math.random(), |
---|
32 | children: [] |
---|
33 | }); |
---|
34 | } |
---|
35 | child = merge(child, entry); |
---|
36 | if(j != groupingFunctions.length - 1){ |
---|
37 | // branch & prepare response for |
---|
38 | // next call |
---|
39 | r = child; |
---|
40 | }else{ |
---|
41 | // add the entry to the leaf! |
---|
42 | child.children.push(entry); |
---|
43 | } |
---|
44 | }); |
---|
45 | r = merge(r, entry); |
---|
46 | }); |
---|
47 | return response; |
---|
48 | }, |
---|
49 | find: function(/*Array*/array, /*Function*/callback){ |
---|
50 | var l = array.length; |
---|
51 | for (var i = 0; i < l; ++i) { |
---|
52 | if (callback.call(null, array[i])){ |
---|
53 | return array[i]; |
---|
54 | } |
---|
55 | } |
---|
56 | return null; |
---|
57 | }, |
---|
58 | solve: function(items, width, height, areaFunc, rtl){ |
---|
59 | // |
---|
60 | // Create temporary TreeMap elements |
---|
61 | // |
---|
62 | var treeMapElements = utils.initElements(items, areaFunc); |
---|
63 | var dataTotal = treeMapElements.total; |
---|
64 | var elements = treeMapElements.elements; |
---|
65 | |
---|
66 | var realSize = dataTotal; |
---|
67 | |
---|
68 | if(dataTotal == 0){ |
---|
69 | if(elements.length == 0){ |
---|
70 | return { |
---|
71 | items: items, rects: [], total: 0 |
---|
72 | }; |
---|
73 | } |
---|
74 | arr.forEach(elements, function(element){ |
---|
75 | element.size = element.sizeTmp = 100; |
---|
76 | }); |
---|
77 | dataTotal = elements.length * 100; |
---|
78 | } |
---|
79 | |
---|
80 | // |
---|
81 | // Sort the TreeMap elements |
---|
82 | // |
---|
83 | elements.sort(function(b, a){ |
---|
84 | return a.size - b.size; |
---|
85 | }); |
---|
86 | |
---|
87 | utils._compute(width, height, elements, dataTotal); |
---|
88 | |
---|
89 | // |
---|
90 | // Restore initial Sort order |
---|
91 | // |
---|
92 | elements.sort(function(a, b){ |
---|
93 | return a.index - b.index; |
---|
94 | }); |
---|
95 | |
---|
96 | var result = {}; |
---|
97 | result.elements = elements; |
---|
98 | result.size = realSize; |
---|
99 | |
---|
100 | rects = arr.map(elements, function(element){ |
---|
101 | return { |
---|
102 | x: rtl?width - element.x - element.width:element.x, y: element.y, w: element.width, h: element.height |
---|
103 | }; |
---|
104 | }); |
---|
105 | |
---|
106 | result.rectangles = rects; |
---|
107 | |
---|
108 | return result; |
---|
109 | }, |
---|
110 | initElements: function(items, areaFunc){ |
---|
111 | var total = 0; |
---|
112 | var elements = arr.map(items, function(item, index){ |
---|
113 | var size = areaFunc != null ? areaFunc(item) : 0; |
---|
114 | if(size < 0){ |
---|
115 | throw new Error("item size dimension must be positive"); |
---|
116 | } |
---|
117 | total += size; |
---|
118 | return { |
---|
119 | index: index, size: size, sizeTmp: size |
---|
120 | }; |
---|
121 | }); |
---|
122 | return { |
---|
123 | elements: elements, total: total |
---|
124 | }; |
---|
125 | }, |
---|
126 | _compute: function(width, height, elements, total){ |
---|
127 | var valueScale = ((width * height) / total) / 100; |
---|
128 | |
---|
129 | arr.forEach(elements, function(element){ |
---|
130 | element.sizeTmp *= valueScale; |
---|
131 | }); |
---|
132 | |
---|
133 | var start = 0; |
---|
134 | var end = 0; |
---|
135 | var aspectCurr = -1 >>> 1; // int.MaxValue; |
---|
136 | var aspectLast; |
---|
137 | var offsetX = 0; |
---|
138 | var offsetY = 0; |
---|
139 | var tmp_width = width; |
---|
140 | var tmp_height = height; |
---|
141 | |
---|
142 | var vert = tmp_width > tmp_height; |
---|
143 | |
---|
144 | while(end != elements.length){ |
---|
145 | aspectLast = utils._trySolution(elements, start, end, vert, tmp_width, tmp_height); |
---|
146 | |
---|
147 | if((aspectLast > aspectCurr) || (aspectLast < 1)){ |
---|
148 | var currX = 0; |
---|
149 | var currY = 0; |
---|
150 | |
---|
151 | for(var n = start; n < end; n++){ |
---|
152 | elements[n].x = offsetX + currX; |
---|
153 | elements[n].y = offsetY + currY; |
---|
154 | if(vert){ |
---|
155 | currY += elements[n].height; |
---|
156 | }else{ |
---|
157 | currX += elements[n].width; |
---|
158 | } |
---|
159 | } |
---|
160 | |
---|
161 | if(vert){ |
---|
162 | offsetX += elements[start].width; |
---|
163 | }else{ |
---|
164 | offsetY += elements[start].height; |
---|
165 | } |
---|
166 | |
---|
167 | tmp_width = width - offsetX; |
---|
168 | tmp_height = height - offsetY; |
---|
169 | |
---|
170 | vert = tmp_width > tmp_height; |
---|
171 | |
---|
172 | start = end; |
---|
173 | end = start; |
---|
174 | |
---|
175 | aspectCurr = -1 >>> 1; // int.MaxValue; |
---|
176 | continue; |
---|
177 | }else{ |
---|
178 | for(var n = start; n <= end; n++){ |
---|
179 | elements[n].width = elements[n].widthTmp; |
---|
180 | elements[n].height = elements[n].heightTmp; |
---|
181 | } |
---|
182 | aspectCurr = aspectLast; |
---|
183 | } |
---|
184 | end++; |
---|
185 | } |
---|
186 | |
---|
187 | var currX1 = 0; |
---|
188 | var currY1 = 0; |
---|
189 | |
---|
190 | for(var n = start; n < end; n++){ |
---|
191 | elements[n].x = offsetX + currX1; |
---|
192 | elements[n].y = offsetY + currY1; |
---|
193 | if(vert){ |
---|
194 | currY1 += elements[n].height; |
---|
195 | }else{ |
---|
196 | currX1 += elements[n].width; |
---|
197 | } |
---|
198 | } |
---|
199 | |
---|
200 | }, |
---|
201 | _trySolution: function(elements, start, end, vert, tmp_width, tmp_height){ |
---|
202 | var total = 0; |
---|
203 | var aspect = 0; |
---|
204 | var localWidth = 0; |
---|
205 | var localHeight = 0; |
---|
206 | |
---|
207 | for(var n = start; n <= end; n++){ |
---|
208 | total += elements[n].sizeTmp; |
---|
209 | } |
---|
210 | |
---|
211 | if(vert){ |
---|
212 | if(tmp_height == 0){ |
---|
213 | localWidth = localHeight = 0; |
---|
214 | }else{ |
---|
215 | localWidth = total / tmp_height * 100; |
---|
216 | localHeight = tmp_height; |
---|
217 | } |
---|
218 | }else{ |
---|
219 | if(tmp_width == 0){ |
---|
220 | localWidth = localHeight = 0; |
---|
221 | }else{ |
---|
222 | localHeight = total / tmp_width * 100; |
---|
223 | localWidth = tmp_width; |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | for(var n = start; n <= end; n++){ |
---|
228 | if(vert){ |
---|
229 | elements[n].widthTmp = localWidth; |
---|
230 | if(total == 0){ |
---|
231 | elements[n].heightTmp = 0; |
---|
232 | }else{ |
---|
233 | elements[n].heightTmp = localHeight * elements[n].sizeTmp / total; |
---|
234 | } |
---|
235 | }else{ |
---|
236 | if(total == 0){ |
---|
237 | elements[n].widthTmp = 0; |
---|
238 | }else{ |
---|
239 | elements[n].widthTmp = localWidth * elements[n].sizeTmp / total; |
---|
240 | } |
---|
241 | elements[n].heightTmp = localHeight; |
---|
242 | } |
---|
243 | } |
---|
244 | aspect = Math.max(elements[end].heightTmp / elements[end].widthTmp, elements[end].widthTmp |
---|
245 | / elements[end].heightTmp); |
---|
246 | if(aspect == undefined){ |
---|
247 | return 1; |
---|
248 | } |
---|
249 | return aspect; |
---|
250 | } |
---|
251 | }; |
---|
252 | return utils; |
---|
253 | }); |
---|