File: /home/smilepac/public_html/wp-content/plugins/codevz-plus/wpbakery/assets/js/360_degree.js
"use strict";
class ProductViewer {
constructor(element) {
this.element = element;
this.handleContainer = element.querySelector(".cz_product-viewer-handle");
this.handleFill = this.handleContainer?.querySelector(".fill");
this.handle = this.handleContainer?.querySelector(".handle");
this.imageWrapper = element.querySelector(".product-viewer");
this.slideShow = this.imageWrapper?.querySelector(".product-sprite");
this.frames = parseInt(element.dataset.frame) || 1;
this.friction = parseFloat(element.dataset.friction) || 1;
this.action = element.dataset.action;
this.visibleFrame = 0;
this.loaded = false;
this.animating = false;
this.xPosition = 0;
this.loadFrames();
}
setTransform(el, value) {
if (!el) return;
el.style.transform = value;
}
loadFrames() {
const imageUrl = this.slideShow?.dataset.image;
if (!imageUrl) return;
this.loading(0.5);
const img = new Image();
img.onload = () => {
this.loaded = true;
};
setTimeout(() => {
img.src = imageUrl;
}, 50);
}
loading(pct) {
this.setTransform(this.handleFill, `scaleX(${pct})`);
setTimeout(() => {
if (this.loaded) {
this.element.classList.add("loaded");
this.setTransform(this.handleFill, "scaleX(1)");
this.dragImage();
if (this.handle) this.dragHandle();
} else {
const nextPct = parseFloat(pct) + 0.1;
if (nextPct < 1) this.loading(nextPct);
}
}, 500);
}
dragHandle() {
const onStart = (e) => {
e.preventDefault();
this.handle.classList.add("cz_draggable");
const rect = this.handleContainer.getBoundingClientRect();
const handleWidth = this.handle.offsetWidth;
const containerWidth = rect.width;
const containerLeft = rect.left + window.scrollX;
const minX = containerLeft - handleWidth / 2;
const maxX = containerLeft + containerWidth - handleWidth / 2;
const pageX = e.touches ? e.touches[0].pageX : e.pageX;
this.xPosition = (this.handle.getBoundingClientRect().left + window.scrollX) + handleWidth - pageX;
const onMove = (moveEvent) => {
if (!this.animating) {
this.animating = true;
requestAnimationFrame(() => {
this.animateDraggedHandle(moveEvent, handleWidth, containerLeft, containerWidth, minX, maxX);
});
}
};
const onEnd = () => {
this.handle.classList.remove("cz_draggable");
document.removeEventListener("mousemove", onMove);
document.removeEventListener("touchmove", onMove);
};
document.addEventListener("mousemove", onMove);
document.addEventListener("touchmove", onMove, { passive: false });
document.addEventListener("mouseup", onEnd, { once: true });
document.addEventListener("touchend", onEnd, { once: true });
};
this.handle.addEventListener("mousedown", onStart);
this.handle.addEventListener("touchstart", onStart, { passive: false });
}
animateDraggedHandle(e, width, left, totalWidth, min, max) {
const pageX = e.touches ? e.touches[0].pageX : e.pageX;
let m = pageX + this.xPosition - width;
m = Math.max(min, Math.min(m, max));
const pct = Math.ceil(1000 * (m + width / 2 - left) / totalWidth) / 10;
this.visibleFrame = Math.ceil(pct * (this.frames - 1) / 100);
this.updateFrame();
if (this.handle) this.handle.style.left = `${pct}%`;
this.animating = false;
}
dragImage() {
let startEvents = ["mousedown", "touchstart"];
let endEvents = ["mouseup", "touchend"];
if (this.action !== "drag") {
startEvents = ["mouseenter", "touchstart"];
endEvents = ["mouseleave", "touchend"];
}
const onStart = (e) => {
this.slideShow.classList.add("cz_draggable");
const rect = this.imageWrapper.getBoundingClientRect();
const wrapperLeft = rect.left + window.scrollX;
const wrapperWidth = rect.width;
this.xPosition = e.touches ? e.touches[0].pageX : e.pageX;
const onMove = (moveEvent) => {
if (!this.animating) {
this.animating = true;
requestAnimationFrame(() => {
this.animateDraggedImage(moveEvent, wrapperLeft, wrapperWidth);
});
}
};
const onEnd = () => {
this.slideShow.classList.remove("cz_draggable");
this.element.removeEventListener("mousemove", onMove);
this.element.removeEventListener("touchmove", onMove);
this.updateHandle();
};
this.element.addEventListener("mousemove", onMove);
this.element.addEventListener("touchmove", onMove, { passive: false });
endEvents.forEach(evt => {
this.element.addEventListener(evt, onEnd, { once: true });
});
};
startEvents.forEach(evt => {
this.slideShow.addEventListener(evt, onStart, { passive: evt === 'touchstart' ? false : true });
});
}
animateDraggedImage(e, left, width) {
const pageX = e.touches ? e.touches[0].pageX : e.pageX;
const deltaX = this.xPosition - pageX;
let shift = Math.ceil((100 * deltaX) / (width * this.friction)) * (this.frames - 1) / 100;
shift = shift > 0 ? Math.floor(shift) : Math.ceil(shift);
let nextFrame = this.visibleFrame + shift;
if (nextFrame < 0) nextFrame = this.frames - 1;
else if (nextFrame > this.frames - 1) nextFrame = 0;
if (nextFrame !== this.visibleFrame) {
this.visibleFrame = nextFrame;
this.updateFrame();
this.xPosition = pageX;
}
this.animating = false;
}
updateHandle() {
if (this.handle) {
const pct = (100 * this.visibleFrame) / this.frames;
this.handle.style.transition = "left 0.2s";
this.handle.style.left = `${pct}%`;
setTimeout(() => { this.handle.style.transition = ""; }, 200);
}
}
updateFrame() {
const pct = (-100 * this.visibleFrame) / this.frames;
this.setTransform(this.slideShow, `translateX(${pct}%)`);
}
}
Codevz_Plus.r360degree = function() {
document.querySelectorAll(".cz_product-viewer-wrapper:not([data-init])").forEach( el => {
el.dataset.init = "1";
setTimeout(() => {
new ProductViewer( el );
}, 500);
});
};
Codevz_Plus.r360degree();