/** * Image Compare * * Modified by Stas to make it lightweight and use only options that are really needed * * @package imageCompare.js * @since 1.0.0 * @author Stas * @link http://xstore.8theme.com * @license Themeforest Split Licence */ // uncomment for packing // import "../styles/index.scss"; // import { disableBodyScroll, enableBodyScroll } from "body-scroll-lock"; class ImageCompare { constructor(el, settings = {}) { const defaults = { // controlLineColor: "#FFFFFF", // controlShadow: true, // addCircle: false, // addCircleBlur: true, showLabels: false, labelOptions: { before: "Before", after: "After", onHover: false, }, smoothing: true, smoothingAmount: 100, onHover: false, verticalMode: false, startingPoint: 50, // slideWidth: 50, // lineWidth: 2, prefix: 'etheme-image-comparison', addOverlay: false }; this.settings = Object.assign(defaults, settings); this.safariAgent = navigator.userAgent.indexOf("Safari") != -1 && navigator.userAgent.indexOf("Chrome") == -1; this.el = el; this.images = {}; this.wrapper = null; this.control = null; this.arrowContainer = null; this.arrowAnimator = []; this.active = false; this.arrowCoordinates = { circle: [5, 3], standard: [8, 0], }; } mount() { // Temporarily disable Safari smoothing if (this.safariAgent) { this.settings.smoothing = false; } this._getImages(); this._shapeContainer(); this._buildControl(); this._events(); } _events() { // Desktop events this.el.addEventListener("mousedown", (ev) => { this._activate(true); document.body.classList.add(this.settings.prefix+"-body"); // disableBodyScroll(this.el, {reserveScrollBarGap: true}); this._slideCompare(ev); }); this.el.addEventListener( "mousemove", (ev) => this.active && this._slideCompare(ev) ); this.el.addEventListener("mouseup", () => !this.settings.onHover && this._activate(false)); document.body.addEventListener("mouseup", () => { document.body.classList.remove(this.settings.prefix + "-body"); // enableBodyScroll(this.el); if ( !this.settings.onHover ) this._activate(false); }); // Mobile events this.control.addEventListener("touchstart", (e) => { this._activate(true); document.body.classList.add(this.settings.prefix+"-body"); // disableBodyScroll(this.el, {reserveScrollBarGap: true}); }); this.el.addEventListener("touchmove", (ev) => { this.active && this._slideCompare(ev); }); this.el.addEventListener("touchend", () => { this._activate(false); document.body.classList.remove(this.settings.prefix+"-body"); // enableBodyScroll(this.el); }); // hover this.el.addEventListener("mouseenter", () => { this.settings.onHover && this._activate(true); // let coord = this.settings.addCircle // ? this.arrowCoordinates.circle // : this.arrowCoordinates.standard; // this.arrowAnimator.forEach((anim, i) => { // anim.style.cssText = ` // ${ // this.settings.verticalMode // ? `transform: translateY(${coord[1] * (i === 0 ? 1 : -1)}px);` // : `transform: translateX(${coord[1] * (i === 0 ? 1 : -1)}px);` // } // `; // }); }); // this.el.addEventListener("mouseleave", () => { // let coord = this.settings.addCircle // ? this.arrowCoordinates.circle // : this.arrowCoordinates.standard; // this.arrowAnimator.forEach((anim, i) => { // anim.style.cssText = ` // ${ // this.settings.verticalMode // ? `transform: translateY(${ // i === 0 ? `${coord[0]}px` : `-${coord[0]}px` // });` // : `transform: translateX(${ // i === 0 ? `${coord[0]}px` : `-${coord[0]}px` // });` // } // `; // }); // }); } _slideCompare(ev) { let bounds = this.el.getBoundingClientRect(); let x = ev.touches !== undefined ? ev.touches[0].clientX - bounds.left : ev.clientX - bounds.left; let y = ev.touches !== undefined ? ev.touches[0].clientY - bounds.top : ev.clientY - bounds.top; let position = this.settings.verticalMode ? (y / bounds.height) * 100 : (x / bounds.width) * 100; if (position >= 0 && position <= 100) { // this.settings.verticalMode // ? (this.control.style.top = `calc(${position}% - ${ // this.settings.slideWidth / 2 // }px)`) // : (this.control.style.left = `calc(${position}% - ${ // this.settings.slideWidth / 2 // }px)`); // new this.settings.verticalMode ? (this.control.style.top = `calc(${position}% - (var(--divider-width, 45px) / 2))`) : (this.control.style.left = `calc(${position}% - (var(--divider-width, 45px) / 2))`); this.settings.verticalMode ? (this.wrapper.style.height = `calc(${position}%)`) : (this.wrapper.style.width = `calc(${100 - position}%)`); } } _activate(state) { this.active = state; } _shapeContainer() { let label_l = document.createElement("span"); let label_r = document.createElement("span"); label_l.classList.add(this.settings.prefix+"-label", this.settings.prefix+"-label-before"); label_r.classList.add(this.settings.prefix+"-label", this.settings.prefix+"-label-after"); if (this.settings.labelOptions.onHover) { label_l.classList.add("on-hover"); label_r.classList.add("on-hover"); } // if (this.settings.verticalMode) { // label_l.classList.add("vertical"); // label_r.classList.add("vertical"); // } label_l.innerHTML = this.settings.labelOptions.before || "Before"; label_r.innerHTML = this.settings.labelOptions.after || "After"; if (this.settings.showLabels) { this.el.prepend(label_l); // if ( !this.settings.verticalMode ) this.wrapper.appendChild(label_r); // else // this.el.appendChild(label_r); } // this.el.classList.add( // this.settings.prefix, // this.settings.prefix + (this.settings.verticalMode ? `-vertical` : `-horizontal`), // ); if (this.settings.addOverlay) { let overlay = document.createElement("div"); overlay.classList.add(this.settings.prefix + "-overlay"); this.el.appendChild(overlay); } } _buildControl() { let control = document.createElement("div"); let uiLine = document.createElement("div"); let arrows = document.createElement("div"); let arrowsWrapper = document.createElement("div"); // let circle = document.createElement("div"); // const arrowSize = "20"; arrows.classList.add(this.settings.prefix+"-theme-wrapper"); arrowsWrapper.classList.add(this.settings.prefix+"-arrows-wrapper"); arrows.appendChild(arrowsWrapper); for (var idx = 0; idx <= 1; idx++) { let animator = document.createElement(`span`); let arrow = ``; if ( !this.settings.verticalMode ) { arrow += (idx === 0 ? `` : `` ); } else { arrow += (idx === 0 ? `` : `` ); } arrow += ``; // let arrow = ` // // `; animator.innerHTML += arrow; this.arrowAnimator.push(animator); arrowsWrapper.appendChild(animator); } // let coord = this.settings.addCircle // ? this.arrowCoordinates.circle // : this.arrowCoordinates.standard; // this.arrowAnimator.forEach((anim, i) => { // // anim.classList.add("icv-arrow-wrapper"); // // anim.style.cssText = ` // ${ // this.settings.verticalMode // ? `transform: translateY(${ // i === 0 ? `${coord[0]}px` : `-${coord[0]}px` // });` // : `transform: translateX(${ // i === 0 ? `${coord[0]}px` : `-${coord[0]}px` // });` // } // `; // }); control.classList.add(this.settings.prefix+"-control"); control.style.cssText = ` ${this.settings.verticalMode ? `height` : `width `}: var(--divider-width, 45px); ${this.settings.verticalMode ? `top` : `left `}: calc(${ this.settings.startingPoint }% - (var(--divider-width, 45px) / 2)); ${ "ontouchstart" in document.documentElement ? `` : this.settings.smoothing ? `transition: ${this.settings.smoothingAmount}ms ease-out;` : `` } `; uiLine.classList.add(this.settings.prefix+"-control-line"); uiLine.style.cssText = ` ${this.settings.verticalMode ? `height` : `width `}: var(--divider-line-width, 2px); background: var(--divider-bg-color, #2962FF); `; let uiLine2 = uiLine.cloneNode(true); // circle.classList.add(this.settings.prefix+"-control-drag"); // circle.style.cssText = ` // ${ // this.settings.addCircleBlur && // `-webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px)` // }; // border: ${this.settings.lineWidth}px solid ${this.settings.controlLineColor}; // ${ // this.settings.controlShadow && // `box-shadow: 0px 0px 15px rgba(0,0,0,0.33)` // }; // `; control.appendChild(uiLine); // this.settings.addCircle && control.appendChild(circle); control.appendChild(arrows); control.appendChild(uiLine2); this.arrowContainer = arrows; this.control = control; this.el.appendChild(control); } _getImages() { let children = this.el.querySelectorAll("img, ." + this.settings.prefix+"-label"); this.el.innerHTML = ""; children.forEach((img) => { this.el.appendChild(img); }); let childrenImages = [...children].filter( (element) => element.nodeName.toLowerCase() === "img" ); // this.settings.verticalMode && [...children].reverse(); this.settings.verticalMode && childrenImages.reverse(); for (let idx = 0; idx <= 1; idx++) { let child = childrenImages[idx]; child.classList.add(this.settings.prefix+"-img"); child.classList.add(idx === 0 ? this.settings.prefix+`-img-a` : this.settings.prefix+`-img-b`); if (idx === 1) { let wrapper = document.createElement("div"); // let afterUrl = childrenImages[1].src; wrapper.classList.add(this.settings.prefix+"-wrapper"); wrapper.style.cssText = ` width: ${100 - this.settings.startingPoint}%; height: ${this.settings.startingPoint}%; ${ "ontouchstart" in document.documentElement ? `` : this.settings.smoothing ? `transition: ${this.settings.smoothingAmount}ms ease-out;` : `` } `; wrapper.appendChild(child); this.wrapper = wrapper; this.el.appendChild(this.wrapper); } } } }