Round progress indicator with directional pointer

I've been working on creating a round progress bar that features an arrow at the front.

This is my current progress:

HTML Code:

<!-- Container -->
<ul class="progress">
    <!-- Item -->
    <li data-name="Item 1" data-percent="Item 1">
        <svg viewBox="-10 -10 220 220">
        <g fill="none" stroke-width="2" transform="translate(100,100)">
        <path d="M 0,-100 A 100,100 0 0,1 86.6,-50" stroke="url(#cl1)"/>
        <path d="M 86.6,-50 A 100,100 0 0,1 86.6,50" stroke="url(#cl2)"/>
        <path d="M 86.6,50 A 100,100 0 0,1 0,100" stroke="url(#cl3)"/>
        <path d="M 0,100 A 100,100 0 0,1 -86.6,50" stroke="url(#cl4)"/>
        <path d="M -86.6,50 A 100,100 0 0,1 -86.6,-50" stroke="url(#cl5)"/>
        <path d="M -86.6,-50 A 100,100 0 0,1 0,-100" stroke="url(#cl6)"/>
        </g>
        </svg>
        <svg viewBox="-10 -10 220 220">
        <path d="M200,100 C200,44.771525 155.228475,0 100,0 C44.771525,0 0,44.771525 0,100 C0,155.228475 44.771525,200 100,200 C155.228475" stroke-dashoffset="590"></path>
        </svg>
    </li>
</ul>
<!-- Defining Angle Gradient Colors -->
<svg width="0" height="0">
<defs>
<linearGradient id="cl1" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
    <stop stop-color="#18FFA9"/>
    <stop offset="100%" stop-color="#18FFA9"/>
</linearGradient>
<linearGradient id="cl2" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1">
    <stop stop-color="#18FFA9"/>
    <stop offset="100%" stop-color="#4FC0EB"/>
</linearGradient>
<linearGradient id="cl3" gradientUnits="objectBoundingBox" x1="1" y1="0" x2="0" y2="1">
    <stop stop-color="#4FC0EB"/>
    <stop offset="100%" stop-color="#FD8AE6"/>
</linearGradient>

[currently pasted only part of svg colors gradient]
    
</defs>
</svg>

CSS Styles:

html,
body {
  background-color: black;
  color: white;
}

@keyframes load {
  0% {
    stroke-dashoffset: 0;
  }
}
.progress {
  position: relative;
  display: inline-block;
  padding: 0;
  text-align: center;
}
.progress > li {
  display: inline-block;
  position: relative;
  text-align: center;
  font-size: 28px;
  line-height: 34px;
}
.progress > li:after {
    content: attr(data-percent);
    position: absolute;
    top: 40%;
    left: 20%;
    font-size: 28px;
    text-align: center;
    margin: auto;
    width: 193px;
    vertical-align: middle;
    display: block;
    text-transform: uppercase;
}
.progress svg {
  width: 409px;
  height: 409px;
}
.progress svg:nth-child(2) {
  position: absolute;
  left: 0;
  top: 0;
  transform: rotate(-90deg);
}
.progress svg:nth-child(2) path {
  fill: none;
  stroke-width: 25;
  stroke-dasharray: 629;
  stroke: black;
  opacity: 0.9;
  animation: load 1s;
}

https://jsfiddle.net/qr7cs40t/1

I came across this code and made some style edits to it.

I'm finding it challenging to work with SVG as I lack experience in it. I tried following tutorials to add the arrow using SVG but faced difficulties.

Currently, there are two main challenges:

  • To incorporate an arrow at the front of the progress circular wheel so that it moves along with the progress.
  • To change the direction from clockwise to also counterclockwise. I aim to have two clockwise and one counterclockwise progress bars on my page.

The arrow should resemble this icon: https://fontawesome.com/icons/arrow-from-bottom?style=light, matching the width of the circular progress bar.

Here's a visual example of the desired outcome:
https://i.sstatic.net/qkdbu.png

Answer №1

If you want to achieve your desired outcome, you'll need to take a different approach than the one presented in this code snippet.

When the animation begins, a visible colored arc is mostly obscured by a thick black stroked arc drawn on top of it. This stroked arc has a stroke-dasharray that is animated to gradually slide along the curve, revealing the colored arc beneath. Since the reveal is accomplished through the movement of a dasharray, traditional methods of adjusting marker position won't work (such as using CSS).

To accomplish this effect, you will need to refactor the SVG and perform the animation using JavaScript or SMIL.

Answer №2

My approach to solving this was to customize existing code to suit my specific requirements.

For a direct link, you can visit: https://codepen.io/lucky8919/pen/JjWXBYX

HTML

  <div class="progress multicolor">
    <span class="arrow"></span>
    <span class="progress-left">
      <span class="progress-bar"></span>
    </span>
    <span class="progress-right">
      <span class="progress-bar"></span>
    </span>
    <div class="progress-value">90%</div>
  </div>

CSS

html,
body {
  background-color: black;
}


* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.progress {
  width: 390px;
  height: 390px;
  line-height: 390px;
  background: none;
  margin: 0;
  box-shadow: none;
  position: relative;
}

.progress:after {
  content: "";
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 12px solid #000;
  position: absolute;
  top: 0;
  left: 0;
}

.progress > span:not(.arrow) {
  width: 50%;
  height: 100%;
  overflow: hidden;
  position: absolute;
  top: 0;
  z-index: 1;
}

.progress > span.arrow {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9;
    animation: rotate 2.7s linear forwards;
}

.progress > span.arrow:after {
    content: "";
    border-width: 8px;
    border-style: solid;
    border-color: transparent transparent transparent red;
    position: absolute;
    left: 198px;
    top: -5px;
}

.progress .progress-left {
  left: 1px;
}

.progress .progress-bar {
  width: 100%;
  height: 100%;
  background: none;
  border-width: 2px;
  border-style: solid;
  position: absolute;
  top: 0;
}

.progress .progress-left .progress-bar {
  left: 100%;
  border-top-right-radius: 320px;
  border-bottom-right-radius: 320px;
  border-left: 0;
  -webkit-transform-origin: center left;
  transform-origin: center left;
}

.progress .progress-right {
  right: 1px;
}

.progress .progress-right .progress-bar {
  left: -100%;
  border-top-left-radius: 320px;
  border-bottom-left-radius: 320px;
  border-right: 0;
  -webkit-transform-origin: center right;
  transform-origin: center right;
  animation: loading-1 1.5s linear forwards;
}

.progress .progress-value {
    position: absolute;
    line-height: 390px;
    width: 98%;
    height: 98%;
    border-radius: 50%;
    top: 4px;
    left: 4px;
    z-index: 5;
    background-color: #000;
    font-family: inherit;
    font-size: 28px;
    text-transform: uppercase;
    text-align: center;
    color: white;
}

.progress.multicolor .progress-bar {
  width: 100%;
  height: 100%;
  border: solid 2px transparent;
  background-origin: border-box;
  background-clip: content-box, border-box;
}

.progress.multicolor .progress-left .progress-bar {
  background-image: linear-gradient(95.14deg, red 75%, blue 85%, green 100%);
}

.progress.multicolor .progress-right .progress-bar {
  background-image: linear-gradient(95.14deg, green 0%, blue 25%, red 50%);
}

.progress.multicolor .progress-left .progress-bar {
  animation: loading-2 1.2s linear forwards 1.5s;
}

@keyframes rotate {
    from {transform:rotate(0deg)}
    to {transform:rotate(324deg)}
}

@keyframes loading-1 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
}

@keyframes loading-2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(144deg);
    transform: rotate(144deg);
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am having trouble getting my textarea to accept width attributes

Strangely, the text area on my website just won't cooperate with the width I specify. I've double-checked the CSS multiple times to no avail! Take a look at this jsfiddle example that demonstrates what I'm trying to achieve. However, on my ...

Loading custom components dynamically in Angular with SVG: a how-to guide

Looking for a way to dynamically load SVG items with ease. The items needed are quite simple. Here's a basic template: <svg:rect [attr.x]="x" [attr.y]="y" width="10" height="10" /> Component Class Example: export class DraggableSvgItemCompon ...

Using jQuery to insert HTML content into a div element by replacing a specific string

