<div class="container">
<span class="label">Wind (m/s) </span>
<div class="progressContainer">
<svg class="progress" viewBox="0 0 400 100">
<path
class="drop"
style="fill:none;stroke:#d0d0d0;stroke-width:8;stroke-linecap:round;"
d="m 20,80 c 0,0 60,-0.001 90,-0.001 30,0 60,0.001 90,0.001 30,0 60,-0.001 90,-0.001 30,0 90,0.001 90,0.001" />
<path
class="range"
style="fill:none;stroke:#3cc124;stroke-width:8;stroke-linecap:round;"
d="m 20,80 c 0,0 60,-0.001 90,-0.001 30,0 60,0.001 90,0.001 30,0 60,-0.001 90,-0.001 30,0 90,0.001 90,0.001" />
</svg>
</div>
</div>
<div class="container">
<span class="label">Current (mA)</span>
<div class="progressContainer">
<svg class="progress" viewBox="0 0 400 100">
<path
class="drop drop2"
style="fill:none;stroke:#d0d0d0;stroke-width:8;stroke-linecap:round;"
d="m 20,80 c 0,0 60,-0.001 90,-0.001 30,0 60,0.001 90,0.001 30,0 60,-0.001 90,-0.001 30,0 90,0.001 90,0.001" />
<path
class="range range2"
style="fill:none;stroke:#6397e4;stroke-width:8;stroke-linecap:round;"
d="m 20,80 c 0,0 60,-0.001 90,-0.001 30,0 60,0.001 90,0.001 30,0 60,-0.001 90,-0.001 30,0 90,0.001 90,0.001" />
</svg>
</div>
</div>
@import url('https://rsms.me/inter/inter-ui.css');
body {
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
margin: 0 30px;
height: 100vh;
font-family: "Inter UI";
font-size: 1.6em;
}
.container {
align-items: center;
display: flex;
justify-content: center;
width: 100%;
}
.label {
min-width: 165px;
}
.progressContainer {
margin-left: 30px;
min-width: 100px;
display: flex;
justify-content: flex-end;
}
.progress {
height: 100px;
min-width: 400px;
transform: translateY(-30px);
transform-origin: 100% 50%;
width: 400px;
}
const array2d = (array) => {
return array.reduce((accumulated, pair, i) => `${accumulated} ${i === 1 ? 'c ' : ''}${pair.join(',')}`
, 'm');
}
const d2Array = (d) => {
const pairs = d.split(' ').filter(v => v.includes(','));
return pairs.map(pair => pair.split(',').map(v => parseFloat(v), 10));
}
const duration = 2000, transformDuration = 600,
progresses = Array.from(document.querySelectorAll('.progress')),
ranges = Array.from(document.querySelectorAll('.range')),
drops = Array.from(document.querySelectorAll('.drop')),
from = d2Array(ranges[0].getAttribute('d'));
toD = "m 340,12.475269 c -20.72434,0 -37.52473,16.800394 -37.52473,37.524731 0,20.724337 16.80039,37.524731 37.52473,37.524731 20.72433,0 37.52473,-16.800394 37.52473,-37.524731 0,-20.724337 -16.8004,-37.524731 -37.52473,-37.524731"
to = d2Array(toD);
let start = null, transformStart = null;
let reverse = false, transformReverse = null;
const animationObjects = [
{ selector: '.range', duration: 2000, reverse: false },
{ selector: '.range2', duration: 1500, reverse: false },
];
animationObjects.forEach((ao) => {
ao.object = document.querySelector(ao.selector);
})
const interpolate = (fromValue, toValue, quota) => {
return fromValue + (toValue - fromValue) * quota;
};
const interpolatePair = (pairFrom, pairTo, quota) => {
return pairTo.map(((toValue, i) => interpolate(pairFrom[i], toValue, quota)))
};
const cubic = (t) => t * t * t;
const animateRange = (obj, quota) => {
const totalLength = drops[0].getTotalLength();
length = quota * totalLength;
obj.style.strokeDasharray = `${length} ${totalLength * 1.1}`
};
const animateTransition = (quota) => {
const current = to.map((pairTo, i) => interpolatePair(from[i], pairTo, quota))
const d = array2d(current)
ranges.forEach((range) => {
range.setAttribute('d', d);
});
drops.forEach((drop) => {
drop.setAttribute('d', d);
});
progresses.forEach((progress) => {
progress.style.transform = `translateY(${(1 - quota) * -30}px) scale(${1 - quota * 0.2})`;
});
}
function step(timestamp) {
// if (!start) start = timestamp;
// const progress = timestamp - start;
// let quota = progress / duration;
// if (reverse) quota = 1 - quota;
// animateRange(quota);
// if (progress < duration) {
// } else {
// animateRange(reverse ? 0 : 1);
// start = timestamp;
// //animateTransition(1);
// reverse = !reverse;
// }
animationObjects.forEach((ao) => {
if (!ao.start) ao.start = timestamp;
const progress = timestamp - ao.start;
let quota = progress / ao.duration;
if (ao.reverse) quota = 1 - quota;
animateRange(ao.object, quota);
if (progress < ao.duration) {
} else {
animateRange(ao.object, ao.reverse ? 0 : 1);
ao.start = timestamp;
ao.reverse = !ao.reverse;
}
});
if (transformStart) {
const transformProgress = timestamp - transformStart;
let transformQuota = transformProgress / transformDuration;
if (transformReverse) transformQuota = 1 - transformQuota;
animateTransition(cubic(transformQuota));
if (transformProgress < transformDuration) {
} else {
animateTransition(transformReverse ? 0 : 1);
transformStart = null;
}
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
let bigScreen = true;
window.addEventListener('resize', () => {
if (window.innerWidth > 767 && !bigScreen) {
transformStart = performance.now();
transformReverse = true;
bigScreen = true;
} else if (window.innerWidth <= 767 && bigScreen) {
transformStart = performance.now();
transformReverse = false;
bigScreen = false;
}
})
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.