Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / swfupload.speed.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js">/*\r
9         Speed Plug-in\r
10         \r
11         Features:\r
12                 *Adds several properties to the 'file' object indicated upload speed, time left, upload time, etc.\r
13                         - currentSpeed -- String indicating the upload speed, bytes per second\r
14                         - averageSpeed -- Overall average upload speed, bytes per second\r
15                         - movingAverageSpeed -- Speed over averaged over the last several measurements, bytes per second\r
16                         - timeRemaining -- Estimated remaining upload time in seconds\r
17                         - timeElapsed -- Number of seconds passed for this upload\r
18                         - percentUploaded -- Percentage of the file uploaded (0 to 100)\r
19                         - sizeUploaded -- Formatted size uploaded so far, bytes\r
20                 \r
21                 *Adds setting 'moving_average_history_size' for defining the window size used to calculate the moving average speed.\r
22                 \r
23                 *Adds several Formatting functions for formatting that values provided on the file object.\r
24                         - SWFUpload.speed.formatBPS(bps) -- outputs string formatted in the best units (Gbps, Mbps, Kbps, bps)\r
25                         - SWFUpload.speed.formatTime(seconds) -- outputs string formatted in the best units (x Hr y M z S)\r
26                         - SWFUpload.speed.formatSize(bytes) -- outputs string formatted in the best units (w GB x MB y KB z B )\r
27                         - SWFUpload.speed.formatPercent(percent) -- outputs string formatted with a percent sign (x.xx %)\r
28                         - SWFUpload.speed.formatUnits(baseNumber, divisionArray, unitLabelArray, fractionalBoolean)\r
29                                 - Formats a number using the division array to determine how to apply the labels in the Label Array\r
30                                 - factionalBoolean indicates whether the number should be returned as a single fractional number with a unit (speed)\r
31                                     or as several numbers labeled with units (time)\r
32         */\r
33 \r
34 var SWFUpload;\r
35 if (typeof(SWFUpload) === "function") {\r
36         SWFUpload.speed = {};\r
37         \r
38         SWFUpload.prototype.initSettings = (function (oldInitSettings) {\r
39                 return function () {\r
40                         if (typeof(oldInitSettings) === "function") {\r
41                                 oldInitSettings.call(this);\r
42                         }\r
43                         \r
44                         this.ensureDefault = function (settingName, defaultValue) {\r
45                                 this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];\r
46                         };\r
47 \r
48                         // List used to keep the speed stats for the files we are tracking\r
49                         this.fileSpeedStats = {};\r
50                         this.speedSettings = {};\r
51 \r
52                         this.ensureDefault("moving_average_history_size", "10");\r
53                         \r
54                         this.speedSettings.user_file_queued_handler = this.settings.file_queued_handler;\r
55                         this.speedSettings.user_file_queue_error_handler = this.settings.file_queue_error_handler;\r
56                         this.speedSettings.user_upload_start_handler = this.settings.upload_start_handler;\r
57                         this.speedSettings.user_upload_error_handler = this.settings.upload_error_handler;\r
58                         this.speedSettings.user_upload_progress_handler = this.settings.upload_progress_handler;\r
59                         this.speedSettings.user_upload_success_handler = this.settings.upload_success_handler;\r
60                         this.speedSettings.user_upload_complete_handler = this.settings.upload_complete_handler;\r
61                         \r
62                         this.settings.file_queued_handler = SWFUpload.speed.fileQueuedHandler;\r
63                         this.settings.file_queue_error_handler = SWFUpload.speed.fileQueueErrorHandler;\r
64                         this.settings.upload_start_handler = SWFUpload.speed.uploadStartHandler;\r
65                         this.settings.upload_error_handler = SWFUpload.speed.uploadErrorHandler;\r
66                         this.settings.upload_progress_handler = SWFUpload.speed.uploadProgressHandler;\r
67                         this.settings.upload_success_handler = SWFUpload.speed.uploadSuccessHandler;\r
68                         this.settings.upload_complete_handler = SWFUpload.speed.uploadCompleteHandler;\r
69                         \r
70                         delete this.ensureDefault;\r
71                 };\r
72         })(SWFUpload.prototype.initSettings);\r
73 \r
74         \r
75         SWFUpload.speed.fileQueuedHandler = function (file) {\r
76                 if (typeof this.speedSettings.user_file_queued_handler === "function") {\r
77                         file = SWFUpload.speed.extendFile(file);\r
78                         \r
79                         return this.speedSettings.user_file_queued_handler.call(this, file);\r
80                 }\r
81         };\r
82         \r
83         SWFUpload.speed.fileQueueErrorHandler = function (file, errorCode, message) {\r
84                 if (typeof this.speedSettings.user_file_queue_error_handler === "function") {\r
85                         file = SWFUpload.speed.extendFile(file);\r
86                         \r
87                         return this.speedSettings.user_file_queue_error_handler.call(this, file, errorCode, message);\r
88                 }\r
89         };\r
90 \r
91         SWFUpload.speed.uploadStartHandler = function (file) {\r
92                 if (typeof this.speedSettings.user_upload_start_handler === "function") {\r
93                         file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);\r
94                         return this.speedSettings.user_upload_start_handler.call(this, file);\r
95                 }\r
96         };\r
97         \r
98         SWFUpload.speed.uploadErrorHandler = function (file, errorCode, message) {\r
99                 file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);\r
100                 SWFUpload.speed.removeTracking(file, this.fileSpeedStats);\r
101 \r
102                 if (typeof this.speedSettings.user_upload_error_handler === "function") {\r
103                         return this.speedSettings.user_upload_error_handler.call(this, file, errorCode, message);\r
104                 }\r
105         };\r
106         SWFUpload.speed.uploadProgressHandler = function (file, bytesComplete, bytesTotal) {\r
107                 this.updateTracking(file, bytesComplete);\r
108                 file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);\r
109 \r
110                 if (typeof this.speedSettings.user_upload_progress_handler === "function") {\r
111                         return this.speedSettings.user_upload_progress_handler.call(this, file, bytesComplete, bytesTotal);\r
112                 }\r
113         };\r
114         \r
115         SWFUpload.speed.uploadSuccessHandler = function (file, serverData) {\r
116                 if (typeof this.speedSettings.user_upload_success_handler === "function") {\r
117                         file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);\r
118                         return this.speedSettings.user_upload_success_handler.call(this, file, serverData);\r
119                 }\r
120         };\r
121         SWFUpload.speed.uploadCompleteHandler = function (file) {\r
122                 file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);\r
123                 SWFUpload.speed.removeTracking(file, this.fileSpeedStats);\r
124 \r
125                 if (typeof this.speedSettings.user_upload_complete_handler === "function") {\r
126                         return this.speedSettings.user_upload_complete_handler.call(this, file);\r
127                 }\r
128         };\r
129         \r
130         // Private: extends the file object with the speed plugin values\r
131         SWFUpload.speed.extendFile = function (file, trackingList) {\r
132                 var tracking;\r
133                 \r
134                 if (trackingList) {\r
135                         tracking = trackingList[file.id];\r
136                 }\r
137                 \r
138                 if (tracking) {\r
139                         file.currentSpeed = tracking.currentSpeed;\r
140                         file.averageSpeed = tracking.averageSpeed;\r
141                         file.movingAverageSpeed = tracking.movingAverageSpeed;\r
142                         file.timeRemaining = tracking.timeRemaining;\r
143                         file.timeElapsed = tracking.timeElapsed;\r
144                         file.percentUploaded = tracking.percentUploaded;\r
145                         file.sizeUploaded = tracking.bytesUploaded;\r
146 \r
147                 } else {\r
148                         file.currentSpeed = 0;\r
149                         file.averageSpeed = 0;\r
150                         file.movingAverageSpeed = 0;\r
151                         file.timeRemaining = 0;\r
152                         file.timeElapsed = 0;\r
153                         file.percentUploaded = 0;\r
154                         file.sizeUploaded = 0;\r
155                 }\r
156                 \r
157                 return file;\r
158         };\r
159         \r
160         // Private: Updates the speed tracking object, or creates it if necessary\r
161         SWFUpload.prototype.updateTracking = function (file, bytesUploaded) {\r
162                 var tracking = this.fileSpeedStats[file.id];\r
163                 if (!tracking) {\r
164                         this.fileSpeedStats[file.id] = tracking = {};\r
165                 }\r
166                 \r
167                 // Sanity check inputs\r
168                 bytesUploaded = bytesUploaded || tracking.bytesUploaded || 0;\r
169                 if (bytesUploaded < 0) {\r
170                         bytesUploaded = 0;\r
171                 }\r
172                 if (bytesUploaded > file.size) {\r
173                         bytesUploaded = file.size;\r
174                 }\r
175                 \r
176                 var tickTime = (new Date()).getTime();\r
177                 if (!tracking.startTime) {\r
178                         tracking.startTime = (new Date()).getTime();\r
179                         tracking.lastTime = tracking.startTime;\r
180                         tracking.currentSpeed = 0;\r
181                         tracking.averageSpeed = 0;\r
182                         tracking.movingAverageSpeed = 0;\r
183                         tracking.movingAverageHistory = [];\r
184                         tracking.timeRemaining = 0;\r
185                         tracking.timeElapsed = 0;\r
186                         tracking.percentUploaded = bytesUploaded / file.size;\r
187                         tracking.bytesUploaded = bytesUploaded;\r
188                 } else if (tracking.startTime > tickTime) {\r
189                         this.debug("When backwards in time");\r
190                 } else {\r
191                         // Get time and deltas\r
192                         var now = (new Date()).getTime();\r
193                         var lastTime = tracking.lastTime;\r
194                         var deltaTime = now - lastTime;\r
195                         var deltaBytes = bytesUploaded - tracking.bytesUploaded;\r
196                         \r
197                         if (deltaBytes === 0 || deltaTime === 0) {\r
198                                 return tracking;\r
199                         }\r
200                         \r
201                         // Update tracking object\r
202                         tracking.lastTime = now;\r
203                         tracking.bytesUploaded = bytesUploaded;\r
204                         \r
205                         // Calculate speeds\r
206                         tracking.currentSpeed = (deltaBytes * 8 ) / (deltaTime / 1000);\r
207                         tracking.averageSpeed = (tracking.bytesUploaded * 8) / ((now - tracking.startTime) / 1000);\r
208 \r
209                         // Calculate moving average\r
210                         tracking.movingAverageHistory.push(tracking.currentSpeed);\r
211                         if (tracking.movingAverageHistory.length > this.settings.moving_average_history_size) {\r
212                                 tracking.movingAverageHistory.shift();\r
213                         }\r
214                         \r
215                         tracking.movingAverageSpeed = SWFUpload.speed.calculateMovingAverage(tracking.movingAverageHistory);\r
216                         \r
217                         // Update times\r
218                         tracking.timeRemaining = (file.size - tracking.bytesUploaded) * 8 / tracking.movingAverageSpeed;\r
219                         tracking.timeElapsed = (now - tracking.startTime) / 1000;\r
220                         \r
221                         // Update percent\r
222                         tracking.percentUploaded = (tracking.bytesUploaded / file.size * 100);\r
223                 }\r
224                 \r
225                 return tracking;\r
226         };\r
227         SWFUpload.speed.removeTracking = function (file, trackingList) {\r
228                 try {\r
229                         trackingList[file.id] = null;\r
230                         delete trackingList[file.id];\r
231                 } catch (ex) {\r
232                 }\r
233         };\r
234         \r
235         SWFUpload.speed.formatUnits = function (baseNumber, unitDivisors, unitLabels, singleFractional) {\r
236                 var i, unit, unitDivisor, unitLabel;\r
237 \r
238                 if (baseNumber === 0) {\r
239                         return "0 " + unitLabels[unitLabels.length - 1];\r
240                 }\r
241                 \r
242                 if (singleFractional) {\r
243                         unit = baseNumber;\r
244                         unitLabel = unitLabels.length >= unitDivisors.length ? unitLabels[unitDivisors.length - 1] : "";\r
245                         for (i = 0; i < unitDivisors.length; i++) {\r
246                                 if (baseNumber >= unitDivisors[i]) {\r
247                                         unit = (baseNumber / unitDivisors[i]).toFixed(2);\r
248                                         unitLabel = unitLabels.length >= i ? " " + unitLabels[i] : "";\r
249                                         break;\r
250                                 }\r
251                         }\r
252                         \r
253                         return unit + unitLabel;\r
254                 } else {\r
255                         var formattedStrings = [];\r
256                         var remainder = baseNumber;\r
257                         \r
258                         for (i = 0; i < unitDivisors.length; i++) {\r
259                                 unitDivisor = unitDivisors[i];\r
260                                 unitLabel = unitLabels.length > i ? " " + unitLabels[i] : "";\r
261                                 \r
262                                 unit = remainder / unitDivisor;\r
263                                 if (i < unitDivisors.length -1) {\r
264                                         unit = Math.floor(unit);\r
265                                 } else {\r
266                                         unit = unit.toFixed(2);\r
267                                 }\r
268                                 if (unit > 0) {\r
269                                         remainder = remainder % unitDivisor;\r
270                                         \r
271                                         formattedStrings.push(unit + unitLabel);\r
272                                 }\r
273                         }\r
274                         \r
275                         return formattedStrings.join(" ");\r
276                 }\r
277         };\r
278         \r
279         SWFUpload.speed.formatBPS = function (baseNumber) {\r
280                 var bpsUnits = [1073741824, 1048576, 1024, 1], bpsUnitLabels = ["Gbps", "Mbps", "Kbps", "bps"];\r
281                 return SWFUpload.speed.formatUnits(baseNumber, bpsUnits, bpsUnitLabels, true);\r
282         \r
283         };\r
284         SWFUpload.speed.formatTime = function (baseNumber) {\r
285                 var timeUnits = [86400, 3600, 60, 1], timeUnitLabels = ["d", "h", "m", "s"];\r
286                 return SWFUpload.speed.formatUnits(baseNumber, timeUnits, timeUnitLabels, false);\r
287         \r
288         };\r
289         SWFUpload.speed.formatBytes = function (baseNumber) {\r
290                 var sizeUnits = [1073741824, 1048576, 1024, 1], sizeUnitLabels = ["GB", "MB", "KB", "bytes"];\r
291                 return SWFUpload.speed.formatUnits(baseNumber, sizeUnits, sizeUnitLabels, true);\r
292         \r
293         };\r
294         SWFUpload.speed.formatPercent = function (baseNumber) {\r
295                 return baseNumber.toFixed(2) + " %";\r
296         };\r
297         \r
298         SWFUpload.speed.calculateMovingAverage = function (history) {\r
299                 var vals = [], size, sum = 0.0, mean = 0.0, varianceTemp = 0.0, variance = 0.0, standardDev = 0.0;\r
300                 var i;\r
301                 var mSum = 0, mCount = 0;\r
302                 \r
303                 size = history.length;\r
304                 \r
305                 // Check for sufficient data\r
306                 if (size >= 8) {\r
307                         // Clone the array and Calculate sum of the values \r
308                         for (i = 0; i < size; i++) {\r
309                                 vals[i] = history[i];\r
310                                 sum += vals[i];\r
311                         }\r
312 \r
313                         mean = sum / size;\r
314 \r
315                         // Calculate variance for the set\r
316                         for (i = 0; i < size; i++) {\r
317                                 varianceTemp += Math.pow((vals[i] - mean), 2);\r
318                         }\r
319 \r
320                         variance = varianceTemp / size;\r
321                         standardDev = Math.sqrt(variance);\r
322                         \r
323                         //Standardize the Data\r
324                         for (i = 0; i < size; i++) {\r
325                                 vals[i] = (vals[i] - mean) / standardDev;\r
326                         }\r
327 \r
328                         // Calculate the average excluding outliers\r
329                         var deviationRange = 2.0;\r
330                         for (i = 0; i < size; i++) {\r
331                                 \r
332                                 if (vals[i] <= deviationRange && vals[i] >= -deviationRange) {\r
333                                         mCount++;\r
334                                         mSum += history[i];\r
335                                 }\r
336                         }\r
337                         \r
338                 } else {\r
339                         // Calculate the average (not enough data points to remove outliers)\r
340                         mCount = size;\r
341                         for (i = 0; i < size; i++) {\r
342                                 mSum += history[i];\r
343                         }\r
344                 }\r
345 \r
346                 return mSum / mCount;\r
347         };\r
348         \r
349 }</pre>    \r
350 </body>\r
351 </html>