JS CSS HTML
const SpaceBetweenSlider = 100;
const displayVariables = (data: { status: string; title: string }[]): void => {
const variablesElement = document.querySelector(".timeline3d__variables");
if (!variablesElement) return;
variablesElement.innerHTML = data
.map(
({ status, title }) => `
<div class="timeline3d__variable">
<span class="">${title}</span>
<span class="">${status}</span>
</div>`,
)
.join("");
};
export const runScript = (): void => {
const container = document.getElementById("3dTimeline") as HTMLElement | null;
if (!container) return;
const raw = container.dataset.slider3d;
const sliderData = raw ? JSON.parse(raw) : null;
if (!sliderData) return;
container.innerHTML = `
<div class="timeline3d">
<div class="timeline3d__category"></div>
<div class="timeline3d__slider"></div>
<div class="scrollbar" id="timeline3d-scrollbar">
<div class="scrollbar__thumb" id="timeline3d-scrollbar-thumb"></div>
</div>
<div class="timeline3d__variables">
</div>
</div>
`;
const track = container.querySelector<HTMLDivElement>(
"#timeline3d-scrollbar",
)!;
const thumb = container.querySelector<HTMLDivElement>(
"#timeline3d-scrollbar-thumb",
)!;
const root = container.querySelector<HTMLDivElement>(".timeline3d")!;
const clamp = (val: number, min: number, max: number) =>
Math.min(Math.max(val, min), max);
let thumbX = 0;
let startX = 0;
let startOffset = 0;
let activeId: number | null = null;
let status = 0;
const sliderWidth = sliderData.length * SpaceBetweenSlider;
let sliderScrollStatus = 0;
const render = (): void => {
root.style.setProperty("--thumb-x", `${thumbX}px`);
const maxOffset = track.clientWidth - thumb.clientWidth;
status = maxOffset ? Number(((thumbX / maxOffset) * 100).toFixed(2)) : 0;
sliderScrollStatus = Number(((sliderWidth / 100) * status).toFixed(1));
displayVariables([
{ status: `${status}%`, title: "status" },
{ status: `${sliderScrollStatus}px`, title: "scroll value" },
]);
};
const onPointerMove = (e: PointerEvent) => {
const dx = e.clientX - startX;
const maxOffset = track.clientWidth - thumb.clientWidth;
thumbX = clamp(startOffset + dx, 0, maxOffset);
render();
};
const onPointerUp = () => {
document.removeEventListener("pointermove", onPointerMove);
document.removeEventListener("pointerup", onPointerUp);
if (activeId !== null) {
thumb.releasePointerCapture(activeId);
activeId = null;
}
};
thumb.addEventListener("pointerdown", (e: PointerEvent) => {
activeId = e.pointerId;
thumb.setPointerCapture(activeId);
startX = e.clientX;
startOffset = thumbX;
document.addEventListener("pointermove", onPointerMove);
document.addEventListener("pointerup", onPointerUp);
});
render();
};
Теперь нужно заменить проценты на растояние самого слайдера, обычно используются пиксели но так как у нас 3д слайдер будем использовать условную величину, предположим у нас между слайдерами растояние в 100 пикселей. Так де добавим данные через data атрибут.