Animate Spinning Circle(Percentage) with CSS

Animate spinning circle(percentage) with css

You can read this article and see a working example and even understand how it works css-pie-timer

UPDATE

I didn't like that solution so I tried to implement it my self and with a little help (I asked few questions here) I manage to do it pretty elegant.

The main idea is to understand how to draw a circle sector and then start drawing section with degree = 0 until you reach degree you want.

I also made it reversible, just for fun :).

HTML

<div class="container">
<div id="activeBorder" class="active-border">
<div id="circle" class="circle">
<span class="prec 270" id="prec">0%</span>
</div>
</div>
</div>

The active border will be replaced with the current percentage. The prec span will contains the textual percentage and also the total degrees you want (270) in this example. As I implemented it, the percentage needs to be the second class.

CSS

This is the tricky part. This is the tricky part. I draw the sector this way:

.active-border{
position: relative;
text-align: center;
width: 110px;
height: 110px;
border-radius: 100%;
background-color:#39B4CC;
background-image:
linear-gradient(91deg, transparent 50%, #A2ECFB 50%),
linear-gradient(90deg, #A2ECFB 50%, transparent 50%);
}

Explanation: the first linear-gradient value will be the degrees shown + 90.
If the degrees is bigger than 180 we'll set the first linear-gradient color to our active color.

JQuery

function loopit(dir){
// choose direction
if (dir == "c")
i++
else
i--;
// stop condition
if (i < 0)
i = 0;
if (i > degs)
i = degs;

// calculate and set the percentage text
prec = (100*i)/360;
$(".prec").html(Math.round(prec)+"%");

if (i<=180){
activeBorder.css('background-image','linear-gradient(' + (90+i) + 'deg, transparent 50%, #A2ECFB 50%),linear-gradient(90deg, #A2ECFB 50%, transparent 50%)');
}
else{
activeBorder.css('background-image','linear-gradient(' + (i-90) + 'deg, transparent 50%, #39B4CC 50%),linear-gradient(90deg, #A2ECFB 50%, transparent 50%)');
}

// recursive call
setTimeout(function(){
if($("#circle").is(":hover"))
loopit("c");
else
loopit("nc");
},1);
}

And here's a working demo

Note It works for firefox and chrome. You'll have to add IE support for linear-gradient.

CSS Circle animation to show percentage

Try this:

Html

<span class='Progress'>
<div class="Bar">
<div class="Outer">
<div class="Fill"></div>
</div>
<div class="Draw"></div>
<div class="Status"><span></span></div>
</div>
</span>

CSS

   .Progress {
position: absolute;
left: 25%;
bottom: 30%;
}

.Progress .Bar {
width: 70px;
height: 70px;
border-radius: 50%;
background-color: #E5E5E5;
position: relative;
}

.Progress .Bar .Outer {
content: "";
position: absolute;
border-radius: 50%;
left: calc(50% - 35px);
top: calc(50% - 35px);
width: 70px;
height: 70px;
clip: rect(0, 70px, 70px, 35px);
}

.Bar .Outer .Fill {
content: "";
position: absolute;
border-radius: 50%;
left: calc(50% - 35px);
top: calc(50% - 35px);
width: 70px;
height: 70px;
clip: rect(0, 35px, 70px, 0);
background: #00A0E3;
transform: rotate(60deg);
}

.Progress .Bar .Draw {
content: "";
position: absolute;
border-radius: 50%;
left: calc(50% - 53.84615px/2);
top: calc(50% - 53.84615px/2);
width: 53.84615px;
height: 53.84615px;
background: #fff;
text-align: center;
display: table;
}

.Progress .Bar .Status {
display: table-cell;
vertical-align: middle;
position: absolute;
margin-left: -100px;
margin-top: -10px;
width: 200px;
height: 200px;
left: 50%;
top: 50%;
text-align: center;
}

.Progress .Bar .Status > span {
font-size: 14px;
font-weight: bold;
color: #00A0E3;
}

.Progress .Bar.halfway {
background-color: #00A0E3;
}
.Progress .Bar.halfway .Outer {
clip: rect(0, 35px, 70px, 0);
}
.Progress .Bar.halfway .Outer .Fill {
clip: rect(0, 70px, 70px, 35px);
background: #E5E5E5;
}

.Progress .Bar.complete.halfway,
.Progress .Bar.complete .Fill
{
background-color: #8cd64c !important;
}

Javascript/JQuery:

$('document').ready(function() {

var progress = function(perc) {

perc = Math.round(perc * 100) / 100; // 2 decimal places

var $bar = $('.Progress .Bar'),
$fill = $('.Progress .Bar .Outer .Fill'),
$status = $('.Progress .Bar .Status span');

$bar.removeClass("halfway").removeClass("complete");

// outer bar
if (perc >= 50) $bar.addClass("halfway");
if (perc >= 100) $bar.addClass("complete");

// progress bar
var degrees = 360 * perc / 100;
$fill.css({
"WebkitTransform": 'rotate(' + degrees + 'deg)',
"-moz-transform": 'rotate(' + degrees + 'deg)'
});

// status
$status.html(perc);
}

// Test it!
progress(10);
setTimeout(function() {
progress(50);
setTimeout(function() {
progress(100);
}, 2000);
}, 2000);

});

Show me the CodePen

Percentage animation on the circle

As I've commented you may rotate the svg element transform:rotate(-90deg). Alternatively you may rotate the circle. Also you can use a path instead of a circle and make it start at the top.
If you want to use a path this is how you do it:

In this case the path starts at the top M60,4
Next comes an arc where both radiuses are 56. The first arc ends at 60,116
Follows a second arc A56,56,0 0 1 60,4 and finnaly you close the path z

For the circumference you don't need to know the radius. You can do var circumference = circle.getTotalLength(); where getTotalLength is a method that is returning the total length of a path.

var circle = document.querySelector('path');

var circumference = circle.getTotalLength();

circle.style.strokeDasharray = circumference;

circle.style.strokeDashoffset = circumference;

function setProgress(percent) {

var offset = circumference - percent / 100 * circumference;

circle.style.strokeDashoffset = offset;

}

setProgress(60);
<svg class="progress-ring" width="120" height="120">

<path fill="none" class="progress-ring__circle" stroke="black" stroke-linecap="round" stroke-width="8" d="M60,4A56,56,0 0 1 60,116A56,56,0 0 1 60,4z" />

</svg>

Animating a circle filling from bottom to top by a dynamic percentage

I'd recommend placing a second div inside of the circle and animating the height of that, which can be transitioned with CSS. It's tough to tell exactly where to put it without seeing the CSS and how it appears, but I'd imagine it could look something like this:

render() {
let gradient = background: `linear-gradient(transparent , ${this.props.color} 100%)`;

return (
<div className="circle-container">
<div className="circle" onClick={this.props.onClick}>
<div className="circle-fill" style={{ background: gradient, height: this.props.percent + '%'}}
<div className="circle-info">
<p className="circle-text">{this.props.percent}%</p>
<p className="circle-text-hidden">CU Avg: {this.props.industryPercent}%</p>
{strike}
</div>
</div>
<h1>{this.props.segmentName}</h1>

</div>
)

You would need other CSS to make this work. I'd recommend making circle position: relative and the circle-fill position: absolute with a width of 100%. You may need to do more adjustments to the z-index to display your content properly at the same time as well.

SCSS stop keyframe SVG circle animation based on percentage

The total length of a path in SVG can be found using the getTotalLength method. In your case you could also use the formula for the perimeter of a circle (2*Math.PI*r).

Anyway you need to know the length of the path you want to animate which in this case is 445.

stroke-dasharray: 445;
stroke-dashoffset: 445;

If you want to stop the animation at 50% this means you have to stop it at 445 / 2 = 222.5

 @keyframes stroke {
to {
stroke-dashoffset: 222.5;
}
}

Next come the demo. I hope it helps.

svg {

border: 1px solid;

}

.circle--static circle {

stroke-dasharray: 4;

animation: stroke 2s ease-out forwards;

}

.circle--animated {

top: 0;

left: 0;

/*position: absolute;*/

}

.circle--animated circle {

stroke-dasharray: 445;

stroke-dashoffset: 445;

animation: stroke 6s ease-out forwards;

animation-iteration-count: infinite;

}

@keyframes stroke {

to {

stroke-dashoffset: 222.5;

}

}

@keyframes fadeIn {

to {

opacity: 1;

}

}
<svg height="180" width="180" class="circle--static">

<circle cx="100" cy="100" r="71" stroke="#cde9db" stroke-width="6" fill-opacity="0" />

</svg>

<svg height="180" width="180" class="circle--animated">

<circle id="kk" cx="100" cy="100" r="71" stroke="#68c087" stroke-width="10" fill-opacity="0" />

</svg>

Resizing SVG Circle Radius Using CSS Animation

In SVG 1.1 the radius of a circle was an attribute and not a CSS property. SVG 2 changes this and instead makes the circle's radius a CSS property that's mapped to an attribute.

CSS animations animate CSS properties and do not animate attributes.

Firefox has now implemented this part of the SVG 2 specification so the testcase in the question will work now although it didn't when the question was written.

SMIL animations will work on attributes (and CSS properties).

<html>
<head>
<link href = "styling.css" rel = "stylesheet" type = "text/css"></link>
</head>
<body>
<svg class = "button" expanded = "true" height = "100px" width = "100px">
<circle cx = "50%" cy = "50%" r = "35%" stroke = "#000000" stroke-width = "10%" fill = "none"/>
<circle class = "innerCircle" cx = "50%" cy = "50%" r = "25%" fill = "#000000">
<animate attributeName="r" begin="0s" dur="1s" repeatCount="indefinite" from="5%" to="25%"/>
</circle>
</svg>
</body>
</html>


Related Topics



Leave a reply



Submit