Great things are on the horizon
Something big is brewing! Our store is in the works and will be launching soon!
/** * Circular Process Slider v2 — cps-script.js * Arrow slides smoothly ALONG the ring path (continuous motion). */ (function () { 'use strict'; var SVG_CX = 250, SVG_CY = 250, SVG_R = 210; function deg2rad(d) { return d * Math.PI / 180; } function ringPoint(angleDeg) { var rad = deg2rad(angleDeg - 90); return { x: SVG_CX + SVG_R * Math.cos(rad), y: SVG_CY + SVG_R * Math.sin(rad) }; } document.addEventListener('DOMContentLoaded', function () { document.querySelectorAll('.cps-section').forEach(initInstance); }); function initInstance(section) { var total = parseInt(section.dataset.total, 10) || 6; var speed = parseInt(section.dataset.speed, 10) || 3000; var START = 60; var GAP = 360 / total; var angles = []; for (var i = 0; i < total; i++) angles.push(START + i * GAP); var current = 0; var arrowDeg = angles[0]; var targetDeg = angles[0]; var animId = null; var autoTimer = null; var paused = false; var lastTs = null; var ROT_SPEED = 180; var svg = section.querySelector('.cps-ring-svg'); var arrowG = section.querySelector('.cps-arrow-group'); var dotsGroup = section.querySelector('.cps-dots-group'); angles.forEach(function (deg, i) { var p = ringPoint(deg); var dot = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); dot.setAttribute('cx', p.x); dot.setAttribute('cy', p.y); dot.setAttribute('r', 5.5); dot.setAttribute('class', 'cps-dot-marker' + (i === 0 ? ' active' : '')); dot.dataset.step = i; dotsGroup.appendChild(dot); }); var arena = section.querySelector('.cps-arena'); var labels = section.querySelectorAll('.cps-label'); function positionLabels() { var W = arena.offsetWidth; var H = arena.offsetHeight; var lR = W * 0.63; labels.forEach(function (lbl, i) { var rad = deg2rad(angles[i] - 90); lbl.style.left = (W / 2 + lR * Math.cos(rad)) + 'px'; lbl.style.top = (H / 2 + lR * Math.sin(rad)) + 'px'; }); } positionLabels(); window.addEventListener('resize', positionLabels); function drawArrow(deg) { var p = ringPoint(deg); var rot = deg; arrowG.setAttribute('transform', 'translate(' + p.x + ',' + p.y + ') rotate(' + rot + ')'); } drawArrow(arrowDeg); function animArrow(ts) { if (!lastTs) lastTs = ts; var dt = ts - lastTs; lastTs = ts; var diff = targetDeg - arrowDeg; while (diff > 180) diff -= 360; while (diff < -180) diff += 360; if (Math.abs(diff) < 0.25) { arrowDeg = targetDeg; drawArrow(arrowDeg); animId = null; lastTs = null; return; } var step = ROT_SPEED * (dt / 1000); arrowDeg += (diff > 0 ? 1 : -1) * Math.min(step, Math.abs(diff)); drawArrow(arrowDeg); animId = requestAnimationFrame(animArrow); } function rotateTo(deg) { var cur = ((arrowDeg % 360) + 360) % 360; var tgt = ((deg % 360) + 360) % 360; if (tgt <= cur) tgt += 360; targetDeg = arrowDeg + (tgt - cur); if (animId) { cancelAnimationFrame(animId); animId = null; } lastTs = null; animId = requestAnimationFrame(animArrow); } function activateStep(idx) { current = ((idx % total) + total) % total; section.querySelectorAll('.cps-step-img').forEach(function (img) { img.classList.toggle('cps-img-active', +img.dataset.step === current); }); labels.forEach(function (lbl) { lbl.classList.toggle('cps-label-active', +lbl.dataset.step === current); }); dotsGroup.querySelectorAll('.cps-dot-marker').forEach(function (d) { d.classList.toggle('active', +d.dataset.step === current); }); section.querySelectorAll('.cps-minfo-item').forEach(function (item) { item.classList.toggle('cps-minfo-active', +item.dataset.step === current); }); rotateTo(angles[current]); } function startAuto() { if (autoTimer) return; autoTimer = setInterval(function () { if (!paused) activateStep(current + 1); }, speed); } function stopAuto() { if (autoTimer) { clearInterval(autoTimer); autoTimer = null; } } section.addEventListener('mouseenter', function () { paused = true; }); section.addEventListener('mouseleave', function () { paused = false; }); section.addEventListener('focusin', function () { paused = true; }); section.addEventListener('focusout', function () { paused = false; }); labels.forEach(function (lbl) { lbl.addEventListener('click', function () { stopAuto(); activateStep(+lbl.dataset.step); startAuto(); }); lbl.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); lbl.click(); } }); }); var btnPrev = section.querySelector('.cps-btn-prev'); var btnNext = section.querySelector('.cps-btn-next'); if (btnPrev) btnPrev.addEventListener('click', function () { stopAuto(); activateStep(current - 1); startAuto(); }); if (btnNext) btnNext.addEventListener('click', function () { stopAuto(); activateStep(current + 1); startAuto(); }); if ('IntersectionObserver' in window) { new IntersectionObserver(function (entries) { entries.forEach(function (e) { e.isIntersecting ? startAuto() : stopAuto(); }); }, { threshold: 0.2 }).observe(section); } else { startAuto(); } } })();
Something big is brewing! Our store is in the works and will be launching soon!