I am faced with a situation where I have <div class="test">hello everyone</div> and the challenge is to replace each instance of "hello" within this div with <h1>helllo</h1> In my attempt, I used $(this).text().replace("hello" ...

CSS border alignment techniques

I am attempting to achieve the effect of having an orange border on top of a blue border, with only the orange border moving. I have noticed this design feature on various websites but have been unable to replicate it without removing the padding of the pa ...

Assign the input text field's value programmatically in the code-behind of a C# Asp.net application

I am attempting to change the value of an HTML input field from C# code behind. These inputs are created through a JavaScript loop, so I have not had much success using run at server or assigning values through <%= %>. Below is my script: var mytab ...

"Implementing unique typefaces on a static website hosted on AWS

I've been attempting to incorporate a unique font into my CSS class using font-face. I have experimented with both .otf and .ttf file formats, uploading the custom font files to an S3 bucket. I made sure to grant public permissions to the font files a ...

Vue JS nested component does not appear in the document object model

I developed two separate VueJS components - one displaying a modal and the other featuring HTML input fields. When I attempt to nest these two components, the inner component fails to appear in the DOM. What could be causing this issue? Here's a snip ...

Struggling to extract the values from a KendoDropDown using Selenium

When using the selenium web driver, we are trying to retrieve a set of option values such as Last 30 days, Last 60 days, etc. Attempts have been made to locate these elements using a CSS selector. var timeperiodcss = "span.k-widget.k-dropdown.k-header se ...

Create a speech bubble using only CSS, featuring a partially see-through background and a stylish border

I wish to design a speech bubble using only CSS. There are specific requirements I need to meet: It should adjust its size based on content with some padding or a set size. The background color must be semi-transparent. You must be able to define a borde ...

Tips for displaying multiple XML datasets on an HTML webpage

I came across an example on W3schools that I'm trying to replicate: http://www.w3schools.com/xml/tryit.asp?filename=tryxml_app_first However, the example only displays one CD. My goal is to showcase all the data (in this case CDs) in the XML file. H ...

How many hyperlinks are there on this webpage?

Is there a way to determine the number of links on a web page without counting social media networks like Google, LinkedIn, Facebook, and Twitter? ...

How can I align text to the center and set the text color at the same

Looking to place text in the center of a colored box? Although attempting to center the text, you may find that it remains towards the top rather than in the middle of the box. How can you shift the text down so it aligns with the middle of the backgroun ...

Include brand logo to the Bootstrap navigation bar

Following the method provided in Bootstrap documentation, I included the following code: <div class="container"> <a class="navbar-brand" href="#"> <img src="/img/hangers.jpg" alt= ...

Changing the text color of Material UI Accordion Summary upon expansion

How can I update the color of an Accordion summary text in Material UI when it is expanded? <Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')} className={classes.root}> <AccordionSummary ...

`What purpose does the data-view attribute serve in Durandal JS?`

While experimenting with the Durandal JS starter kit application, I happened to view the page source in Mozilla browser and noticed the following. <div class="" data-view="views/shell" style="" data-active-view="true"> </div> I couldn't ...

The website functions properly with Live Server, but encounters issues when launched from the Files directory

After testing multiple browsers, the site consistently works fine with Live Server. However, when accessed through Firefox or Chrome, my style.css fails to load completely. On Edge, an error message indicates that the file is missing. Below are snippets of ...

Adjusting the background color of <tr> depending on the number of <tr> elements in the HTML using CSS

When working on my HTML page, I have utilized multiple <tr> tags with different bgcolor values such as: <tr bgcolor="#000000"> <tr bgcolor="#E5F1CC"> <tr bgcolor="#D30A0A"> <tr bgcolor="#656766"> I am aiming to assign unique ...

Using jQuery, how can I add value to every input when the option is changed?

I need help changing the values of all input:text elements based on selections from a select menu. Specifically, I want to change only the matched td.class values from the data-pset attribute inside the <select>. As a beginner in jQuery, I can only ...

How to modify the styling of an input element in React without directly manipulating the input itself

I have collected responses from a survey I created and now I want to showcase the results. The responses are rated on a scale from 1 to 5, and I would like to display them similar to the screenshot. Each number should be presented within a square, with ...

Arrange and display similar objects together

I have a list of items in a listView that need to be visually grouped based on their class, displayed within boxes. For example, I have 5 items with the following classes: <div class="1"></div> <div class="1"></div> <div class= ...