// circles // copyright Artan Sinani // https://github.com/lugolabs/circles /* Lightwheight JavaScript library that generates circular graphs in SVG. Call Circles.create(options) with the following options: id - the DOM element that will hold the graph percentage - the percentage dictating the smaller circle radius - the radius of the circles width - the width of the ring (optional, has value 10, if not specified) number - the number to display at the centre of the graph (optional, the percentage will show if not specified) text - the text to display after the number (optional, nothing will show if not specified) colors - an array of colors, with the first item coloring the full circle (optional, it will be `['#EEE', '#F00']` if not specified) duration - value in ms of animation duration; (optional, defaults to 500); if `null` is passed, the animation will not run API: generate(radius) - regenerates the circle with the given radius (see spec/responsive.html for an example hot to create a responsive circle) */ (function() { var Circles = window.Circles = function(options) { var elId = options.id; this._el = document.getElementById(elId); if (this._el === null) return; this._radius = options.radius; this._percentage = options.percentage; this._text = options.text; // #3 this._number = options.number || this._percentage; this._strokeWidth = options.width || 10; this._colors = options.colors || ['#EEE', '#F00']; this._interval = 16; this._textWrpClass = 'circles-text-wrp'; this._textClass = 'circles-text'; this._numberClass = 'circles-number'; this._confirmAnimation(options.duration); var endAngleRad = Math.PI / 180 * 270; this._start = -Math.PI / 180 * 90; this._startPrecise = this._precise(this._start); this._circ = endAngleRad - this._start; this.generate(); if (this._canAnimate) this._animate(); }; Circles.prototype = { VERSION: '0.0.4', generate: function(radius) { if (radius) { this._radius = radius; this._canAnimate = false; } this._svgSize = this._radius * 2; this._radiusAdjusted = this._radius - (this._strokeWidth / 2); this._el.innerHTML = this._wrap(this._generateSvg() + this._generateText()); }, _confirmAnimation: function(duration) { if (duration === null) { this._canAnimate = false; return; } duration = duration || 500; var step = duration / this._interval, pathFactor = this._percentage / step, numberFactor = this._number / step; if (this._percentage <= (1 + pathFactor)) { this._canAnimate = false; } else { this._canAnimate = true; this._pathFactor = pathFactor; this._numberFactor = numberFactor; } }, _animate: function() { var i = 1, self = this, path = this._el.getElementsByTagName('path')[1], numberEl = this._getNumberElement(), isInt = this._number % 1 === 0, requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { setTimeout(callback, self._interval); }, animate = function() { var percentage = self._pathFactor * i, nextPercentage = self._pathFactor * (i + 1), number = self._numberFactor * i, canContinue = true; if (isInt) { number = Math.round(number); } if (nextPercentage > self._percentage) { percentage = self._percentage; number = self._number; canContinue = false; } if (percentage > self._percentage) return; path.setAttribute('d', self._calculatePath(percentage, true)); numberEl.innerHTML = self._calculateNumber(number); i++; if (canContinue) requestAnimFrame(animate); }; requestAnimFrame(animate); }, _getNumberElement: function() { var divs = this._el.getElementsByTagName('span'); for (var i = 0, l = divs.length; i < l; i++) { if (divs[i].className === this._numberClass) return divs[i]; } }, _wrap: function(content) { return '