-4

I've been trying to build a semi arc progress bar which would start not from 45 degrees and ends to 180 degrees but would be 30 degrees/195 degrees spectrum.

I haven't found anything similar yet as there are lots of examples which are just half circle tho.

Does anyone can point me to the right direction or have an example?

Thanks!

Beppe
  • 189
  • 2
  • 4
  • 14

1 Answers1

1

You can use a conic-gradient together with some CSS variables to get a easy loader effect.

To calculate the angles you can use the formula (percent * (max - min) / 100) + min; Which converts the precentage loaded into the correct angle (degrees) we need.

All possible angle combinations are possible as long as the MIN in JS matches the degrees set in CSS. (and the MAX is higher then the MIN).

If you replace the orange color in CSS with transparent you'll get a seemless loader, though for demo purposes its easier to keep it colored.

const loader = document.querySelector('.progress');

const MIN = 30; // Must match CSS degrees
const MAX = 195;

function updateProgress(percent) {
  const degrees = (percent * (MAX - MIN) / 100) + MIN;
  loader.style.setProperty('--progress', `${degrees}deg`);
  loader.textContent = `${percent}%`;
}

// Something is loading down here ...
let percent = 0;
setInterval(() => {
  percent = (percent + 1) % 100;
  updateProgress(percent);
}, 1000 / 30); // 30 FPS
.progress {
  width: 100px;
  height: 100px;
  background-image: conic-gradient(
    orange 30deg,
    orangered 30deg var(--progress, 0), /* Set via JS */
    orange var(--progress, 0) /* Set via JS */
  );
  border-radius: 50%;
  
  /* center text */
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
}
<div class="progress"></div>

EDIT:

const loader = document.querySelector('.progress');

const MIN = 30;
const MAX = 330;

// Set CSS properties
loader.style.setProperty('--min-degrees', `${MIN}deg`);
loader.style.setProperty('--max-degrees', `${MAX}deg`);

function updateProgress(percent) {
  const degrees = (percent * (MAX - MIN) / 100) + MIN;
  loader.style.setProperty('--progress', `${degrees}deg`);
}

// Something is loading down here ...
let percent = 0;
setInterval(() => {
  percent = (percent + 1) % 100;
  updateProgress(percent);
}, 1000 / 60); // 60 FPS
.progress {
  width: 100px;
  height: 100px;
  /* Lightblue gradient */
  background-image: conic-gradient(
    transparent var(--min-degrees),
    #E8F6FD var(--min-degrees) var(--max-degrees),
    transparent var(--max-degrees)
  );
  border-radius: 50%;
  transform: rotate(180deg); /* Rotate whole element to start from center bottom */
  position: relative;
}

.progress::before {
  content: "";
  width: 100%;
  height: 100%;
  /* Darkblue gradient */
  background-image: conic-gradient(
    transparent var(--min-degrees),
    #00ACEE var(--min-degrees) var(--progress, 0),
    transparent var(--progress, 0)
  );
  border-radius: 50%;
  position: absolute;
  left: 0;
  top: 0;
}

/* White circle on top to make it look like a cutout */
.progress::after {
  content: "";
  width: 75px;
  height: 75px;
  left: 12.5px;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: #FFF;
  border-radius: 50%;
}
<div class="progress"></div>
Reyno
  • 6,119
  • 18
  • 27
  • Thanks a lot for your answer. I'm not sure this is exactly what I'm looking for. I need it to start from the left bottom side (30 degrees) which is the 0 and it to finish at the bottom right side (270 degree circa) which is the 100%. I'm trying to use your code but cannot make it work :/ – Beppe Oct 25 '21 at 13:37
  • @Beppe Yes since you cant show a gradient from those points (as far as i know). But we can rotate the whole element. See my second snippet as example (collapsed by default) – Reyno Oct 25 '21 at 13:50
  • Oh ok, just seen your answer now and trying it on fiddle. I would need something very similar to this graphically https://stackoverflow.com/questions/34826477/arc-progress-bar and that I can drive it dynamically through JS - as in, I get a value between 0 and 100 and I move the bar accordingly. Is it possible with this code of yours? Thanks! – Beppe Oct 25 '21 at 13:52
  • @Beppe Yes this is possible but a bit more complicated since you need multiple gradients. But i've updated the last snippet to show it working. `min` and `max` are also all moved to JS only. To update the progress bar just call `updateProgress` with a percentage – Reyno Oct 25 '21 at 14:13
  • Great, I've tweaked your JS and made it stop dynamically wherever I want. Seems to work. Have a look at this fiddle https://jsfiddle.net/h79zgjas/1/ – Beppe Oct 25 '21 at 14:23