<a href="https://github.com/aorcsik/radial-progress-bar" target="_blank"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
<br>
<section>
  <div id="example1" class="example"></div>
  <h2>Radial Progress Bar</h2>
  <p>The default radial progress bar. Blue progress bar, semi-transparent background path, 40px progress text in the center. Subsequent percentage settings can be queued.</p>
  <!-- <p><strong>HTML</strong></p>
  <pre>
&lt;div id="example1"&gt;&lt;/div&gt;</pre>
  <p><strong>JavaScript</strong></p>
  <pre>
jQuery("#example1").radialProgress("init", {
  'size': 100,
  'fill': 5
}).radialProgress("to", {'perc': 50})
  .radialProgress("to", {'perc': 30})
  .radialProgress("to", {'perc': 100});</pre>-->
</section>
<section>
  <div id="pie" class="example" style="width: 100px;"></div>
  <h2>Simple Pie Chart</h2>
  <p>Multiple radial progress bars layered on top and offsetted by each other. Values are visible in the center as a list. Data is loaded in initialization.</p>
</section>
<section>
  <div id="multi" class="example" style="width: 100px;"></div>
  <h2>Concentric Bars</h2>
  <p>Multiple radial progress bars in concentric circles around each other. Defined as regular radial progress bar, empty on init, each bar can be set separately or together. </p>
  <p>With ranges and periodic updates the clock on the left can be easily created.</p> 
</section>
<section>
  <h2>Inline Icons</h2>
  With a small size and fill settings and transparent text inline icon progress bar <span id="smallrad" style="display: inline-block;"></span> or pie chart <span id="smallpie" style="display: inline-block;"></span> can be created.</span>
</section>
body {
  font-family: "Helvetica", "Arial", sans-serif;
  font-size: 20px;
}

section {
  margin-bottom: 20px;
  margin-right: 2.5%;
  margin-left: 2.5%;
  margin-top: 20px;
  padding: 0 
}

section p,
section pre {
  margin-left: 120px;
}

section pre {
  background: rgba(0,0,0,0.1);
  padding: 10px;
  border-radius: 3px
}

h2 {
  margin: 0 0 10px 0; 
}


.example {
  float: left;
  margin-right: 20px;
}

@media (min-width: 481px) {
  section {
    width: 45%;
    float: left;
  }
  section:nth-child(odd) {
    clear: both;
  }
}
(function($){

function radialProgress($obj, options) {
  var defaults = {
    "inline": true,
    "font-size": 40,
    "font-family": "Helvetica, Arial, sans-serif",
    "text-color": null,
    "lines": 1,
    "line": 0,
    "symbol": "",
    "margin": 0, 
    "color": "rgb(55,123,181)",
    "background": "rgba(0,0,0,0.1)",
    "size": $obj.outerWidth(),
    "fill": "5px",
    "range": [0, 100]
  };
  this.options = $.extend(defaults, options);

  this.first_rot_base = -135;
  this.second_rot_base = -315;
  
  this.options['size'] = parseInt(this.options['size'], 10);
  this.options['fill'] = parseInt(this.options['fill'], 10);
  this.options['font-size'] = parseInt(this.options['font-size'], 10);
  this.options['margin'] = Math.max(0, parseInt(this.options['margin'], 10));
  this.options['text-color'] = this.options['text-color'] || this.options['color'];
  
  $obj.css({
    "position": "relative",
    "width": this.options['size'],
    "height": this.options['size'],
    "display": this.options['inline'] ? "inline-block" : "block"
  });
    
  this.$radialBackground = $("<div>").appendTo($obj).css({
    "box-sizing": "border-box",
    "-moz-box-sizing": "border-box",
    "-webkit-box-sizing": "border-box",
    "position": "absolute",
    "top": this.options['margin'],
    "left": this.options['margin'],
    "width": this.options['size'] - this.options['margin'] * 2,
    "height": this.options['size'] - this.options['margin'] * 2,
    "border": this.options['fill'] + "px solid " + this.options['background'],
    "border-radius": Math.ceil(this.options['size'] / 2) + "px",
  });
  
  this.$radialFirstHalfMask = $("<div>").appendTo($obj).css({
    "position": "absolute",
    "top": this.options['margin'],
    "right": this.options['margin'],
    "width": Math.round(this.options['size'] / 2) - this.options['margin'],
    "height": this.options['size'] - this.options['margin'] * 2,
    "overflow": "hidden"
  });

  this.$radialSecondHalfMask = $("<div>").appendTo($obj).css({
    "position": "absolute",
    "top": this.options['margin'],
    "left": this.options['margin'],
    "width": Math.round(this.options['size'] / 2) - this.options['margin'],
    "height": this.options['size'] - this.options['margin'] * 2,
    "overflow": "hidden"
  });
  
  this.$radialFirstHalf = $("<div>").appendTo(this.$radialFirstHalfMask).css({
    "box-sizing": "border-box",
    "-moz-box-sizing": "border-box",
    "-webkit-box-sizing": "border-box",
    "position": "absolute",
    "top": "0px",
    "border-width": this.options['fill'],
    "border-style": "solid",
    "border-color": this.options['color'] + " " + this.options['color'] + " transparent transparent",
    "width": "200%",
    "height": "100%",
    "border-radius": "50%",
    "left": "-100%",
    "transform": "rotate(" + this.first_rot_base + "deg)"
  });

  this.$radialSecondHalf = $("<div>").appendTo(this.$radialSecondHalfMask).css({
    "box-sizing": "border-box",
    "-moz-box-sizing": "border-box",
    "-webkit-box-sizing": "border-box",
    "position": "absolute",
    "top": "0px",
    "border-width": this.options['fill'],
    "border-style": "solid",
    "border-color": this.options['color'] + " " + this.options['color'] + " transparent transparent",
    "width": "200%",
    "height": "100%",
    "border-radius": "50%",
    "left": "0px",
    "transform": "rotate(" + this.second_rot_base + "deg)"
  });
  
  if (this.options['text-color']) {
    this.$radialLabel = $("<div>").appendTo($obj).css({
      "position": "absolute",
      "font-size": this.options['font-size'] + "px",
      "font-family": this.options['font-family'],
      "color": this.options['text-color'],
      "left": "50%",
      "top": "50%",
      "transform": "translate(-50%, -50%)"
    });
  }

  this.perc = 0;
  this.queue = [];
}

radialProgress.prototype.toPerc = function(options) {
  var self = this,
      offset = options['offset'] || 0,
      interval_delay = 10,
      time = options['time'] || 1000,
      targetPerc = Math.max(0, Math.min(100, (options['perc'] - self.options['range'][0]) / (self.options['range'][1] - self.options['range'][0]) * 100)),
      diffPerc = targetPerc - this.perc,
      direction = diffPerc / Math.abs(diffPerc),
      step = diffPerc / (time / interval_delay);
  if (!this.animation) {
    this.animation = setInterval(function() {
      if ((direction > 0 && self.perc >= targetPerc) || (direction < 0 && self.perc <= targetPerc)) {
        window.clearInterval(self.animation);
        self.animation = null;
        var next = self.queue.shift();
        if (next) self.toPerc(next);
        return;
      }
      self.perc += step;
      var first_rot = self.first_rot_base;
      var second_rot = self.second_rot_base;
      if (self.perc < 50) {
        first_rot = self.first_rot_base + (self.perc / 50) * 180;
        second_rot = self.second_rot_base;
      } else {
        first_rot = self.first_rot_base + 1 * 180;
        second_rot = self.second_rot_base + ((self.perc - 50) / 50) * 180;
      }
      self.$radialFirstHalf.css({
        "transform": "rotate(" + first_rot + "deg)"
      });
      self.$radialSecondHalf.css({
        "transform": "rotate(" + second_rot + "deg)"
      });
      if (self.$radialLabel) {
        var value = targetPerc ? self.perc/targetPerc * (targetPerc - offset) : 0;
        value = self.options['range'][0] + value / 100 * (self.options['range'][1] - self.options['range'][0]);
        var text = Math.round(value + self.options['symbol']);
        for (var ti = 0; ti < self.options['line']; ti++) text = "&nbsp;<br>" + text;
        for (var ti = self.options['lines'] - (self.options['line'] + 1); ti > 0; ti--) text = text + "<br>&nbsp;";
        self.$radialLabel.html(text);
      }
    }, interval_delay);
  } else {
    this.queue.push(options);
  }
};

$.fn.radialProgress = function(func, options) {
  if (func === "init") {
    $(this).data("__radialProgress", new radialProgress($(this), options));
  } else if ($(this).data("__radialProgress")) {
    if (func === "to") $(this).data("__radialProgress").toPerc(options)
  }
  return this;
};
  
$.fn.radialPieChart = function(func, options) {
  if (func === "init") {
    var sum = options['data'].reduce(function(a, item) {
      return a + item.perc;
    }, 0);
    for (var i = 0; i < options['data'].length; i++) {
      $(this).data("__pieChartSegment" + i, new radialProgress($(this), $.extend(options, options['data'][i], {'lines': options['data'].length, 'line': i })));      
      $(this).data("__pieChartSegment" + i).toPerc({'perc': sum, 'offset': sum - options['data'][i].perc});
      sum -= options['data'][i].perc;
    }
  }
  return this;
};

$.fn.radialMultiProgress = function(func, options) {
  if (func === "init") {
    var space = options['space'] || 2,
        segmentFill = Math.floor(options['fill'] / options['data'].length) - space,
        margin = 0;
    for (var i = 0; i < options['data'].length; i++) {
      $(this).data("__multiProgress" + i, new radialProgress($(this), $.extend(options, options['data'][i], {'fill': segmentFill, 'margin': margin, 'lines': options['data'].length, 'line': i })));
      margin += segmentFill + space;
    }
  }
  else if (options['index'] !== undefined) {
    if ($(this).data("__multiProgress" + options['index'])) {
      if (func === "to") $(this).data("__multiProgress" + options['index']).toPerc(options);
    }
  }
  else if (options['list'] !== undefined) {
    for (var i = 0; i < options['list'].length; i++) {
      if (func === "to") $(this).data("__multiProgress" + options['list'][i]['index']).toPerc(options['list'][i]);
    }
  }
  return this;
};
  
})(jQuery);

