1(function(window, document, undefined) { "use strict"; 2 3 /** 4 * Find the absolute position of an element 5 */ 6 var absPos = function(element) { 7 var offsetLeft, offsetTop; 8 offsetLeft = offsetTop = 0; 9 if (element.offsetParent) { 10 do { 11 offsetLeft += element.offsetLeft; 12 offsetTop += element.offsetTop; 13 } while (element = element.offsetParent); 14 } 15 return [offsetLeft, offsetTop]; 16 }; 17 18 /** 19 * @constructor Progress Circle class 20 * @param params.canvas Canvas on which the circles will be drawn. 21 * @param params.minRadius Inner radius of the innermost circle, in px. 22 * @param params.arcWidth Width of each circle(to be more accurate, ring). 23 * @param params.gapWidth Space between each circle. 24 * @param params.centerX X coordinate of the center of circles. 25 * @param params.centerY Y coordinate of the center of circles. 26 * @param params.infoLineBaseAngle Base angle of the info line. 27 * @param params.infoLineAngleInterval Angles between the info lines. 28 */ 29 var ProgressCircle = function(params) { 30 this.canvas = params.canvas; 31 this.minRadius = params.minRadius || 15; 32 this.arcWidth = params.arcWidth || 5; 33 this.gapWidth = params.gapWidth || 3; 34 this.centerX = params.centerX || this.canvas.width / 2; 35 this.centerY = params.centerY || this.canvas.height / 2;
36 this.infoLineLength = params.infoLineLength || 60; 37 this.horizLineLength = params.horizLineLength || 10; 38 this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8; 39 this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6; 40 41 this.context = this.canvas.getContext('2d'); 42 43 this.width = this.canvas.width; 44 this.height = this.canvas.height; 45 46 this.circles = []; 47 this.runningCount = 0; 48 }; 49 50 ProgressCircle.prototype = { 51 constructor: ProgressCircle, 52 53 /** 54 * @method Adds an progress monitor entry. 55 * @param params.fillColor Color to fill in the circle. 56 * @param params.outlineColor Color to outline the circle. 57 * @param params.progressListener Callback function to fetch the progress. 58 * @param params.infoListener Callback function to fetch the info. 59 * @returns this 60 */ 61 addEntry: function(params) { 62 this.circles.push(new Circle({ 63 canvas: this.canvas, 64 context: this.context, 65 centerX: this.centerX, 66 centerY: this.centerY, 67 innerRadius: this.minRadius + this.circles.length * 68 (this.gapWidth + this.arcWidth), 69 arcWidth: this.arcWidth,
70 infoLineLength: this.infoLineLength, 71 horizLineLength: this.horizLineLength, 72 73 id: this.circles.length, 74 fillColor: params.fillColor, 75 outlineColor: params.outlineColor, 76 progressListener: params.progressListener, 77 infoListener: params.infoListener, 78 infoLineAngle: this.infoLineBaseAngle + 79 this.circles.length * this.infoLineAngleInterval, 80 })); 81 82 return this; 83 }, 84 85 /** 86 * @method Starts the monitor and updates with the given interval. 87 * @param interval Interval between updates, in millisecond. 88 * @returns this 89 */ 90 start: function(interval) { 91 var self = this; 92 this.timer = setInterval(function() { 93 self._update(); 94 }, interval || 33); 95 96 return this; 97 }, 98 99 /** 100 * @method Stop the animation. 101 */ 102 stop: function() { 103 clearTimeout(this.timer); 104 }, 105 106 /** 107 * @private 108 * @method Call update on each circle and redraw them. 109 * @returns this 110 */ 111 _update: function() { 112 this._clear(); 113 this.circles.forEach(function(circle, idx, array) { 114 circle.update(); 115 }); 116 117 return this; 118 }, 119 120 /** 121 * @private 122 * @method Clear the canvas. 123 * @returns this 124 */ 125 _clear: function() { 126 this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 127 128 return this; 129 }, 130 131 }; 132 133 /** 134 * @private 135 * @class Individual progress circle. 136 * @param params.canvas Canvas on which the circle will be drawn. 137 * @param params.context Context of the canvas. 138 * @param params.innerRadius Inner radius of the circle, in px. 139 * @param params.arcWidth Width of each arc(circle). 140 * @param params.gapWidth Distance between each arc. 141 * @param params.centerX X coordinate of the center of circles. 142 * @param params.centerY Y coordinate of the center of circles. 143 * @param params.fillColor Color to fill in the circle. 144 * @param params.outlineColor Color to outline the circle. 145 * @param params.progressListener Callback function to fetch the progress. 146 * @param params.infoListener Callback function to fetch the info. 147 * @param params.infoLineAngle Angle of info line. 148 */ 149 var Circle = function(params) { 150 this.id = params.id; 151 this.canvas = params.canvas; 152 this.context = params.context; 153 this.centerX = params.centerX; 154 this.centerY = params.centerY; 155 this.arcWidth = params.arcWidth; 156 this.innerRadius = params.innerRadius || 0; 157 this.fillColor = params.fillColor || '#fff'; 158 this.outlineColor = params.outlineColor || this.fillColor; 159 this.progressListener = params.progressListener;
160 this.infoLineLength = params.infoLineLength || 250; 161 this.horizLineLength = params.horizLineLength || 50; 162 this.infoListener = params.infoListener; 163 this.infoLineAngle = params.infoLineAngle; 164 165 this.outerRadius = this.innerRadius + this.arcWidth; 166 167 // If the info listener is not registered, then don't calculate 168 // the related coordinates 169 if (!this.infoListener) return; 170 171 // calculate the info-line turning points 172 var angle = this.infoLineAngle, 173 arcDistance = (this.innerRadius + this.outerRadius) / 2, 174 175 sinA = Math.sin(angle), 176 cosA = Math.cos(angle); 177 178 this.infoLineStartX = this.centerX + sinA * arcDistance; 179 this.infoLineStartY = this.centerY - cosA * arcDistance; 180 181 this.infoLineMidX = this.centerX + sinA * this.infoLineLength; 182 this.infoLineMidY = this.centerY - cosA * this.infoLineLength; 183 184 this.infoLineEndX = this.infoLineMidX + 185 (sinA < 0 ? -this.horizLineLength : this.horizLineLength); 186 this.infoLineEndY = this.infoLineMidY; 187 188 var infoText = document.createElement('div'), 189 style = infoText.style; 190 191 style.color = this.fillColor; 192 style.position = 'absolute'; 193 style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px'; 194 // style.top will be calculated in the `drawInfo` method. Since 195 // user may want to change the size of the font, so the top offset 196 // must be updated in each loop. 197 infoText.className = 'ProgressCircleInfo'; // For css styling 198 infoText.id = 'progress_circle_info_' + this.id; 199 document.body.appendChild(infoText); 200 this.infoText = infoText; 201 }; 202 203 Circle.prototype = { 204 constructor: Circle, 205 206 update: function() { 207 this.progress = this.progressListener(); 208 this._draw(); 209 210 if (this.infoListener) { 211 this.info = this.infoListener(); 212 this._drawInfo(); 213 } 214 }, 215 216 /** 217 * @private 218 * @method Draw the circle on the canvas. 219 * @returns this 220 */ 221 _draw: function() { 222 var ctx = this.context, 223 224 ANGLE_OFFSET = -Math.PI / 2, 225 226 startAngle = 0 + ANGLE_OFFSET, 227 endAngle= startAngle + this.progress * Math.PI * 2, 228 229 x = this.centerX, 230 y = this.centerY, 231 232 innerRadius = this.innerRadius, 233 outerRadius = this.outerRadius; 234 235 ctx.fillStyle = this.fillColor; 236 ctx.strokeStyle = this.outlineColor; 237 238 ctx.beginPath(); 239 ctx.arc(x, y, innerRadius, startAngle, endAngle, false); 240 ctx.arc(x, y, outerRadius, endAngle, startAngle, true); 241 ctx.closePath(); 242 ctx.stroke(); 243 ctx.fill(); 244 245 return this; 246 }, 247 248 /** 249 * @private 250 * @method Draw the info lines and info text. 251 * @returns this 252 */ 253 _drawInfo: function() { 254 255 var pointList, lineHeight; 256 257 pointList = [ 258 [this.infoLineStartX, this.infoLineStartY], 259 [this.infoLineMidX, this.infoLineMidY], 260 [this.infoLineEndX, this.infoLineEndY], 261 ]; 262 this._drawSegments(pointList, false); 263 264 this.infoText.innerHTML = this.info; 265 266 lineHeight = this.infoText.offsetHeight; 267 this.infoText.style.top = this.infoLineEndY + 268 absPos(this.canvas)[1] - lineHeight / 2 + 'px'; 269 270 return this; 271 }, 272 273 /** 274 * @private 275 * @method Helper function to draw the segments 276 * @param pointList An array of points in the form of [x, y]. 277 * @param close Whether to connect the first and last point. 278 */ 279 _drawSegments: function(pointList, close) { 280 var ctx = this.context; 281 282 ctx.beginPath(); 283 ctx.moveTo(pointList[0][0], pointList[0][1]); 284 for (var i = 1; i < pointList.length; ++i) { 285 ctx.lineTo(pointList[i][0], pointList[i][1]); 286 } 287 288 if (close) { 289 ctx.closePath(); 290 } 291 ctx.stroke(); 292 }, 293 }; 294 295 window.ProgressCircle = ProgressCircle; 296 297})(window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.