Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Have bootstraps progress bar converted to circle and image inside it

I am trying to be able to use the bootstrap progress bar so that it can wrap around my image in a circle around the edge.

Like in the code below on html I still would prefer to set the width in the div the way bootstrap does.

Question: How am I able to use bootstrap progress bar to be wrapped around my image where would still be able to set progress bar with in div?

Here what I have tried so far. Snippet Example Codepen

CSS

.progress {
    border-radius: 50%;
} 
.progress-bar {
    border-radius: 50%;
}
.wrapper > img {
    position: absolute;
    top: 0;
    left: 0;
    text-align: center;
}

HTML

<div class="container">
    <div class="row">
        <div class="page-header">Circle progress bar with image</div>
    </div>
    <div class="row">
        <div class="col-lg-3 col-md-3 col-sm-3">

            <div class="wrapper">

                <img src="holder.js/150x150" class="img-circle img-thumbnail" />  

                <div class="progress" style="height: 150px; width: 150px;">  
                    <div class="progress-bar" style="width: 50%"></div>  
                </div>  

            </div> 

        </div>
    </div>
</div>  
like image 986
Mr. ED Avatar asked Aug 06 '16 01:08

Mr. ED


People also ask

What are the different types of progress bars?

There are 2 types of progress bars: determinate and indeterminate. The former is used when the amount of information that needs to be loaded is detectable. The latter is used when the system is unsure how much needs to be loaded or how long it will take.


1 Answers

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:

  • https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
  • https://css-tricks.com/almanac/properties/s/stroke-dasharray/
  • Lea Verou - The Missing Slice 35:50-42:10
like image 118
Mi-Creativity Avatar answered Oct 11 '22 15:10

Mi-Creativity