jQuery("#example1").radialProgress("init", {
  'size': 100,
  'fill': 5
}).radialProgress("to", {'perc': 100, 'time': 10000}); 

jQuery("#pie").radialPieChart("init", {
  'font-size': 13,
  'fill': 20,
  'data': [
    {'color': "#2DB1E4", 'perc': 33},
    {'color': "#9CCA13", 'perc': 33},
    {'color': "#A4075E", 'perc': 33}
  ]
});

var clock = jQuery("#multi").radialMultiProgress("init", {
  'fill': 25,
  'font-size': 14,
  'data': [
    {'color': "#2DB1E4", 'range': [0, 12]},
    {'color': "#9CCA13", 'range': [0, 59]},
    {'color': "#A4075E", 'range': [0, 59]}
  ]
});

var startClock = function() {
  var dh, dm, ds;
  setInterval(function() {
    var date = new Date(),
        h = date.getHours() % 12,
        m = date.getMinutes(),
        s = date.getSeconds();
    if (dh !== h) { clock.radialMultiProgress("to", {
      "index": 0, 'perc': h, 'time': (h ? 100 : 10)
    }); dh = h; }
    if (dm !== m) { clock.radialMultiProgress("to", {
      "index": 1, 'perc': m, 'time': (m ? 100 : 10)
    }); dm = m; }
    if (ds !== s) { clock.radialMultiProgress("to", {
      "index": 2, 'perc': s, 'time': (s ? 100 : 10)
    }); ds = s; }
  }, 1000);  
};

startClock();

jQuery("#smallrad").radialProgress("init", {
  'size': 20, 
  'fill': 2,
  'text-color': "transparent"
}).radialProgress("to", {'perc': 66});

jQuery("#smallpie").radialPieChart("init", {
  'size': 20,
  'fill': 5,
  'text-color': "transparent",
  'data': [
    {'color': "#2DB1E4", 'perc': 30},
    {'color': "#9CCA13", 'perc': 40},
    {'color': "#A4075E", 'perc': 30}
  ]
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js