You can achieve this using "automated" SVG circle, automated because you don't need to hard code values like width, height, radius or viewBox dimensions, all it needs that the corresponding img
tag has width
and height
attributes, also stroke-width
attribute for the svg circle
.
All further calculations depend on values of these attributes, like positioning both the image and the circle, setting width and height for the svg, also the values of radius and circumference of the circle. also if you have more than one circle in your page, circles don't need to have same width and size, each circle will take dimensions from the corresponding img
.
All magic is in this line:
'stroke-dasharray': SVG.circum * ratio / 100 + ' ' + SVG.circum
Where circum
is the length of the circle circumference, the concept behind this is controlling the values of stroke-dasharray
(1) with our script. for example, suppose you call the function providing value of 70
, and let's say the circum
is 500
, so it'll be:
stroke-dasharray: 350 500
think of it like the second value "500
" is the full circle, the first value "350
" is where the stroke stops.
To set values of a certain circle, just call the miProgressbar()
function, passing the circle element and the needed value, like this:
miProgressbar($('#circle1'), 70);
Updated: All examples below tested with Chrome, Firefox, IE9-IE11 and Vivaldi browsers, and worked in all even in IE9+, except that in IE9-IE11 example5 and example6 only the first circles have strokes, not sure about modern versions of Safari, Opera and Edge.
Example 1: CodePen - full circle [ ratio = 100%
]
var svgCircles = $('.wrapper svg circle');
miProgressbar($('#circle1'), 70);
// from here on, everything works automatically, you don't need to change anything
svgCircles.each(function() {
var $this = $(this),
$parent = $this.parent(),
SVG = miSVGdata($this);
$this.attr('r', SVG.radius);
$parent.css({
'top': SVG.strokeWidth / 2,
'left': SVG.strokeWidth / 2
});
$parent.attr('viewBox', '0 0 ' + SVG.svgWidth + ' ' + SVG.svgHeight);
$parent.attr('width', SVG.svgWidth);
$parent.attr('height', SVG.svgHeight);
});
function miProgressbar(element, ratio) {
var SVG = miSVGdata(element);
element.css({
'stroke-dasharray': SVG.circum * ratio / 100 + ' ' + SVG.circum
});
}
function miSVGdata(element) {
var svgParent = element.parent(),
strokeWidth = parseInt(element.attr('stroke-width'), 10),
img = element.parents('.wrapper').find('img'),
svgWidth = parseInt(img.attr('width'), 10) + strokeWidth,
svgHeight = parseInt(img.attr('height'), 10) + strokeWidth,
circum, radius, svgObj;
img.css({
top: strokeWidth,
left: strokeWidth
});
radius = svgWidth / 2 - strokeWidth / 2;
circum = parseInt(2 * radius * 3.14, 10);
svgObj = {
svgWidth: svgWidth,
svgHeight: svgHeight,
parent: svgParent,
strokeWidth: strokeWidth,
radius: radius,
circum: circum
};
return svgObj;
}
HTML:
The structure of the wrapper div will look like this, remember that ALL automated calculations are based on the width
and height
attribute of each image so they must be provided for these images.
<div class="wrapper">
<img src="holder.js/150x150" width="150" height="150" class="img-circle img-thumbnail" />
<svg class="mi-progressbar">
<circle id="circle1" r="25%" cx="50%" cy="50%" stroke-width="20"></circle>
</svg>
</div>
Keep in mind that you can even inject the SVG code via javascript using .insertAfter()
and this way your hardcoded wrapper would have the img
only.
Example 2: CodePen - coloring
Example with multiple images and different styles with same colors as the bootstrap progress bar and same naming style, like this:
svg circle.progress-bar-success{ stroke:#5cb85c; }
Example 3: CodePen with different values set when calling the function like this:
miProgressbar($('#circle1'), 0);
miProgressbar($('#circle2'), 100);
miProgressbar($('#circle3'), 65);
miProgressbar($('#circle4'), 40);
miProgressbar($('#circle5'), 15);
Example 4: CodePen - animating
You can animate the circular progress bar by passing different -i.e increasing - ratio values to the miProgressbar(element, ratio)
function. the code snippet for the above animation:
var i = 0;
setInterval(function() {
if(i <= 100){
miProgressbar(svgCircles, i);
i++;
}
}, 50);
Example 5: CodePen - different image sizes the svg circle will adapt it automatically by just changing values of width
and height
attributes of the img
.
* didn't work as supposed in IE9 - IE11, only first circle
Example 6: CodePen - value of stroke-width
controls width of the border
* didn't work as supposed in IE9 - IE11, only first circle
--------------------------------------------
(1) - sources: