| @@ -1,0 +1,545 @@ | ||
| 1 | +/* | |
| 2 | +The MIT License (MIT) | |
| 3 | + | |
| 4 | +Copyright (c) 2014 Valerio Neri | |
| 5 | + | |
| 6 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | +of this software and associated documentation files (the "Software"), to deal | |
| 8 | +in the Software without restriction, including without limitation the rights | |
| 9 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | +copies of the Software, and to permit persons to whom the Software is | |
| 11 | +furnished to do so, subject to the following conditions: | |
| 12 | + | |
| 13 | +The above copyright notice and this permission notice shall be included in all | |
| 14 | +copies or substantial portions of the Software. | |
| 15 | +*/ | |
| 16 | + | |
| 17 | + | |
| 18 | +var donutChart = function(chartElementID){ | |
| 19 | + var centerx = 0; | |
| 20 | + var centery = 0; | |
| 21 | + var sizex = 0; | |
| 22 | + var sizey = 0; | |
| 23 | + var scaling = 0; | |
| 24 | + var radius = 0; | |
| 25 | + var startx = 0; | |
| 26 | + var starty = 0; | |
| 27 | + var endx = 0; | |
| 28 | + var endy = 0; | |
| 29 | + var animationSpeed = 1; | |
| 30 | + var firedAnimation = false; | |
| 31 | + var innerCircleColor = "#666666"; | |
| 32 | + var outerCircleColor = "#aade87"; | |
| 33 | + var textColor = "#ffffff"; | |
| 34 | + var unitText = "%"; | |
| 35 | + var innerCircleDOM = undefined; | |
| 36 | + var outerCircleDOM = undefined; | |
| 37 | + var tNumberDOM = undefined; | |
| 38 | + var textDOM = undefined; | |
| 39 | + var tUnitDOM = undefined; | |
| 40 | + var titleDOM = undefined; | |
| 41 | + var svg = undefined; | |
| 42 | + var chartID = chartElementID; | |
| 43 | + var chart = undefined; | |
| 44 | + var lastValue = -1; | |
| 45 | + var startValue = 0; | |
| 46 | + var endValue = 0; | |
| 47 | + var loaded = false; | |
| 48 | + var that=this; | |
| 49 | + var maxValue = 100; | |
| 50 | + var titleText =""; | |
| 51 | + var titlePosition = "top"; | |
| 52 | + var titleColor = "#ffffff"; | |
| 53 | + var textShift = 20; // this is required for moving the chart | |
| 54 | + var textScaling = 1; | |
| 55 | + | |
| 56 | + // update: unfortunately in some cases the event is fired, and nobody tells us - that's why we just wait for the element to be available | |
| 57 | + // wait for the DOM, otherwise you won't find the reference to elements | |
| 58 | + //document.addEventListener("DOMContentLoaded", onLoad); | |
| 59 | + onLoad(); | |
| 60 | + | |
| 61 | + // this is used for refreshing the animation | |
| 62 | + (function() { | |
| 63 | + var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || | |
| 64 | + window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; | |
| 65 | + window.requestAnimationFrame = requestAnimationFrame; | |
| 66 | + })(); | |
| 67 | + | |
| 68 | + this.getValue = function(){ | |
| 69 | + if (lastValue>-1) | |
| 70 | + return Math.round(lastValue/360*maxValue*10)/10; | |
| 71 | + else | |
| 72 | + return 0; | |
| 73 | + } | |
| 74 | + | |
| 75 | + this.setValue = function(value){ | |
| 76 | + that.draw({end:value, animationSpeed:0}); | |
| 77 | + } | |
| 78 | + | |
| 79 | + function setAnimate(fromD, toD, duration){ | |
| 80 | + dAct = fromD; | |
| 81 | + // determine direction (up or down) | |
| 82 | + if (dAct<toD) | |
| 83 | + doIt(dAct, toD, duration, "up"); | |
| 84 | + else | |
| 85 | + doIt(dAct, toD, duration, "down"); | |
| 86 | + } | |
| 87 | + | |
| 88 | + // this function is used for the animation - it uses an exponential acceleration | |
| 89 | + function calculateAccValue(xx, m){ | |
| 90 | + var mxValue = m; | |
| 91 | + var x=Math.round(xx); | |
| 92 | + if (m==0){ | |
| 93 | + mxValue=1; | |
| 94 | + } | |
| 95 | + if (x==0){ | |
| 96 | + x=1; | |
| 97 | + } | |
| 98 | + if (Math.abs(x)>=mxValue){ | |
| 99 | + return mxValue; | |
| 100 | + }else{ | |
| 101 | + //return ( Math.pow( (-2),( (-1*x) + (Math.log(maxValue)/Math.log(2)) ) ) + maxValue); | |
| 102 | + var num1 = -2; | |
| 103 | + var num2 = Math.round( ((-1*x)+(Math.log(mxValue)/Math.log(2))) ); | |
| 104 | + return Math.pow(num1 , num2 )+mxValue; | |
| 105 | + } | |
| 106 | + } | |
| 107 | + | |
| 108 | + function textSetter(DOM, text){ | |
| 109 | + // text scaling | |
| 110 | + if ((text>=1000)&&(textScaling=1)){ | |
| 111 | + textScaling=1-((Math.floor( (Math.log(text)/Math.log(10))-2))/10)-0.1; | |
| 112 | + tNumberDOM.setAttribute('font-size', 50*scaling*textScaling); | |
| 113 | + tUnitDOM.setAttribute('font-size', 30*scaling*textScaling); | |
| 114 | + } else{ | |
| 115 | + textScaling = 1; | |
| 116 | + tNumberDOM.setAttribute('font-size', 50*scaling*textScaling); | |
| 117 | + tUnitDOM.setAttribute('font-size', 30*scaling*textScaling); | |
| 118 | + } | |
| 119 | + DOM.textContent = text; | |
| 120 | + } | |
| 121 | + | |
| 122 | + function doIt(dAct, toD, duration, direction){ | |
| 123 | + var toString = ""; | |
| 124 | + // -0.0001 is used for preventing IE reach 360 and close the circle | |
| 125 | + toString = getD(dAct-0.0001); | |
| 126 | + outerCircleDOM.setAttribute('d',toString); | |
| 127 | + | |
| 128 | + //force the value to be an integer | |
| 129 | + var anim_cur_val = Math.round(dAct/360*maxValue*10)/10; | |
| 130 | + //textSetter(tNumberDOM, Math.round(dAct/360*maxValue*10)/10); | |
| 131 | + textSetter(tNumberDOM, anim_cur_val.toFixed(0)); | |
| 132 | + | |
| 133 | + //console.log('dAct '+dAct+ ' toD'+toD); | |
| 134 | + // determine direction (up or down) | |
| 135 | + if (direction=="up") | |
| 136 | + dAct = dAct + 5.5; | |
| 137 | + else | |
| 138 | + dAct = dAct - 5.5; | |
| 139 | + | |
| 140 | + duration = duration - calculateAccValue(duration, 500); | |
| 141 | + if (direction=="up"){ | |
| 142 | + if (dAct < toD){ | |
| 143 | + setTimeout(function(){ | |
| 144 | + // animate it according to refresh rate | |
| 145 | + requestAnimationFrame(function(){ | |
| 146 | + doIt(dAct, toD, duration, direction); | |
| 147 | + }) | |
| 148 | + },duration); | |
| 149 | + } else { | |
| 150 | + | |
| 151 | + outerCircleDOM.setAttribute('d',getD((toD-0.0001))); | |
| 152 | + textSetter(tNumberDOM, Math.round(toD/360*maxValue*10)/10); | |
| 153 | + } | |
| 154 | + } else { | |
| 155 | + if (dAct >= toD){ | |
| 156 | + setTimeout(function(){ | |
| 157 | + // animate it according to refresh rate | |
| 158 | + requestAnimationFrame(function(){ | |
| 159 | + doIt(dAct, toD, duration, direction); | |
| 160 | + }) | |
| 161 | + },duration); | |
| 162 | + } else { | |
| 163 | + outerCircleDOM.setAttribute('d',getD(toD-0.0001)); | |
| 164 | + textSetter(tNumberDOM ,Math.round(toD/360*maxValue*10)/10); | |
| 165 | + } | |
| 166 | + } | |
| 167 | + | |
| 168 | + }; | |
| 169 | + | |
| 170 | + // this function gives us the circle coordinates | |
| 171 | + function getCoordinates(radius,offset,degrees){ | |
| 172 | + var radians = degreesToRadians(degrees); | |
| 173 | + var x = offset.x + radius * Math.cos(radians) | |
| 174 | + var y = offset.y + radius * Math.sin(radians) | |
| 175 | + return {x:x,y:y}; | |
| 176 | + }; | |
| 177 | + | |
| 178 | + // small converstion beween degrees and radians | |
| 179 | + function degreesToRadians(degrees){ | |
| 180 | + var radians = (degrees * Math.PI) / 180; | |
| 181 | + return radians | |
| 182 | + }; | |
| 183 | + | |
| 184 | + // this function returns the "d" string for the path, according to the degrees | |
| 185 | + function getD(degree){ | |
| 186 | + radius = 100*scaling; | |
| 187 | + startx = centerx+radius; | |
| 188 | + starty = centery; | |
| 189 | + var coor = getCoordinates(radius, {x:startx,y:starty},degree); | |
| 190 | + endx = coor.x; | |
| 191 | + endy = coor.y; | |
| 192 | + var largearc = 0; | |
| 193 | + if (degree>180){ | |
| 194 | + largearc=1; | |
| 195 | + } else { | |
| 196 | + largearc=0; | |
| 197 | + } | |
| 198 | + // don't ask me how I did it folks | |
| 199 | + d="M "+startx+" "+starty+" a "+radius+" "+radius+" 0 "+largearc+" 1 "+(endx-startx-radius)+" "+(endy-starty)+" L "+(centerx)+" "+(centery)+" Z"; | |
| 200 | + //console.log('GETd '+degree+ " "+d); | |
| 201 | + return d; | |
| 202 | + } | |
| 203 | + | |
| 204 | + // this function checks, if an element is fully visible (according to the scrolling) | |
| 205 | + function checkVisible(){ | |
| 206 | + if (firedAnimation){ | |
| 207 | + // animation has already fired, detach the event listeners | |
| 208 | + document.removeEventListener("scroll", checkVisible, false); | |
| 209 | + window.removeEventListener("resize", checkVisible, false); | |
| 210 | + return; | |
| 211 | + } | |
| 212 | + var rect = chart.getBoundingClientRect(); | |
| 213 | + var top = window.pageYOffset || document.documentElement.scrollTop; | |
| 214 | + var left = window.pageXOffset || document.documentElement.scrollLeft; | |
| 215 | + if ((rect.top>=0)&&(rect.top+rect.height<window.innerHeight) && | |
| 216 | + (rect.left>=0)&&(rect.left+rect.width<window.innerWidth)){ | |
| 217 | + // this means that we fully see the chart | |
| 218 | + // fire the animation (only once) | |
| 219 | + firedAnimation = true; | |
| 220 | + setAnimate(startValue, endValue, (500/animationSpeed)); | |
| 221 | + } | |
| 222 | + } | |
| 223 | + | |
| 224 | + var waitingLoad =0; | |
| 225 | + | |
| 226 | + function onLoad(){ | |
| 227 | + // get the container for the chart | |
| 228 | + chart = document.getElementById(chartID); | |
| 229 | + | |
| 230 | + // if the container is not ready in the DOM, then retry | |
| 231 | + // try for around 20secs, then throw an exception | |
| 232 | + if (chart==null){ | |
| 233 | + | |
| 234 | + // after 10 seconds, pause a little bit | |
| 235 | + if ((waitingLoad > 10000)&&(waitingLoad<20000)){ | |
| 236 | + setTimeout(onLoad, 1000); | |
| 237 | + waitingLoad = waitingLoad +1000; | |
| 238 | + return; | |
| 239 | + } | |
| 240 | + if (waitingLoad > 20000){ | |
| 241 | + throw('donutChart: onLoad() - The chart element "'+chartID+'" could not be loaded in the last 20 seconds'); | |
| 242 | + } | |
| 243 | + setTimeout(onLoad, 500); | |
| 244 | + waitingLoad = waitingLoad +500; | |
| 245 | + return; | |
| 246 | + } | |
| 247 | + // create an svg object and all other things - thanks to Thoka | |
| 248 | + svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); | |
| 249 | + innerCircleDOM = document.createElementNS('http://www.w3.org/2000/svg','circle'); | |
| 250 | + outerCircleDOM = document.createElementNS('http://www.w3.org/2000/svg','path'); | |
| 251 | + textDOM = document.createElementNS('http://www.w3.org/2000/svg','text'); | |
| 252 | + tNumberDOM = document.createElementNS('http://www.w3.org/2000/svg','tspan'); | |
| 253 | + tUnitDOM = document.createElementNS('http://www.w3.org/2000/svg','tspan'); | |
| 254 | + titleDOM = document.createElementNS('http://www.w3.org/2000/svg','text'); | |
| 255 | + | |
| 256 | + // append to the chart | |
| 257 | + chart.appendChild(svg); | |
| 258 | + svg.appendChild(outerCircleDOM); | |
| 259 | + svg.appendChild(innerCircleDOM); | |
| 260 | + svg.appendChild(textDOM); | |
| 261 | + svg.appendChild(titleDOM); | |
| 262 | + | |
| 263 | + textDOM.appendChild(tNumberDOM); | |
| 264 | + textDOM.appendChild(tUnitDOM); | |
| 265 | + loaded = true; | |
| 266 | + } | |
| 267 | + | |
| 268 | + this.reload = function(){ | |
| 269 | + if (!loaded) | |
| 270 | + onLoad(); | |
| 271 | + } | |
| 272 | + | |
| 273 | + this.clear = function(){ | |
| 274 | + // reinitialize some parameters | |
| 275 | + firedAnimation = false; | |
| 276 | + animationSpeed = 1; | |
| 277 | + maxValue = 100; | |
| 278 | + unitText = "%"; | |
| 279 | + lastValue = -1; | |
| 280 | + this.setValue(0); | |
| 281 | + } | |
| 282 | + | |
| 283 | + this.delete = function(){ | |
| 284 | + // remove everything | |
| 285 | + this.clear(); | |
| 286 | + textDOM.removeChild(tNumberDOM); | |
| 287 | + textDOM.removeChild(tUnitDOM); | |
| 288 | + svg.removeChild(textDOM); | |
| 289 | + svg.removeChild(titleDOM); | |
| 290 | + svg.removeChild(outerCircleDOM); | |
| 291 | + svg.removeChild(innerCircleDOM); | |
| 292 | + chart.removeChild(svg); | |
| 293 | + loaded = false; | |
| 294 | + // yes but we leave chart, because it was provided | |
| 295 | + } | |
| 296 | + | |
| 297 | + this.draw = function(options){ | |
| 298 | + // check if main function has already loaded, if not, reiterate | |
| 299 | + if (!loaded){ | |
| 300 | + setTimeout(function(){ | |
| 301 | + that.draw(options); | |
| 302 | + }, 500); | |
| 303 | + return; | |
| 304 | + } | |
| 305 | + | |
| 306 | + // OPTION CHECK - contains the options | |
| 307 | + // check if all options are set | |
| 308 | + var oTester = []; | |
| 309 | + oTester.options = typeof(options)!="undefined"; | |
| 310 | + | |
| 311 | + if (! (oTester.options)){ | |
| 312 | + throw('donutChart: draw() - Not enough parameters or no parameters set in object'); | |
| 313 | + return; | |
| 314 | + } | |
| 315 | + | |
| 316 | + oTester.end = typeof(options.end)!="undefined"; | |
| 317 | + oTester.start = typeof(options.start)!="undefined"; | |
| 318 | + oTester.scaling = typeof(options.scaling)!="undefined"; | |
| 319 | + oTester.size = typeof(options.size)!="undefined"; | |
| 320 | + oTester.animationSpeed = typeof(options.animationSpeed)!="undefined"; | |
| 321 | + oTester.textColor = typeof(options.textColor)!="undefined"; | |
| 322 | + oTester.innerCircleColor = typeof(options.innerCircleColor)!="undefined"; | |
| 323 | + oTester.outerCircleColor = typeof(options.outerCircleColor)!="undefined"; | |
| 324 | + oTester.unitText = typeof(options.unitText)!="undefined"; | |
| 325 | + oTester.maxValue = typeof(options.maxValue)!="undefined"; | |
| 326 | + oTester.titleText = typeof(options.titleText)!="undefined"; | |
| 327 | + oTester.titleColor = typeof(options.titleColor)!="undefined"; | |
| 328 | + oTester.titlePosition = typeof(options.titlePosition)!="undefined"; | |
| 329 | + | |
| 330 | + if (! (oTester.end)){ | |
| 331 | + throw('donutChart: draw() - No "end" value specified'); | |
| 332 | + return; | |
| 333 | + } | |
| 334 | + | |
| 335 | + // reinitialize some parameters | |
| 336 | + firedAnimation = false; | |
| 337 | + animationSpeed = 1; | |
| 338 | + maxValue = 100; | |
| 339 | + unitText = "%"; | |
| 340 | + textShift = 20; | |
| 341 | + textScaling = 1; | |
| 342 | + | |
| 343 | + // if the values are not set, set the standard | |
| 344 | + if (!oTester.size){ | |
| 345 | + options.size = 200; | |
| 346 | + } | |
| 347 | + | |
| 348 | + if (!oTester.scaling){ | |
| 349 | + options.scaling = 1; | |
| 350 | + } | |
| 351 | + | |
| 352 | + // if size ist not set, then take the options.scaling and the standard size of 200x200 | |
| 353 | + if (!oTester.size){ | |
| 354 | + svg.setAttribute('width', 200*options.scaling); | |
| 355 | + svg.setAttribute('height', 200*options.scaling); | |
| 356 | + options.size = 200*options.scaling; | |
| 357 | + } | |
| 358 | + // if scaling not set, then take the size anc calculate the options.scaling | |
| 359 | + if (!oTester.scaling){ | |
| 360 | + svg.setAttribute('width', options.size); | |
| 361 | + svg.setAttribute('height', options.size); | |
| 362 | + if (svg.getAttribute('width')<svg.getAttribute('height')){ | |
| 363 | + options.scaling = svg.getAttribute('width') / 200; | |
| 364 | + } else{ | |
| 365 | + options.scaling = svg.getAttribute('height') / 200; | |
| 366 | + } | |
| 367 | + } | |
| 368 | + | |
| 369 | + // set the colors, if set | |
| 370 | + if (oTester.outerCircleColor){ | |
| 371 | + outerCircleColor = options.outerCircleColor; | |
| 372 | + } | |
| 373 | + if (oTester.innerCircleColor){ | |
| 374 | + innerCircleColor = options.innerCircleColor; | |
| 375 | + } | |
| 376 | + if (oTester.textColor){ | |
| 377 | + textColor = options.textColor; | |
| 378 | + } | |
| 379 | + | |
| 380 | + // set the unitText, if set | |
| 381 | + if (oTester.unitText){ | |
| 382 | + unitText = options.unitText; | |
| 383 | + } | |
| 384 | + | |
| 385 | + // set the title, if set | |
| 386 | + if (oTester.titleText){ | |
| 387 | + titleText = options.titleText; | |
| 388 | + } | |
| 389 | + if (oTester.titleColor){ | |
| 390 | + titleColor = options.titleColor; | |
| 391 | + } | |
| 392 | + if (oTester.titlePosition){ | |
| 393 | + titlePosition = options.titlePosition; | |
| 394 | + } | |
| 395 | + | |
| 396 | + | |
| 397 | + // set the maxValue, if set | |
| 398 | + if (oTester.maxValue){ | |
| 399 | + maxValue = options.maxValue; | |
| 400 | + } | |
| 401 | + | |
| 402 | + // set the starting position, if set | |
| 403 | + if (oTester.start){ | |
| 404 | + options.start = Math.round(parseFloat(options.start)*10)/10; | |
| 405 | + if (options.start>maxValue) | |
| 406 | + options.start = maxValue; | |
| 407 | + if (options.start<0) | |
| 408 | + options.start = 0; | |
| 409 | + if (isNaN(options.start)){ | |
| 410 | + // not a number and not parseable, ignore | |
| 411 | + options.start = 0; | |
| 412 | + oTester.start = false; | |
| 413 | + } | |
| 414 | + startValue = options.start/maxValue*360; | |
| 415 | + } | |
| 416 | + | |
| 417 | + options.end = Math.round(parseFloat(options.end)*10)/10; | |
| 418 | + | |
| 419 | + if (options.end>maxValue) | |
| 420 | + options.end = maxValue; | |
| 421 | + if (options.end<0) | |
| 422 | + options.end = 0; | |
| 423 | + | |
| 424 | + if (isNaN(options.end)){ | |
| 425 | + // not a number and not parseable, ignore | |
| 426 | + return; | |
| 427 | + } | |
| 428 | + | |
| 429 | + options.end = options.end/maxValue*360; | |
| 430 | + endValue = options.end; | |
| 431 | + | |
| 432 | + textShift = textShift*options.scaling; | |
| 433 | + | |
| 434 | + // set the size and the center | |
| 435 | + sizex = options.size; | |
| 436 | + sizey = options.size+2*textShift; | |
| 437 | + centerx = sizex/2; | |
| 438 | + centery = (sizey/2); | |
| 439 | + scaling = options.scaling; | |
| 440 | + | |
| 441 | + // set animation speed (0 = no animation), standard is one | |
| 442 | + if(oTester.animationSpeed){ | |
| 443 | + animationSpeed = options.animationSpeed; | |
| 444 | + } | |
| 445 | + | |
| 446 | + //e4j | |
| 447 | + var innerCircleStroke = typeof(options.innerCircleStroke)!="undefined" ? options.innerCircleStroke : 'none'; | |
| 448 | + var outerCircleStroke = typeof(options.outerCircleStroke)!="undefined" ? options.outerCircleStroke : 'none'; | |
| 449 | + // | |
| 450 | + | |
| 451 | + // initialise with start position | |
| 452 | + outerCircleDOM.setAttribute('d', getD(startValue)); | |
| 453 | + | |
| 454 | + chart.style.width = sizex; | |
| 455 | + chart.style.height = sizey; | |
| 456 | + | |
| 457 | + svg.setAttribute('height', sizey); | |
| 458 | + svg.setAttribute('class', 'donutChart'); | |
| 459 | + svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); | |
| 460 | + svg.setAttribute('version', '1.1'); | |
| 461 | + | |
| 462 | + innerCircleDOM.setAttribute('cx', centerx); | |
| 463 | + innerCircleDOM.setAttribute('cy', centery); | |
| 464 | + innerCircleDOM.setAttribute('r', 80*options.scaling); | |
| 465 | + innerCircleDOM.setAttribute('stroke', innerCircleStroke); | |
| 466 | + innerCircleDOM.setAttribute('stroke-width', '2'); | |
| 467 | + innerCircleDOM.setAttribute('fill', innerCircleColor); | |
| 468 | + | |
| 469 | + outerCircleDOM.setAttribute('fill', outerCircleColor); | |
| 470 | + outerCircleDOM.setAttribute('stroke', outerCircleStroke); | |
| 471 | + outerCircleDOM.setAttribute('stroke-width', '36'); | |
| 472 | + | |
| 473 | + tNumberDOM.setAttribute('x', centerx); | |
| 474 | + tNumberDOM.setAttribute('y', centery+Math.round(18.75*options.scaling)); | |
| 475 | + tNumberDOM.setAttribute('font-size', 50*options.scaling); | |
| 476 | + tNumberDOM.setAttribute('fill', textColor); | |
| 477 | + tNumberDOM.setAttribute('font-family', 'arial'); | |
| 478 | + tNumberDOM.setAttribute('font-weight', 'normal'); | |
| 479 | + tNumberDOM.setAttribute('text-anchor', 'middle'); | |
| 480 | + | |
| 481 | + tUnitDOM.setAttribute('font-size', 30*options.scaling); | |
| 482 | + tUnitDOM.textContent = unitText; | |
| 483 | + tUnitDOM.setAttribute('fill', textColor); | |
| 484 | + tUnitDOM.setAttribute('text-anchor', 'middle'); | |
| 485 | + tUnitDOM.setAttribute('font-family', 'arial'); | |
| 486 | + tUnitDOM.setAttribute('font-weight', 'normal'); | |
| 487 | + | |
| 488 | + titleDOM.setAttribute('x', centerx); | |
| 489 | + // set the position of the title | |
| 490 | + switch(titlePosition){ | |
| 491 | + case "inner-bottom": | |
| 492 | + if (!oTester.titleColor) | |
| 493 | + titleColor = "#ffffff"; | |
| 494 | + titleDOM.setAttribute('y', centery+sizey/5+textShift/2); | |
| 495 | + break; | |
| 496 | + | |
| 497 | + case "outer-bottom": | |
| 498 | + if (!oTester.titleColor) | |
| 499 | + titleColor = "#666666"; | |
| 500 | + | |
| 501 | + titleDOM.setAttribute('y', sizey-textShift/2); | |
| 502 | + break; | |
| 503 | + | |
| 504 | + case "inner-top": | |
| 505 | + if (!oTester.titleColor) | |
| 506 | + titleColor = "#ffffff"; | |
| 507 | + titleDOM.setAttribute('y', centery-sizey/5-textShift/2); | |
| 508 | + break; | |
| 509 | + | |
| 510 | + default: | |
| 511 | + case "outer-top": | |
| 512 | + if (!oTester.titleColor) | |
| 513 | + titleColor = "#666666"; | |
| 514 | + | |
| 515 | + titleDOM.setAttribute('y', textShift/2); | |
| 516 | + break; | |
| 517 | + } | |
| 518 | + | |
| 519 | + titleDOM.setAttribute('font-size', 12*options.scaling); | |
| 520 | + titleDOM.setAttribute('fill', titleColor); | |
| 521 | + titleDOM.setAttribute('font-family', 'arial'); | |
| 522 | + titleDOM.setAttribute('font-weight', 'normal'); | |
| 523 | + titleDOM.setAttribute('text-anchor', 'middle'); | |
| 524 | + titleDOM.textContent = titleText; | |
| 525 | + | |
| 526 | + | |
| 527 | + // if the animation has been chosen | |
| 528 | + if (animationSpeed>0){ | |
| 529 | + // ignore start value if lastvalue is already set | |
| 530 | + if (lastValue>-1){ | |
| 531 | + startValue = lastValue; | |
| 532 | + } | |
| 533 | + window.addEventListener("resize", checkVisible, false); | |
| 534 | + document.addEventListener("scroll", checkVisible, false); | |
| 535 | + tNumberDOM.textContent = Math.round(startValue/360*maxValue*10)/10; | |
| 536 | + checkVisible(); | |
| 537 | + } else { | |
| 538 | + // set the circle to the end position, without animation | |
| 539 | + // the 0.0001 is for avoiding the circle to disappear, due to some browser | |
| 540 | + outerCircleDOM.setAttribute('d', getD(options.end-0.0001)); | |
| 541 | + tNumberDOM.textContent = Math.round(options.end/360*maxValue*10)/10; | |
| 542 | + } | |
| 543 | + lastValue = endValue; | |
| 544 | + } | |
| 545 | +} | |