In this post I will provides a few examples of creating stylish progress loaders using Javascript for SVG animations.
SVG Animations Using Javascript
SVG
SVGs ( Scalable Vector Graphics ) are vector images built on mathematical formulas to define shapes in an image. The important aspect of these images are that they can be scaled without losing image quality.
I use SVG Path Visualizer when I need to create a custom image using Paths. The webpage has a breakdown for each element with an explanation as well as samples if you are new to SVGs.
To implement these in HTML, use the <svg> tag and specify the viewport size. Inside the <svg> tag, add your SVG elements.
Some predefined elements are:
| circle | draw a circle |
| polygon | draw a polygon shape |
| rect | draw a rectangle |
| line | draw a line |
| polyline | draw a series of jointed lines |
| path | completely customizable shape |
Code
In this example code, there are 4 examples of adding SVGs in an webpage including Javascript for SVG animations. The SVGs all will be used as progress loaders with a progress animation. The last example uses the <path> to create a dynamic image using Javascript.
General Page Setup
To begin with we setup a basic page centering the main div wrapper.
Basically each SVG element is separated in their own div inside the main centered div.
| .center onclick="startAnim()" | start the Javascript function named startAnim() when the user clicks this div which is the main content wrapper. |
Child Divs
| the background SVG | the gray background mirroring the size and dimensions of the progress SVG |
| the progress SVG | this holds the value of the currently set progress for the SVG |
| H1 | displays the progress percent for each SVG progress loader |
NOTE:
The key to making the progress loader work with values 0% to 100% is to set the following two attributes accordingly.
| pathLength | set to 100 |
| stroke-dasharray | set the dash size - ex. 0, 100 is 0% and 22, 100 is 22% |
<!DOCTYPE html>
<html>
<head>
<title>Javascript SVG Animations</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
/* CSS styling here */
</style>
<script>
// Javascript content here
</script>
</head>
<body>
//add the divs here
</body>
</html> <div class="center" onclick="startAnim()">
<div>
<h1 class="displayProgress">0%</h1>
<svg viewbox="0 0 100 100" width="100%" class="circularProgress">
<circle cx="50" cy="50" r="40" stroke="gray" stroke-width="3.5" fill="none"></circle>
<circle class="progressTrack" cx="50" cy="50" r="40" pathLength="100" stroke-dasharray="0, 100" stroke-linecap="round" stroke="green" stroke-width="3" fill="none"></circle>
</svg>
</div>
<div>
<h1 class="displayProgress">0%</h1>
<svg viewbox="0 0 100 100" width="100%"class="circularProgress">
<rect width="50" height="50" x="25" y="25" rx="10" ry="10" stroke="gray" stroke-width="3" fill="none"></rect>
<rect class="progressTrack" width="50" height="50" x="25" y="25" rx="10" ry="10" pathLength="100" stroke-dasharray="0, 100" stroke-linecap="round" stroke="green" stroke-width="3" fill="none"></rect>
</svg>
</div>
<div>
<h1 class="displayProgress">0%</h1>
<svg viewbox="0 0 100 100" width="100%" class="circularProgress">
<polygon points="50,10 90,90 10,90" stroke="gray" stroke-width="3" fill="none" />
<polygon class="progressTrack" points="50,10 90,90 10,90" pathLength="100" stroke-dasharray="0, 100" stroke-linecap="round" stroke="green" stroke-width="3" fill="none" />
</svg>
</div>
<div>
<h1 class="displayProgress">0%</h1>
<svg viewbox="0 0 100 100" width="100%" class="circularProgress">
<path id="animatedTrack" d="M10,50 S25,10 50,50 S75,90 90,50" stroke="gray" stroke-width="3" fill="none" />
<path class="progressTrack" d="M10,50 S25,10 50,50 S75,90 90,50" pathLength="100" stroke-dasharray="0, 100" stroke-linecap="round" stroke="green" stroke-width="3" fill="none" />
</svg>
</div>
</div>CSS
Following the HTML is the page styling and main content div styling.
html {
background-color: #004e5c;
}
body {
color: whitesmoke;
background-color: #004e5c;
display: grid;
width: 100vw;
height: 100vh;
margin: auto;
padding: 0;
}
.center {
margin: auto;
}Child Div Styling
.center div
| display | flex display properties set for layout |
| flex-direction | column so they line in middle one below the next and so on |
| align-items | centering the items |
| justify-content | center div |
| height | 25vh set because there are 4 child divs, wanted them to fit without scroll needed |
.center div {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 25vh;
}Header For Progress Value
.center div h1
| position | absolute so the text can be positioned in center of SVG |
| text-shadow | decorate the text a little |
.center div h1 {
position: absolute;
}
.displayProgress {
text-shadow: 2px 2px 4px black;
}Apply Shadow To SVG
svg *
| filter | add the drop-shadow image filter to SVG images |
svg * {
filter: drop-shadow(0px 0px 0.75px black);
}Animated Path SVG
.progressTrack, #animatedTrack
| transition | animate the attribute changes to the SVGs with the id set to animatedTrack and class name of progressTrack. Animation duration set to 1 sec. |
.progressTrack, #animatedTrack {
filter: drop-shadow(0px 0px 0.75px whitesmoke);
transition: all 1s;
}Javascript
Below is the Javascript used for applying new attributes to the elements, starting/stopping animation and generating random progresses.
| progress | array holding the progress of each example SVG in the webpage |
| isAnimating | switching boolean for starting and stopping the animation |
| startAnim() | function to start/stop animation, updates the isAnimating switching boolean |
| startProgressAnim() | function initiating the animation, contains a 2 sec loop to change until user click on wrapper div again to stop |
| randomColor() | function to create a random color for each of the progress loaders |
| randomProgressValue() | function to generate a random progress value to use in each progress loader. This is also called to change the path values of the last SVG. |
let progress = [0,0,0,0];
var isAnimating = false;
function startAnim(){
isAnimating = !isAnimating;
if(isAnimating){
setTimeout(startProgressAnim, 100);
}
}
function startProgressAnim(){
if(!isAnimating){
return;
}
var elements = document.getElementsByClassName("progressTrack")
var progressHeaders = document.getElementsByClassName("displayProgress");
for(let i = 0; i < progress.length; i++){
progress[i] = randomProgressValue();
elements[i].setAttribute("stroke-dasharray", `${progress[i]}, 100`);
elements[i].setAttribute("stroke", "#" + randomColor());
progressHeaders[i].innerHTML = `${Math.floor(progress[i])}%`;
if(i == progress.length-1){
var c1 = randomProgressValue();
var c2 = randomProgressValue();
elements[i].setAttribute("d", `M10,50 S25,${c1} 50,50 S75,${c2} 90,50`);
document.getElementById("animatedTrack").setAttribute("d", `M10,50 S25,${c1} 50,50 S75,${c2} 90,50`);
}
}
setTimeout(startProgressAnim, 2000);
}
function randomColor(){
return Math.floor(Math.random() * 0xffffff).toString(16);
}
function randomProgressValue(){
return Math.floor(Math.random() * 100);
}Hope this was useful.
