/* HEATLIFT GLOBAL SCRIPTS — HTHP cycle animation */
(function () {
'use strict';
const SELECTOR = '[data-hl-cycle]';
const initialized = new WeakSet();
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
const ORIGINAL_WIDTH = 3095;
const ORIGINAL_HEIGHT = 1055;
const ORIGINAL_POINTS = [
{ x: 727, y: 989 },
{ x: 1149, y: 989 },
{ x: 1149, y: 579 },
{ x: 1973, y: 579 },
{ x: 1973, y: 101 },
{ x: 1588, y: 101 },
{ x: 1588, y: 322 },
{ x: 727, y: 322 },
{ x: 727, y: 989 }
];
const segments = [];
let totalLength = 0;
for (let index = 0; index < ORIGINAL_POINTS.length - 1; index += 1) {
const start = ORIGINAL_POINTS[index];
const end = ORIGINAL_POINTS[index + 1];
const length = Math.hypot(end.x - start.x, end.y - start.y);
totalLength += length;
segments.push({ start, end, length, endDistance: totalLength });
}
function createTrail(container, xPercent, yPercent) {
const trail = document.createElement('span');
trail.className = 'hl-hthp-cycle__trail';
trail.style.left = xPercent + '%';
trail.style.top = yPercent + '%';
container.appendChild(trail);
window.setTimeout(function () {
trail.style.opacity = '0';
window.setTimeout(function () { trail.remove(); }, 520);
}, 420);
}
function initializeCycle(container) {
if (!container || initialized.has(container) || reducedMotion.matches) return;
const image = container.querySelector('.hl-hthp-cycle__image');
if (!image) return;
initialized.add(container);
container.querySelectorAll('.hl-hthp-cycle__moving-point, .hl-hthp-cycle__trail').forEach(function (node) {
node.remove();
});
const point = document.createElement('span');
point.className = 'hl-hthp-cycle__moving-point';
point.setAttribute('aria-hidden', 'true');
container.appendChild(point);
let distance = 0;
let previousTime = 0;
let previousTrailTime = 0;
const speed = 190; // Original-image pixels per second.
function render(timestamp) {
if (!container.isConnected || reducedMotion.matches) {
point.remove();
initialized.delete(container);
return;
}
if (document.hidden) {
previousTime = timestamp;
window.requestAnimationFrame(render);
return;
}
if (!previousTime) previousTime = timestamp;
const deltaSeconds = Math.min((timestamp - previousTime) / 1000, 0.05);
previousTime = timestamp;
distance = (distance + speed * deltaSeconds) % totalLength;
let segment = segments[segments.length - 1];
for (const candidate of segments) {
if (distance <= candidate.endDistance) {
segment = candidate;
break;
}
}
const segmentStart = segment.endDistance - segment.length;
const progress = (distance - segmentStart) / segment.length;
const x = segment.start.x + (segment.end.x - segment.start.x) * progress;
const y = segment.start.y + (segment.end.y - segment.start.y) * progress;
const xPercent = (x / ORIGINAL_WIDTH) * 100;
const yPercent = (y / ORIGINAL_HEIGHT) * 100;
point.style.left = xPercent + '%';
point.style.top = yPercent + '%';
if (timestamp - previousTrailTime > 110) {
createTrail(container, xPercent, yPercent);
previousTrailTime = timestamp;
}
window.requestAnimationFrame(render);
}
const start = function () { window.requestAnimationFrame(render); };
if (image.complete) start();
else image.addEventListener('load', start, { once: true });
}
function initializeAll(scope) {
const root = scope || document;
if (root.matches && root.matches(SELECTOR)) initializeCycle(root);
root.querySelectorAll(SELECTOR).forEach(initializeCycle);
}
function boot() {
initializeAll(document);
// Supports modules inserted or refreshed by the Divi Visual Builder.
const observer = new MutationObserver(function (mutations) {
for (const mutation of mutations) {
mutation.addedNodes.forEach(function (node) {
if (node.nodeType === Node.ELEMENT_NODE) initializeAll(node);
});
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot, { once: true });
} else {
boot();
}
}());