<div class="timeline">
<svg class="timeline__clip">
<defs>
<linearGradient id="gradient" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#f6bbdb" />
<stop offset="100%" stop-color="#e50b80" />
</linearGradient>
<clipPath id="clip">
<rect y="14" width="100%" height="28" rx="14" />
</clipPath>
</defs>
<g class="timeline__back">
<rect class="timeline__bar" y="14" width="100%" height="28" rx="14" />
<circle class="timeline__dot" cx="10%" cy="50%" r="28" />
<circle class="timeline__dot" cx="50%" cy="50%" r="28" />
<circle class="timeline__dot" cx="100%" cy="50%" r="28" transform="translate(-28 0)" />
</g>
<g class="timeline__front" fill="url(#gradient)">
<rect class="timeline__bar" x="-100%" y="14" width="100%" height="28" rx="14" clip-path="url(#clip)"/>
<circle class="timeline__dot" cx="10%" cy="50%" r="28" transform="scale(0)"/>
<circle class="timeline__dot" cx="50%" cy="50%" r="28" transform="scale(0)"/>
<circle class="timeline__dot" cx="100%" cy="50%" r="28" transform="translate(-28 0) scale(0)" />
</g>
</svg>
</div>
<button class="play">play</button>
<input class="seek" type="range" min="0" max="100" value="60">
body {
background: #f9e8ee;
}
.timeline {
position: relative;
height: 56px;
}
.timeline__clip {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.timeline__back {
fill: #fff;
}
.timeline__dot {
transform-origin: 50% 50%;
transform-box: fill-box;
}
import anime from "https://cdn.skypack.dev/animejs@3.2.1";
const barDuradion = 3000;
const dotDuradion = barDuradion * 0.05;
const bar = document.querySelector(".timeline__front .timeline__bar");
const dots = document.querySelectorAll(".timeline__front .timeline__dot");
const play = document.querySelector(".play");
const seek = document.querySelector(".seek");
const timeline = anime.timeline({
easing: "linear",
duration: dotDuradion,
autoplay: false,
update({ progress }) {
seek.value = progress;
}
});
timeline
.add({
targets: bar,
x: "0%",
easing: "linear",
duration: barDuradion
})
.add({
targets: dots[0],
transform: "scale(1)",
}, barDuradion * 0.10)
.add({
targets: dots[1],
transform: "scale(1)",
}, barDuradion * 0.50)
.add({
targets: dots[2],
transform: "translate(-28 0) scale(1)",
}, barDuradion * 1.00);
play.addEventListener("click", () => {
timeline.play();
});
seek.addEventListener("input", ({ target: { value } }) => {
timeline.seek(timeline.duration * (+value / 100));
});
timeline.seek(timeline.duration * 0.60)
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.