|
1 /* |
|
2 YUI 3.10.3 (build 2fb5187) |
|
3 Copyright 2013 Yahoo! Inc. All rights reserved. |
|
4 Licensed under the BSD License. |
|
5 http://yuilibrary.com/license/ |
|
6 */ |
|
7 |
|
8 YUI.add('series-stacked', function (Y, NAME) { |
|
9 |
|
10 /** |
|
11 * Provides functionality for creating stacked series. |
|
12 * |
|
13 * @module charts |
|
14 * @submodule series-stacked |
|
15 */ |
|
16 var Y_Lang = Y.Lang; |
|
17 |
|
18 /** |
|
19 * Utility class used for creating stacked series. |
|
20 * |
|
21 * @module charts |
|
22 * @class StackingUtil |
|
23 * @constructor |
|
24 * @submodule series-stacked |
|
25 */ |
|
26 function StackingUtil(){} |
|
27 |
|
28 StackingUtil.prototype = { |
|
29 /** |
|
30 * Indicates whether the series is stacked. |
|
31 * |
|
32 * @property _stacked |
|
33 * @private |
|
34 */ |
|
35 _stacked: true, |
|
36 |
|
37 /** |
|
38 * @protected |
|
39 * |
|
40 * Adjusts coordinate values for stacked series. |
|
41 * |
|
42 * @method _stackCoordinates |
|
43 */ |
|
44 _stackCoordinates: function() |
|
45 { |
|
46 if(this.get("direction") === "vertical") |
|
47 { |
|
48 this._stackXCoords(); |
|
49 } |
|
50 else |
|
51 { |
|
52 this._stackYCoords(); |
|
53 } |
|
54 }, |
|
55 |
|
56 /** |
|
57 * Stacks coordinates for a stacked vertical series. |
|
58 * |
|
59 * @method _stackXCoords |
|
60 * @protected |
|
61 */ |
|
62 _stackXCoords: function() |
|
63 { |
|
64 var order = this.get("order"), |
|
65 seriesCollection = this.get("seriesTypeCollection"), |
|
66 i = 0, |
|
67 xcoords = this.get("xcoords"), |
|
68 ycoords = this.get("ycoords"), |
|
69 len, |
|
70 coord, |
|
71 prevCoord, |
|
72 prevOrder, |
|
73 stackedXCoords = xcoords.concat(), |
|
74 prevXCoords, |
|
75 prevYCoords, |
|
76 nullIndices = [], |
|
77 nullIndex; |
|
78 if(order > 0) |
|
79 { |
|
80 prevXCoords = seriesCollection[order - 1].get("stackedXCoords"); |
|
81 prevYCoords = seriesCollection[order - 1].get("stackedYCoords"); |
|
82 len = prevXCoords.length; |
|
83 } |
|
84 else |
|
85 { |
|
86 len = xcoords.length; |
|
87 } |
|
88 for(; i < len; i = i + 1) |
|
89 { |
|
90 if(Y_Lang.isNumber(xcoords[i])) |
|
91 { |
|
92 if(order > 0) |
|
93 { |
|
94 prevCoord = prevXCoords[i]; |
|
95 if(!Y_Lang.isNumber(prevCoord)) |
|
96 { |
|
97 prevOrder = order; |
|
98 while(prevOrder > - 1 && !Y_Lang.isNumber(prevCoord)) |
|
99 { |
|
100 prevOrder = prevOrder - 1; |
|
101 if(prevOrder > -1) |
|
102 { |
|
103 prevCoord = seriesCollection[prevOrder].get("stackedXCoords")[i]; |
|
104 } |
|
105 else |
|
106 { |
|
107 prevCoord = this._leftOrigin; |
|
108 } |
|
109 } |
|
110 } |
|
111 xcoords[i] = xcoords[i] + prevCoord; |
|
112 } |
|
113 stackedXCoords[i] = xcoords[i]; |
|
114 } |
|
115 else |
|
116 { |
|
117 nullIndices.push(i); |
|
118 } |
|
119 } |
|
120 this._cleanXNaN(stackedXCoords, ycoords); |
|
121 len = nullIndices.length; |
|
122 if(len > 0) |
|
123 { |
|
124 for(i = 0; i < len; i = i + 1) |
|
125 { |
|
126 nullIndex = nullIndices[i]; |
|
127 coord = order > 0 ? prevXCoords[nullIndex] : this._leftOrigin; |
|
128 stackedXCoords[nullIndex] = Math.max(stackedXCoords[nullIndex], coord); |
|
129 } |
|
130 } |
|
131 this.set("stackedXCoords", stackedXCoords); |
|
132 this.set("stackedYCoords", ycoords); |
|
133 }, |
|
134 |
|
135 /** |
|
136 * Stacks coordinates for a stacked horizontal series. |
|
137 * |
|
138 * @method _stackYCoords |
|
139 * @protected |
|
140 */ |
|
141 _stackYCoords: function() |
|
142 { |
|
143 var order = this.get("order"), |
|
144 graphic = this.get("graphic"), |
|
145 h = graphic.get("height"), |
|
146 seriesCollection = this.get("seriesTypeCollection"), |
|
147 i = 0, |
|
148 xcoords = this.get("xcoords"), |
|
149 ycoords = this.get("ycoords"), |
|
150 len, |
|
151 coord, |
|
152 prevCoord, |
|
153 prevOrder, |
|
154 stackedYCoords = ycoords.concat(), |
|
155 prevXCoords, |
|
156 prevYCoords, |
|
157 nullIndices = [], |
|
158 nullIndex; |
|
159 if(order > 0) |
|
160 { |
|
161 prevXCoords = seriesCollection[order - 1].get("stackedXCoords"); |
|
162 prevYCoords = seriesCollection[order - 1].get("stackedYCoords"); |
|
163 len = prevYCoords.length; |
|
164 } |
|
165 else |
|
166 { |
|
167 len = ycoords.length; |
|
168 } |
|
169 for(; i < len; i = i + 1) |
|
170 { |
|
171 if(Y_Lang.isNumber(ycoords[i])) |
|
172 { |
|
173 if(order > 0) |
|
174 { |
|
175 prevCoord = prevYCoords[i]; |
|
176 if(!Y_Lang.isNumber(prevCoord)) |
|
177 { |
|
178 prevOrder = order; |
|
179 while(prevOrder > - 1 && !Y_Lang.isNumber(prevCoord)) |
|
180 { |
|
181 prevOrder = prevOrder - 1; |
|
182 if(prevOrder > -1) |
|
183 { |
|
184 prevCoord = seriesCollection[prevOrder].get("stackedYCoords")[i]; |
|
185 } |
|
186 else |
|
187 { |
|
188 prevCoord = this._bottomOrigin; |
|
189 } |
|
190 } |
|
191 } |
|
192 ycoords[i] = prevCoord - (h - ycoords[i]); |
|
193 } |
|
194 stackedYCoords[i] = ycoords[i]; |
|
195 } |
|
196 else |
|
197 { |
|
198 nullIndices.push(i); |
|
199 } |
|
200 } |
|
201 this._cleanYNaN(xcoords, stackedYCoords); |
|
202 len = nullIndices.length; |
|
203 if(len > 0) |
|
204 { |
|
205 for(i = 0; i < len; i = i + 1) |
|
206 { |
|
207 nullIndex = nullIndices[i]; |
|
208 coord = order > 0 ? prevYCoords[nullIndex] : h; |
|
209 stackedYCoords[nullIndex] = Math.min(stackedYCoords[nullIndex], coord); |
|
210 } |
|
211 } |
|
212 this.set("stackedXCoords", xcoords); |
|
213 this.set("stackedYCoords", stackedYCoords); |
|
214 }, |
|
215 |
|
216 /** |
|
217 * Cleans invalid x-coordinates by calculating their value based on the corresponding y-coordinate, the |
|
218 * previous valid x-coordinate with its corresponding y-coordinate and the next valid x-coordinate with |
|
219 * its corresponding y-coordinate. If there is no previous or next valid x-coordinate, the value will not |
|
220 * be altered. |
|
221 * |
|
222 * @method _cleanXNaN |
|
223 * @param {Array} xcoords An array of x-coordinate values |
|
224 * @param {Array} ycoords An arry of y-coordinate values |
|
225 * @private |
|
226 */ |
|
227 _cleanXNaN: function(xcoords, ycoords) |
|
228 { |
|
229 var previousValidIndex, |
|
230 nextValidIndex, |
|
231 previousValidX, |
|
232 previousValidY, |
|
233 x, |
|
234 y, |
|
235 nextValidX, |
|
236 nextValidY, |
|
237 isNumber = Y_Lang.isNumber, |
|
238 m, |
|
239 i = 0, |
|
240 len = ycoords.length; |
|
241 for(; i < len; ++i) |
|
242 { |
|
243 x = xcoords[i]; |
|
244 y = ycoords[i]; |
|
245 //if x is invalid, calculate where it should be |
|
246 if(!isNumber(x) && i > 0 && i < len - 1) |
|
247 { |
|
248 previousValidY = ycoords[i - 1]; |
|
249 //check to see if the previous value is valid |
|
250 previousValidX = this._getPreviousValidCoordValue(xcoords, i); |
|
251 nextValidY = ycoords[i + 1]; |
|
252 nextValidX = this._getNextValidCoordValue(xcoords, i); |
|
253 //check to see if the next value is valid |
|
254 if(isNumber(previousValidX) && isNumber(nextValidX)) |
|
255 { |
|
256 //calculate slope and solve for x |
|
257 m = (nextValidY - previousValidY) / (nextValidX - previousValidX); |
|
258 xcoords[i] = (y + (m * previousValidX) - previousValidY)/m; |
|
259 } |
|
260 previousValidIndex = NaN; |
|
261 nextValidIndex = NaN; |
|
262 } |
|
263 } |
|
264 }, |
|
265 |
|
266 /** |
|
267 * Returns the previous valid (numeric) value in an array if available. |
|
268 * |
|
269 * @method _getPreviousValidCoordValue |
|
270 * @param {Array} coords Array of values |
|
271 * @param {Number} index The index in the array in which to begin searching. |
|
272 * @return Number |
|
273 * @private |
|
274 */ |
|
275 _getPreviousValidCoordValue: function(coords, index) |
|
276 { |
|
277 var coord, |
|
278 isNumber = Y_Lang.isNumber, |
|
279 limit = -1; |
|
280 while(!isNumber(coord) && index > limit) |
|
281 { |
|
282 index = index - 1; |
|
283 coord = coords[index]; |
|
284 } |
|
285 return coord; |
|
286 }, |
|
287 |
|
288 /** |
|
289 * Returns the next valid (numeric) value in an array if available. |
|
290 * |
|
291 * @method _getNextValidCoordValue |
|
292 * @param {Array} coords Array of values |
|
293 * @param {Number} index The index in the array in which to begin searching. |
|
294 * @return Number |
|
295 * @private |
|
296 */ |
|
297 _getNextValidCoordValue: function(coords, index) |
|
298 { |
|
299 var coord, |
|
300 isNumber = Y_Lang.isNumber, |
|
301 limit = coords.length; |
|
302 while(!isNumber(coord) && index < limit) |
|
303 { |
|
304 index = index + 1; |
|
305 coord = coords[index]; |
|
306 } |
|
307 return coord; |
|
308 }, |
|
309 |
|
310 /** |
|
311 * Cleans invalid y-coordinates by calculating their value based on the corresponding x-coordinate, the |
|
312 * previous valid y-coordinate with its corresponding x-coordinate and the next valid y-coordinate with |
|
313 * its corresponding x-coordinate. If there is no previous or next valid y-coordinate, the value will not |
|
314 * be altered. |
|
315 * |
|
316 * @method _cleanYNaN |
|
317 * @param {Array} xcoords An array of x-coordinate values |
|
318 * @param {Array} ycoords An arry of y-coordinate values |
|
319 * @private |
|
320 */ |
|
321 _cleanYNaN: function(xcoords, ycoords) |
|
322 { |
|
323 var previousValidIndex, |
|
324 nextValidIndex, |
|
325 previousValidX, |
|
326 previousValidY, |
|
327 x, |
|
328 y, |
|
329 nextValidX, |
|
330 nextValidY, |
|
331 isNumber = Y_Lang.isNumber, |
|
332 m, |
|
333 i = 0, |
|
334 len = xcoords.length; |
|
335 for(; i < len; ++i) |
|
336 { |
|
337 x = xcoords[i]; |
|
338 y = ycoords[i]; |
|
339 //if y is invalid, calculate where it should be |
|
340 if(!isNumber(y) && i > 0 && i < len - 1) |
|
341 { |
|
342 //check to see if the previous value is valid |
|
343 previousValidX = xcoords[i - 1]; |
|
344 previousValidY = this._getPreviousValidCoordValue(ycoords, i); |
|
345 //check to see if the next value is valid |
|
346 nextValidX = xcoords[i + 1]; |
|
347 nextValidY = this._getNextValidCoordValue(ycoords, i); |
|
348 if(isNumber(previousValidY) && isNumber(nextValidY)) |
|
349 { |
|
350 //calculate slope and solve for y |
|
351 m = (nextValidY - previousValidY) / (nextValidX - previousValidX); |
|
352 ycoords[i] = previousValidY + ((m * x) - (m * previousValidX)); |
|
353 } |
|
354 previousValidIndex = NaN; |
|
355 nextValidIndex = NaN; |
|
356 } |
|
357 } |
|
358 } |
|
359 }; |
|
360 Y.StackingUtil = StackingUtil; |
|
361 |
|
362 |
|
363 }, '3.10.3', {"requires": ["axis-stacked"]}); |