Progress bar approaching two values
Progress bar slowly approaches two estimated values. Use case is a queued job, where the average time of the job and average time spent in queue are both known.
by thirdender
HTML
<script src="//code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<script src="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<progress></progress>
<div></div>
SCSS
body {
margin: 20px;
}
progress {
appearance: none;
position: relative;
border: none;
height: 20px;
width: 100%;
border-radius: 10px;
overflow: hidden;
background: #e4e4e4;
color: lightblue;
&::-webkit-progress-bar {
background-color: #e4e4e4;
}
&::-webkit-progress-value {
transition: width 0.3s ease;
background-color: lightblue;
}
&::-moz-progress-bar {
transition: width 0.3s ease;
background-color: lightblue;
}
}
JavaScript
const bar = document.querySelector('progress');
const output = document.querySelector('div');
// Sigmoid function, constrains a number between 0 and 1
const sig = (x) => 1 / (1 + Math.pow(Math.E, -x));
// Decimal to sigmoid, constrains values of 0 and Infinity to between 0 and 1
const decimalSig = (x) => (sig(x * Math.E) - 0.5) * 2;
const averageQueuedDuration = 1200;
const averageScanDuration = 800;
const queuedAt = new Date();
const startedAt = new Date(+queuedAt + 2400);
const completedAt = new Date(+startedAt + 1600);
const max = averageQueuedDuration + averageScanDuration;
// bar.setAttribute('max', max); // Hi Max!
bar.setAttribute('max', 100);
setInterval(() => {
const now = +(new Date());
const isQueued = true;
const isStarted = now >= startedAt;
const isCompleted = now >= completedAt;
let value;
if (isCompleted) {
value = max;
} else if (isStarted) {
const remaining = (now - startedAt) / averageScanDuration;
value = (decimalSig(remaining) * averageScanDuration) + averageQueuedDuration;
} else {
const remaining = (now - queuedAt) / averageQueuedDuration;
value = decimalSig(remaining) * averageQueuedDuration;
}
bar.setAttribute('value', (value / max) * 100);
}, 100)