oscarviedma

OV Parallax Reveal — Divi JS

Apr 16th, 2026
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.51 KB | None | 0 0
  1. <script>
  2. /* ============================================
  3. OV Parallax Reveal — Divi JS
  4. ============================================ */
  5. (function () {
  6. window.addEventListener('DOMContentLoaded', function () {
  7.  
  8. // Secciones de Divi con clase ov-prl-section
  9. const sections = Array.from(document.querySelectorAll('.ov-prl-section'));
  10. const total = sections.length;
  11. if (total === 0) return;
  12.  
  13. const DURATION = 900; // duración scroll normal (ms)
  14. const DURATION_SEQ = 600; // duración navegación secuencial — dots y anclas (ms)
  15. const PARALLAX = 0.35;
  16. let current = 0;
  17. let animating = false;
  18.  
  19. // Mostrar primera sección
  20. sections[0].classList.add('ov-prl-visible');
  21.  
  22. // --- Inyectar dots ---
  23. const dotsWrap = document.createElement('div');
  24. dotsWrap.id = 'ov-prl-dots';
  25. sections.forEach((_, i) => {
  26. const d = document.createElement('div');
  27. d.className = 'ov-prl-dot' + (i === 0 ? ' ov-prl-active' : '');
  28. d.dataset.goto = i;
  29. dotsWrap.appendChild(d);
  30. });
  31. document.body.appendChild(dotsWrap);
  32. const dots = Array.from(dotsWrap.querySelectorAll('.ov-prl-dot'));
  33.  
  34. // --- Helpers ---
  35. function easeInOut(t) {
  36. return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
  37. }
  38.  
  39. function reset(sec) {
  40. sec.style.transform = 'translateY(0)';
  41. const bg = sec.querySelector('.ov-prl-bg');
  42. if (bg) bg.style.transform = 'translateY(0)';
  43. }
  44.  
  45. function updateDots() {
  46. dots.forEach((d, i) => d.classList.toggle('ov-prl-active', i === current));
  47. }
  48.  
  49. // --- Animación principal (un paso) ---
  50. function goTo(next, duration = DURATION) {
  51. if (animating || next === current || next < 0 || next >= total) return;
  52. animating = true;
  53.  
  54. const prev = current;
  55. const forward = next > prev;
  56. const leaving = sections[prev];
  57. const entering = sections[next];
  58. const leaveBg = leaving.querySelector('.ov-prl-bg');
  59. const enterBg = entering.querySelector('.ov-prl-bg');
  60.  
  61. sections.forEach(s => s.classList.remove('ov-prl-visible'));
  62. leaving.classList.add('ov-prl-visible');
  63. entering.classList.add('ov-prl-visible');
  64.  
  65. if (forward) {
  66. leaving.style.zIndex = 2;
  67. entering.style.zIndex = 1;
  68. leaving.style.transform = 'translateY(0)';
  69. if (leaveBg) leaveBg.style.transform = 'translateY(0)';
  70. entering.style.transform = 'translateY(0)';
  71. if (enterBg) enterBg.style.transform = `translateY(${PARALLAX * 60}%)`;
  72.  
  73. const start = performance.now();
  74. (function tick(now) {
  75. const t = Math.min((now - start) / duration, 1);
  76. const ease = easeInOut(t);
  77. leaving.style.transform = `translateY(${-ease * 100}%)`;
  78. if (leaveBg) leaveBg.style.transform = `translateY(${ease * 100 * PARALLAX}%)`;
  79. if (enterBg) enterBg.style.transform = `translateY(${PARALLAX * 60 * (1 - ease)}%)`;
  80. if (t < 1) { requestAnimationFrame(tick); return; }
  81. leaving.classList.remove('ov-prl-visible');
  82. reset(leaving);
  83. reset(entering);
  84. current = next;
  85. animating = false;
  86. wheelAccum = 0; // resetear acumulador al terminar animación
  87. updateDots();
  88. })(performance.now());
  89.  
  90. } else {
  91. entering.style.zIndex = 2;
  92. leaving.style.zIndex = 1;
  93. entering.style.transform = 'translateY(-100%)';
  94. if (enterBg) enterBg.style.transform = 'translateY(0%)';
  95. leaving.style.transform = 'translateY(0)';
  96. if (leaveBg) leaveBg.style.transform = 'translateY(0)';
  97.  
  98. const start = performance.now();
  99. (function tick(now) {
  100. const t = Math.min((now - start) / duration, 1);
  101. const ease = easeInOut(t);
  102. entering.style.transform = `translateY(${-(1 - ease) * 100}%)`;
  103. if (leaveBg) leaveBg.style.transform = `translateY(${ease * 100 * PARALLAX}%)`;
  104. if (t < 1) { requestAnimationFrame(tick); return; }
  105. leaving.classList.remove('ov-prl-visible');
  106. reset(leaving);
  107. reset(entering);
  108. current = next;
  109. animating = false;
  110. wheelAccum = 0; // resetear acumulador al terminar animación
  111. updateDots();
  112. })(performance.now());
  113. }
  114. }
  115.  
  116. // --- Navegación secuencial (pasa por cada slide intermedio) ---
  117. function goToSequential(target) {
  118. if (target === current) return;
  119. const step = target > current ? 1 : -1;
  120.  
  121. function next() {
  122. const nextIndex = current + step;
  123. goTo(nextIndex, DURATION_SEQ);
  124. if (nextIndex === target) return;
  125. const wait = setInterval(() => {
  126. if (!animating) {
  127. clearInterval(wait);
  128. next();
  129. }
  130. }, 50);
  131. }
  132.  
  133. next();
  134. }
  135.  
  136. // --- Evento wheel con acumulador para trackpad ---
  137. let wheelAccum = 0;
  138. window.addEventListener('wheel', (e) => {
  139. if (animating) return;
  140. wheelAccum += e.deltaY;
  141. if (Math.abs(wheelAccum) < 50) return; // umbral mínimo
  142. const next = wheelAccum > 0 ? current + 1 : current - 1;
  143. wheelAccum = 0;
  144. if (next < 0 || next >= total) return;
  145. goTo(next);
  146. }, { passive: true });
  147.  
  148. // --- Touch ---
  149. let ty = 0;
  150. window.addEventListener('touchstart', (e) => {
  151. ty = e.touches[0].clientY;
  152. }, { passive: true });
  153. window.addEventListener('touchend', (e) => {
  154. const diff = ty - e.changedTouches[0].clientY;
  155. if (Math.abs(diff) > 50) goTo(diff > 0 ? current + 1 : current - 1);
  156. }, { passive: true });
  157.  
  158. // --- Teclado ---
  159. window.addEventListener('keydown', (e) => {
  160. if (e.key === 'ArrowDown' || e.key === 'PageDown') goTo(current + 1);
  161. if (e.key === 'ArrowUp' || e.key === 'PageUp') goTo(current - 1);
  162. });
  163.  
  164. // --- Dots (secuencial) ---
  165. dots.forEach(d => d.addEventListener('click', () => goToSequential(+d.dataset.goto)));
  166.  
  167. // --- Anclas del menú (secuencial) ---
  168. document.querySelectorAll('a[href^="#"]').forEach(link => {
  169. link.addEventListener('click', (e) => {
  170. const id = link.getAttribute('href').slice(1);
  171. const target = document.getElementById(id);
  172. if (!target) return;
  173. const index = sections.indexOf(target);
  174. if (index === -1) return;
  175. e.preventDefault();
  176. goToSequential(index);
  177. });
  178. });
  179.  
  180. });
  181. })();
  182. </script>
Advertisement
Add Comment
Please, Sign In to add comment