So, Bootstrap 5 has some fancy Multiple progress bars.
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: 15%" aria-valuenow="15" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar bg-success" role="progressbar" style="width: 30%" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 20%" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
It looks pretty good but I'm having the biggest headache trying to countdown with it.
Unless I'm missing the ability to adjust the whole thing with a single width value, my problem is that you need to start with the bottom bar, reduce that width, then move on to the middle bar, reduce that till zero, and so on.
This makes things quite complex, I'm not even sure I want to show my code here as my head is spinning. OK here it is:
// Select children of multi step bar
var nodes = document.getElementById('progress-divided').children;
// Loop through those children in reverse
for (var i = nodes.length - 1; i >= 0; i--) {
// Go to next step in loop if width is zero
let percentageTime = nodes[i].ariaValueNow;
if ( percentageProgress < ( 100 - percentageTime ) ) {
nodes[i].style.width = 0 + "%"
console.log("Moving to next step!")
return
}
// grab the percentage of the total
// work out the balance - ie 25% for a 75% addition
let percentageBalance = 100 - percentageTime
// remove that figure from the total to get an accurate countdown
let secondsStepRemain = (diff - ( ( percentageBalance / 100 ) * secondsBoil ))
// remove the time from the grain total to get the reduced fixed total
let secondsStepTotal = ( percentageTime / 100 ) * secondsBoil
// work out the percentage of this total - so 100 counting down
let percentageStep = ( secondsStepRemain / secondsStepTotal ) * 100
// work out as a factor of the total
let percentage = ( percentageStep / 100 ) * percentageTime
// adjust the width
nodes[i].style.width = percentage + "%";
// we only do this on one bar - so break if this is fulfilled
break;
}
This actually does count down to the first step, but then gets confused (I think as it's breaking out of the loop when it shouldn't be).
Anybody have a more simple/elegant solution to this problem?
Phew this was a whopper. Wish that Bootstrap would have some built in functions to get this working as it took a good while. I had some help building the map function so can't claim all the credit!
The answer to this was to grab the percentages of the bars as an array, say in the answer above: [15, 30, 20, 35], mine always start at 100%, then process them, then apply them back to the DOM element.
// the total elapsed percentage
let percentageElapsed = 75
// the array I'm using to calculate the progress bar
let percentages = [15, 30, 20, 35]
// Process the array - remove from the first element
// then the second, until the total is finished
percentages = percentages.map((d) => {
let _x = percentageElapsed - d;
let sum = _x >= 0 ? 0 : -_x;
percentageElapsed = _x > 0 ? _x : 0;
return sum;
});
// I had to reverse this here to get it to work properly
percentages = percentages.reverse()
// Grab the DOM elements I want to work on
// the `progress-divided` element is the parent element
var nodes = document.getElementById('progress-divided').children;
// Apply this back to the DOM
for (let i = 0; i < nodes.length; ++i) {
nodes[i].style.width = percentages[i] + "%"
}