<div class="section section-product-all-images">
<div class="container">
<h2 class="h2">Photos</h2>
<div class="image-thumb-grid">
<ul class="image-thumb-grid-list">
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool" data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.png?h=400&w=500&hash=4E254D2964FDDD4D12E42FC032EB8F15" alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product" data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.jpg" data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.png?h=768&w=1024&hash=A1CD0C8E881B9C6D8D20E92880FA3D41" data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.png?h=169&w=169&hash=CECB43C44DBFF80A95520A355E07E985">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool" data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.png?h=400&w=500&hash=046DD37AD384473762672F5553C1A823" alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product" data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.jpg" data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.png?h=768&w=1024&hash=E58B0CEC48568613DBA5AB57479C19A2" data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.png?h=169&w=169&hash=00CC5E072654185CE4FF558F6E7E8798">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool" data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.png?h=400&w=500&hash=E511BA1EB20FAF9E6A348DAEE13B3135" alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product" data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.jpg" data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.png?h=768&w=1024&hash=056CCF4B5E9E7092585E1AA0AAD8E7A7" data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.png?h=169&w=169&hash=BA19093A07C0316C7BDC3218840D1A54">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool" data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.png?h=400&w=500&hash=F5F0BADDBA4FFEF5E7168D1C31246F8F" alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product" data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.jpg" data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.png?h=768&w=1024&hash=75D74C38A40C330D4324AA4B72CC469F" data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.png?h=169&w=169&hash=8971A8A47BF7F2C4C5114FD7FC4F55E6">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool" data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.png?h=400&w=500&hash=9127D631BD40CE9D2118A81BB05AAE0C" alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product" data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.jpg" data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.png?h=768&w=1024&hash=FD4FF4BF10E8D7D7F7A0F800744842C7" data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.png?h=169&w=169&hash=599BBA53B0543026B69CE1BDACBC0CEE">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="section section-product-all-images">
<div class="container">
<h2 class="h2">Photos</h2>
<div class="image-thumb-grid">
<ul class="image-thumb-grid-list">
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool"
data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img
src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.png?h=400&w=500&hash=4E254D2964FDDD4D12E42FC032EB8F15"
alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product"
data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.jpg"
data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.png?h=768&w=1024&hash=A1CD0C8E881B9C6D8D20E92880FA3D41"
data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-main.png?h=169&w=169&hash=CECB43C44DBFF80A95520A355E07E985">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool"
data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img
src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.png?h=400&w=500&hash=046DD37AD384473762672F5553C1A823"
alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product"
data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.jpg"
data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.png?h=768&w=1024&hash=E58B0CEC48568613DBA5AB57479C19A2"
data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-angle.png?h=169&w=169&hash=00CC5E072654185CE4FF558F6E7E8798">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool"
data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img
src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.png?h=400&w=500&hash=E511BA1EB20FAF9E6A348DAEE13B3135"
alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product"
data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.jpg"
data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.png?h=768&w=1024&hash=056CCF4B5E9E7092585E1AA0AAD8E7A7"
data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-side.png?h=169&w=169&hash=BA19093A07C0316C7BDC3218840D1A54">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool"
data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img
src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.png?h=400&w=500&hash=F5F0BADDBA4FFEF5E7168D1C31246F8F"
alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product"
data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.jpg"
data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.png?h=768&w=1024&hash=75D74C38A40C330D4324AA4B72CC469F"
data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-front.png?h=169&w=169&hash=8971A8A47BF7F2C4C5114FD7FC4F55E6">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
<li class="image-thumb-grid-item">
<a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool"
data-classes="light zoom">
<span class="head">
<i class="ico"></i>
<span class="image">
<img
src="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.png?h=400&w=500&hash=9127D631BD40CE9D2118A81BB05AAE0C"
alt="DDJ-SP1" class="zoomtool-capable" rel="zoom-product"
data-full="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.jpg"
data-large="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.png?h=768&w=1024&hash=FD4FF4BF10E8D7D7F7A0F800744842C7"
data-small="https://www.pioneerdj.com/-/media/pioneerdj/images/products/controller/ddj-sp1/black/ddj-sp1-perspective.png?h=169&w=169&hash=599BBA53B0543026B69CE1BDACBC0CEE">
</span>
</span>
<span class="body">
DDJ-SP1
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
/* No context defined. */
/**
* Zoomer
*
* This is the plugin code for the Zoomer overlayer/gallery/image zoom effect.
*
* @demo one image:
*
* new Zoomer({
* trigger: document.querySelector('.link'),
* image: 'https://www.url.tld/full-size-image.jpg',
* });
*
* @demo gallery of images:
*
* new Zoomer({
* gallery: 'specific-name',
* images: [
* {
* 'thumb': '/path/thumnail-image.jpg',
* 'large': '/path/full-size-image.jpg',
* 'title': 'Optional image alt param',
* },
* ...
* ],
* });
*
*/
// import ZoomerOverlayer from './ZoomerOverlayer';
const Zoomer = function(settings = {}) {
const defaults = {
downloadButton: true, // show download button
generateOverlayerOnLoad: false, // generate overlayer dom content on page load
scaleWithBrowser: true, // boolean to scale real img size or with browser width
startZoomPercentage: 50, // start zoom percentage
minScale: .2, // minimum scale size
maxScale: 1.5, // maximum scale size
blockScrollClass: 'zoomeractive', // class that is placed on the html element to block scrolling
// - required:
// trigger: node element to launch the zoomer
// image: string to image (URL or file path)
// — or:
// gallery: string to 'ID' the gallery
// images: array of images (with thumb & large)
};
this.settings = {
...defaults,
...settings,
};
this.el = {};
this.init();
};
Zoomer.prototype.init = function() {
this.getElements();
if (!(this.isArray(this.images) && this.images.length > 0)) {
return;
}
this.overlayer = new ZoomerOverlayer({
images: this.images,
downloadButton: this.settings.downloadButton,
scaleWithBrowser: this.settings.scaleWithBrowser,
startZoomPercentage: this.settings.startZoomPercentage,
minScale: this.settings.minScale,
maxScale: this.settings.maxScale,
blockScrollClass: this.settings.blockScrollClass,
});
if (this.settings.generateOverlayerOnLoad === true) {
this.overlayer.generate();
}
this.addEvents();
};
Zoomer.prototype.getElements = function() {
if (this.isNode(this.settings.trigger) && this.isString(this.settings.image)) {
this.el.triggers = [this.settings.trigger];
this.images = [{
large: this.settings.image,
title: this.isString(this.settings.trigger.dataset.zoomerTitle) ? this.settings.trigger.dataset.zoomerTitle : (this.settings.trigger.title ?? ''),
}];
} else if (this.isString(this.settings.gallery)) {
this.el.triggers = [...document.querySelectorAll(`[data-zoomer-gallery="${this.settings.gallery}"]`)];
if (this.isArray(this.settings.images) && this.settings.images.length > 0) {
this.images = this.settings.images;
} else {
this.el.triggers = [...document.querySelectorAll(`[data-zoomer-gallery="${this.settings.gallery}"]`)];
this.images = [];
this.el.triggers.forEach(trigger => {
if (this.isString(trigger.dataset.zoomerImageThumbnail) && this.isString(trigger.dataset.zoomerImageLarge)) {
const thumb = trigger.dataset.zoomerImageThumbnail;
const large = trigger.dataset.zoomerImageLarge;
const title = this.isString(trigger.dataset.zoomerTitle) ? trigger.dataset.zoomerTitle : (trigger.title ?? '');
this.images.push({ thumb, large, title });
}
});
}
}
};
Zoomer.prototype.addEvents = function() {
if (this.isArray(this.el.triggers)) {
this.el.triggers.forEach((trigger, triggerIndex) => {
trigger.addEventListener('click', e => {
e.preventDefault();
this.open(trigger.dataset.zoomerIndex ?? (1 + triggerIndex));
});
});
}
document.addEventListener('keyup', e => {
if (this.overlayer && e.key === 'Escape') {
this.overlayer.hide();
}
});
};
Zoomer.prototype.open = function(number = 1) {
if (!this.overlayer || !this.overlayer.el.wrapper) {
this.overlayer.generate();
}
if (!this.overlayer) {
return;
}
this.overlayer.show(number);
};
Zoomer.prototype.close = function() {
if (!this.overlayer) {
return;
}
this.overlayer.hide();
};
Zoomer.prototype.scaleTo = function(percentage) {
if (percentage < 0 || percentage > 100) {
return;
}
this.overlayer.scaleTo(percentage);
};
Zoomer.prototype.isString = function(v) {
return (typeof v === 'string' || v instanceof String) && v.length > 0;
};
Zoomer.prototype.isArray = function(v) {
return Array.isArray(v);
};
Zoomer.prototype.isNode = function(v) {
return v && v.nodeType && v.parentNode;
};
window.Zoomer = Zoomer;
// export default Zoomer;
/**
* Zoomer init code
* This code just does the startups of Zoomer galleries.
*/
const initSingleZoomers = () => {
[...document.querySelectorAll('[data-zoomer]')].forEach(el => {
if (el.dataset.zoomer !== 'gallery') {
new Zoomer({
trigger: el,
image: el.dataset.zoomer,
});
}
});
};
const initGalleryZoomers = () => {
const selector = '[data-zoomer="gallery"][data-zoomer-gallery][data-zoomer-image-thumbnail][data-zoomer-image-large]'; // don't change! All data elements are required - if it would only be '[data-zoomer="gallery"]' it might duplicate galleries!
const galleries = [];
[...document.querySelectorAll(selector)].forEach(el => {
galleries[el.dataset.zoomerGallery] = el.dataset.zoomerGallery;
});
Object.keys(galleries).forEach(gallery => new Zoomer({ gallery }));
};
const initOldZoomtoolZoomers = () => {
const selectors = {
wrapper: '.section', // maybe better: '.image-thumb-grid'
links: 'a.zoom-tool', // <a href="#zoom-tool-01" class="zoom-thumb image-thumb trigger__open-overlayer zoom-tool">
image: 'img[data-large][data-small]', // <img ... class="zoomtool-capable" rel="zoom-product" data-...>
};
[...document.querySelectorAll(selectors.wrapper)].forEach((galleryWrapper, galleryIndex) => {
const galleryName = `original-zoomer-updated--${1 + galleryIndex}`;
const images = [];
[...galleryWrapper.querySelectorAll(selectors.links)].forEach((link, linkIndex) => {
const image = link.querySelector(selectors.image);
if (image && image.parentNode) {
images.push({
'thumb': image.dataset.small,
'large': image.dataset.large,
'title': image.alt ?? '',
});
link.dataset.zoomer = 'gallery';
link.dataset.zoomerGallery = galleryName;
link.dataset.zoomerItem = 1 + linkIndex;
}
});
if (galleryName.length && images.length) {
new Zoomer({ gallery: galleryName, images });
}
});
};
document.addEventListener('DOMContentLoaded', () => {
if (!window.Zoomer) {
return;
}
initSingleZoomers();
initGalleryZoomers();
initOldZoomtoolZoomers();
});
// ZoomerOverlayer is external JS file that is required by Zoomer.js
// import ZoomerScaler from './ZoomerScaler';
const ZoomerOverlayer = function(settings = {}) {
const defaults = {
images: [],
scaleWithBrowser: false,
startZoomPercentage: 50,
minScale: .1,
maxScale: 2,
downloadButton: false,
blockScrollClass: 'zoomeractive',
};
this.settings = {
...defaults,
...settings,
};
this.el = {};
this.generated = false;
this.activeVisual = -1;
};
ZoomerOverlayer.prototype.generate = function() {
if (this.generated || this.el.wrapper || !this.settings.images || this.settings.images.length <= 0) {
return;
}
this.el.wrapper = document.createElement('div');
this.el.wrapper.classList.add('zoomer');
this.el.wrapper.classList.toggle('zoomer--fullscale', !this.settings.scaleWithBrowser);
this.el.inner = document.createElement('div');
this.el.inner.classList.add('zoomer__inner');
this._generateHeader(this.el.inner);
this._generateVisual(this.el.inner);
this._generateThumbs(this.el.inner);
this.scaleTo(this.settings.startZoomPercentage);
this.el.wrapper.appendChild(this.el.inner);
document.body.appendChild(this.el.wrapper);
this.addEvents();
this.generated = true;
};
ZoomerOverlayer.prototype.addEvents = function() {
if (this.el && this.el.visual && this.el.visual.wrapper && this.el.visual.inner) {
this.el.visual.wrapper.addEventListener('wheel', e => {
if (!this.scaler) {
return;
}
e.preventDefault();
const newValue = this.scaler.getValue() + (e.deltaY / 50);
this.scaler.scaleTo(newValue);
});
this.el.visual.wrapper.addEventListener('mousedown', e => this._startMove(e));
this.el.visual.wrapper.addEventListener('mousemove', e => this._isMoving(e));
this.el.visual.wrapper.addEventListener('mouseup', () => this._endMove());
this.el.visual.wrapper.addEventListener('mouseleave', () => this._endMove());
this.el.visual.wrapper.addEventListener('touchstart', e => this._startMove(e));
this.el.visual.wrapper.addEventListener('touchmove', e => this._isMoving(e));
this.el.visual.wrapper.addEventListener('touchend', () => this._endMove());
}
};
ZoomerOverlayer.prototype._generateHeader = function(wrapperEl) {
if (!this.el) {
return;
}
this.el.header = {};
this.scaler = new ZoomerScaler({
onUpdate: percentage => this.scaleTo(percentage),
});
if (this.settings.downloadButton) {
this.el.download = document.createElement('a');
this.el.download.href = '#';
this.el.download.setAttribute('download', true);
this.el.download.target = '_blank';
this.el.download.classList.add('zoomer-header__download');
this.el.download.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M8.53 11.78a.75.75 0 0 1-1.06 0l-2.5-2.5a.75.75 0 0 1 1.06-1.06l1.22 1.22V1.75a.75.75 0 0 1 1.5 0v7.69l1.22-1.22a.75.75 0 1 1 1.06 1.06zM1.75 13.5a.75.75 0 0 0 0 1.5h12.5a.75.75 0 0 0 0-1.5z" clip-rule="evenodd"/></svg>';
}
this.el.close = document.createElement('button');
this.el.close.classList.add('zoomer-header__close');
this.el.close.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M3.47 3.47a.75.75 0 0 1 1.06 0L8 6.94l3.47-3.47a.75.75 0 1 1 1.06 1.06L9.06 8l3.47 3.47a.75.75 0 1 1-1.06 1.06L8 9.06l-3.47 3.47a.75.75 0 0 1-1.06-1.06L6.94 8 3.47 4.53a.75.75 0 0 1 0-1.06" clip-rule="evenodd"/></svg>';
this.el.close.addEventListener('click', () => this.hide());
this.el.header.inner = document.createElement('div');
this.el.header.inner.classList.add('zoomer-header__inner');
this.el.header.inner.appendChild(this.scaler.getElement());
if (this.settings.downloadButton && this.el.download) {
this.el.header.inner.appendChild(this.el.download);
}
this.el.header.inner.appendChild(this.el.close);
this.el.header.wrapper = document.createElement('div');
this.el.header.wrapper.classList.add('zoomer-header');
this.el.header.wrapper.appendChild(this.el.header.inner);
if (wrapperEl) {
wrapperEl.appendChild(this.el.header.wrapper);
}
};
ZoomerOverlayer.prototype._generateVisual = function(wrapperEl) {
this.el.visual = {};
this.el.visual.wrapper = document.createElement('div');
this.el.visual.wrapper.classList.add('zoomer-visual');
this.el.visual.inner = document.createElement('div');
this.el.visual.inner.classList.add('zoomer-visual__inner');
this.el.visual.wrapper.appendChild(this.el.visual.inner);
this.el.visual.image = document.createElement('img');
this.el.visual.image.setAttribute('draggable', false);
this.el.visual.inner.appendChild(this.el.visual.image);
if (wrapperEl) {
wrapperEl.appendChild(this.el.visual.wrapper);
}
};
ZoomerOverlayer.prototype._generateThumbs = function(wrapperEl) {
if (!this.el || this.settings.images.length <= 1) {
return;
}
this.el.thumbs = {};
this.el.thumbs.wrapper = document.createElement('div');
this.el.thumbs.wrapper.classList.add('zoomer-thumbs');
this.el.thumbs.inner = document.createElement('div');
this.el.thumbs.inner.classList.add('zoomer-thumbs__inner');
this.el.thumbs.wrapper.appendChild(this.el.thumbs.inner);
this.el.thumbs.sliderList = document.createElement('ul');
this.el.navLinks = [];
this.settings.images.forEach((image, index) => {
const img = document.createElement('img');
img.src = image.thumb;
img.alt = '';
const link = document.createElement('button');
link.classList.add('zoomer-thumbs__link');
link.addEventListener('click', () => this.show(1 + index));
link.appendChild(img);
this.el.navLinks.push(link);
const li = document.createElement('li');
li.appendChild(link);
this.el.thumbs.sliderList.appendChild(li);
});
this.el.thumbs.slider = document.createElement('div');
this.el.thumbs.slider.classList.add('zoomer-thumbs__slider');
this.el.thumbs.slider.appendChild(this.el.thumbs.sliderList);
this.el.thumbs.inner.appendChild(this.el.thumbs.slider);
if (wrapperEl) {
wrapperEl.appendChild(this.el.thumbs.wrapper);
}
};
ZoomerOverlayer.prototype.show = function(number = 1) {
if (!this.el.wrapper) {
return;
}
document.documentElement.classList.add(this.settings.blockScrollClass);
this.resetMoveTo();
this.scaler.scaleTo(this.settings.startZoomPercentage);
this.el.wrapper.classList.add('zoomer--visible');
this.activeVisual = number;
this.updateVisual(number);
this.activateThumb(number);
};
ZoomerOverlayer.prototype.hide = function() {
if (!this.el.wrapper) {
return;
}
this.el.wrapper.classList.remove('zoomer--visible');
this.clearVisual();
this.activateThumb(false);
document.documentElement.classList.remove(this.settings.blockScrollClass);
};
ZoomerOverlayer.prototype.clearVisual = function() {
if (!this.el.visual || !this.el.visual.inner) {
return;
}
this.el.visual.wrapper.classList.remove('zoomer-visual--visible');
this.el.visual.image.setAttribute('src', '');
this.el.visual.image.setAttribute('alt', '');
};
ZoomerOverlayer.prototype.updateVisual = function(number = 1) {
const index = number - 1;
if (!this.settings.images || !this.settings.images[index]) {
throw new Error(`Zoomer: failed to add visual (number: ${number})`);
}
this.el.visual.image.setAttribute('src', this.settings.images[index].large);
this.el.visual.image.setAttribute('alt', this.settings.images[index].title ?? '');
this.el.visual.wrapper.classList.add('zoomer-visual--visible');
if (this.el.download) {
this.el.download.href = `${this.settings.images[index].large}?force=1`;
}
};
ZoomerOverlayer.prototype.activateThumb = function(number = 1) {
if (!this.el.navLinks) {
return;
}
this.el.navLinks.forEach((link, linkIndex) => {
link.classList.toggle('zoomer-thumbs__link--active', linkIndex === number - 1);
});
};
ZoomerOverlayer.prototype.scaleTo = function(percentage) {
let minScale = this.settings.minScale;
let maxScale = this.settings.maxScale;
let scaleCalc = (maxScale - minScale) / 100;
const scale = minScale + (scaleCalc * percentage);
this.el.wrapper.style.setProperty("--zoomer-scale", scale);
};
ZoomerOverlayer.prototype.resetMoveTo = function() {
this._xPerc = this.settings.scaleWithBrowser ? 0 : -50;
this._yPerc = this.settings.scaleWithBrowser ? 0 : -50;
this.moveTo(this._xPerc, this._yPerc);
};
ZoomerOverlayer.prototype.moveTo = function(xPerc, yPerc) {
if ([xPerc, yPerc].includes(NaN)) {
xPerc = this.settings.scaleWithBrowser ? 0 : -50;
yPerc = this.settings.scaleWithBrowser ? 0 : -50;
}
xPerc = parseFloat(xPerc);
yPerc = parseFloat(yPerc);
// xPerc = xPerc < -100 ? -100 : (xPerc > 0 ? 0 : xPerc);
// yPerc = yPerc < -100 ? -100 : (yPerc > 0 ? 0 : yPerc);
this.el.wrapper.style.setProperty("--zoomer-xperc", `${xPerc}%`);
this.el.wrapper.style.setProperty("--zoomer-yperc", `${yPerc}%`);
};
ZoomerOverlayer.prototype._startMove = function(e) {
this.isMoving = true;
const offsetX = e.touches && e.touches[0] ? e.touches[0].clientX : e.offsetX;
const offsetY = e.touches && e.touches[0] ? e.touches[0].clientY : e.offsetY;
this._moveBoxRect = this.el.visual.inner.getBoundingClientRect();
this._movingStartXPerc = ((offsetX / (this._moveBoxRect.width / 100)));
this._movingStartYPerc = ((offsetY / (this._moveBoxRect.height / 100)));
const xPerc = parseFloat(this.el.wrapper.style.getPropertyValue('--zoomer-xperc'));
const yPerc = parseFloat(this.el.wrapper.style.getPropertyValue('--zoomer-yperc'));
this._xPerc = xPerc; // this._xPerc = xPerc >= -100 && xPerc <= 0 ? xPerc : -50;
this._yPerc = yPerc; // this._yPerc = yPerc >= -100 && yPerc <= 0 ? yPerc : -50;
};
ZoomerOverlayer.prototype._isMoving = function(e) {
if (!this.isMoving || !this._moveBoxRect) {
return;
}
// if (e && e.stopPropagation) {
// e.stopPropagation();
// }
const offsetX = e.touches && e.touches[0] ? e.touches[0].clientX : e.offsetX;
const offsetY = e.touches && e.touches[0] ? e.touches[0].clientY : e.offsetY;
const percentageX = ((offsetX / (this._moveBoxRect.width / 100)));
const percentageY = ((offsetY / (this._moveBoxRect.height / 100)));
this._movingCurrentXPerc = this._movingStartXPerc - percentageX;
this._movingCurrentYPerc = this._movingStartYPerc - percentageY;
this.moveTo(this._xPerc - this._movingCurrentXPerc, this._yPerc - this._movingCurrentYPerc);
};
ZoomerOverlayer.prototype._endMove = function() {
this.isMoving = false;
};
// window.ZoomerOverlayer = ZoomerOverlayer;
// export default ZoomerOverlayer;
// ZoomerScaler is external JS file that is required by ZoomerOverlayer.js
const ZoomerScaler = function(settings = {}) {
this.defaultSettings = {
startValue: 50,
clickSteps: 25,
scaleOutIcon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M1.75 8a.75.75 0 0 1 .75-.75h11a.75.75 0 0 1 0 1.5h-11A.75.75 0 0 1 1.75 8" clip-rule="evenodd"/></svg>',
scaleInIcon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M8 1.75a.75.75 0 0 1 .75.75v4.75h4.75a.75.75 0 0 1 0 1.5H8.75v4.75a.75.75 0 0 1-1.5 0V8.75H2.5a.75.75 0 0 1 0-1.5h4.75V2.5A.75.75 0 0 1 8 1.75" clip-rule="evenodd"/></svg>',
};
this.settings = {
...this.defaultSettings,
...settings,
};
this.el = {};
this.init();
};
ZoomerScaler.prototype.init = function() {
this.validateSettings();
this.generateElement();
};
ZoomerScaler.prototype.validateSettings = function() {
this.settings.startValue = parseInt(this.settings.startValue);
this.settings.startValue = (this.settings.startValue < 0 || this.settings.startValue > 100) ? this.defaultSettings.startValue : this.settings.startValue;
this.settings.clickSteps = parseInt(this.settings.clickSteps);
this.settings.clickSteps = (this.settings.clickSteps < .1 || this.settings.clickSteps > 50) ? this.defaultSettings.clickSteps : this.settings.clickSteps;
if (typeof this.settings.scaleOutIcon !== typeof '') {
this.settings.scaleOutIcon = '-';
}
if (typeof this.settings.scaleInIcon !== typeof '') {
this.settings.scaleInIcon = '+';
}
};
ZoomerScaler.prototype.generateElement = function() {
this.el.range = document.createElement('input');
this.el.range.type = 'range';
this.el.range.min = 0;
this.el.range.max = 100;
this.el.range.value = this.settings.startValue;
this.el.range.classList.add('zoomer-scale__range');
this.el.range.addEventListener('input', () => this.scaleTo(this.el.range.value));
this.el.scaleOutBtn = document.createElement('button');
this.el.scaleOutBtn.classList.add('zoomer-scale__out');
this.el.scaleOutBtn.innerHTML = this.settings.scaleOutIcon;
this.el.scaleOutBtn.addEventListener('click', () => this.scaleOut());
this.el.scaleInBtn = document.createElement('button');
this.el.scaleInBtn.classList.add('zoomer-scale__out');
this.el.scaleInBtn.innerHTML = this.settings.scaleInIcon;
this.el.scaleInBtn.addEventListener('click', () => this.scaleIn());
this.el.wrapper = document.createElement('div');
this.el.wrapper.classList.add('zoomer-scale');
this.el.wrapper.appendChild(this.el.scaleOutBtn);
this.el.wrapper.appendChild(this.el.range);
this.el.wrapper.appendChild(this.el.scaleInBtn);
};
ZoomerScaler.prototype.reset = function() {
this.scaleTo(this.settings.startValue);
};
ZoomerScaler.prototype.getValue = function() {
if (!this.el || !this.el.range) {
return -1;
}
return parseInt(this.el.range.value);
};
ZoomerScaler.prototype.scaleOut = function() {
if (!(this.el && this.el.range)) {
throw new Error('ZoomerScaler can not scale out');
}
this.scaleTo(parseInt(this.el.range.value) - this.settings.clickSteps);
};
ZoomerScaler.prototype.scaleIn = function() {
if (!(this.el && this.el.range)) {
throw new Error('ZoomerScaler can not scale in');
}
this.scaleTo(parseInt(this.el.range.value) + this.settings.clickSteps);
};
ZoomerScaler.prototype.scaleTo = function(newValue) {
if (!(this.el && this.el.range)) {
return;
}
this.el.range.value = newValue;
if (typeof this.settings.onUpdate === typeof function() {}) {
this.settings.onUpdate(parseInt(this.el.range.value));
}
};
ZoomerScaler.prototype.getElement = function() {
if (!(this.el && this.el.wrapper)) {
throw new Error('ZoomerScaler can not get wrapper');
}
return this.el.wrapper;
};
// window.ZoomerScaler = ZoomerScaler;
// export default ZoomerScaler;
.zoomer-header {
background-color: var(--zoomer--border-color, white);
padding-bottom: var(--zoomer--border-size);
&__inner {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--gap--4);
margin: 0 auto;
padding: var(--gap--2) 0;
max-width: var(--zoomer--header-width);
@media (min-width: 768px) {
justify-content: flex-start;
gap: var(--gap--20);
}
& > * {
flex: 0 1 auto;
}
}
&__download,
&__close {
color: var(--color--action);
transition: opacity var(--zoomer--transition-speed) var(--zoomer--transition-ease);
cursor: pointer;
&:hover {
opacity: .5;
}
}
&__close {
@media (min-width: 768px) {
margin-left: auto;
}
}
svg {
display: block;
width: var(--zoomer--icon-size);
height: var(--zoomer--icon-size);
}
}
@mixin zoomerScaleRangeStyle {
width: var(--zoomer--scale-size);
height: var(--zoomer--scale-size);
border-radius: 50%;
background: var(--color--action);
box-shadow: none;
border: none;
pointer-events: auto;
appearance: none;
}
.zoomer-scale {
display: flex;
justify-content: center;
align-items: center;
gap: var(--gap--4);
height: var(--zoomer--scale-size);
&__range,
input[type=range] {
appearance: none;
display: block;
width: var(--zoomer--scale-width, 150px);
height: 4px;
margin: 0;
padding: 0;
background-color: #dfdfdf;
border: none;
border-radius: 0;
accent-color: var(--color--action);
cursor: pointer;
// ⚠️ dont use comma's
&::-webkit-slider-thumb { @include zoomerScaleRangeStyle(); }
&::-moz-range-thumb { @include zoomerScaleRangeStyle(); }
&::-ms-thumb { @include zoomerScaleRangeStyle(); }
}
&__in,
&__out {
color: var(--color--neutrals-10);
transition: color var(--zoomer--transition-speed) var(--zoomer--transition-ease);
cursor: pointer;
&:hover {
color: var(--color--neutrals-5);
}
}
}
.zoomer-thumbs {
position: absolute;
right: var(--gap--2);
bottom: var(--gap--2);
left: var(--gap--2);
z-index: 1;
&__inner {
position: relative;
max-width: var(--zoomer--thumbs-width);
margin: 0 auto;
background-color: var(--zoomer--bg-color);
border: 1px solid var(--color--neutrals-2);
}
&__slider {
display: block;
width: 100%;
overflow-x: auto;
ul {
display: flex;
justify-content: flex-start;
align-items: center;
gap: var(--gap--4);
margin: 0 !important;
padding: 0;
list-style: none;
li {
flex: 0 0 auto; // 20%;
}
}
}
&__link {
display: flex;
justify-content: center;
align-items: center;
padding: var(--gap--4);
border-bottom: 5px solid transparent;
transition: border-bottom var(--zoomer--transition-speed) var(--zoomer--transition-ease);
img {
width: 100px;
transform: translateY(5px);
transition: transform var(--zoomer--transition-speed) var(--zoomer--transition-ease);
}
&:hover,
&.zoomer-thumbs__link--active {
border-bottom: 5px solid var(--color--theme, #000);
img {
transform: translateY(0);
}
}
&.zoomer-thumbs__link--active {
cursor: default;
}
}
}
.zoomer-visual {
position: relative;
display: block;
background-color: var(--zoomer--bg-color, white);
overflow: hidden;
opacity: 0;
transition: opacity var(--zoomer--transition-speed) var(--zoomer--transition-ease);
&--visible {
opacity: 1;
}
&__inner {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
cursor: move;
* {
pointer-events: none;
}
}
img {
flex: 0 0 100%;
display: block;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
object-fit: contain;
margin: 0;
user-select: none;
transform-origin: 50% 50%;
transform: translate(var(--zoomer-xperc, 0), var(--zoomer-yperc, 0)) scale(var(--zoomer-scale, .5));
.zoomer--fullscale & {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
max-width: unset;
max-height: unset;
object-fit: unset;
transform: translate(var(--zoomer-xperc, -50%), var(--zoomer-yperc, -50%)) scale(var(--zoomer-scale, .5));
}
}
}
:root {
--zoomer--bg-color: var(--color--neutrals-0);
--zoomer--border-size: var(--gap--4);
--zoomer--border-color: #F9F9F9;
--zoomer--header-width: var(--section--8); // before: 1000px
--zoomer--thumbs-width: var(--section--8); // before: 1200px
--zoomer--icon-size: 20px;
--zoomer--scale-size: 18px;
--zoomer--scale-width: min(180px, 20vw);
--zoomer--transition-ease: ease-out;
--zoomer--transition-speed: 150ms;
}
html.zoomeractive,
html.zoomeractive body {
overflow: hidden !important;
}
.zoomer {
display: none;
width: 100vw;
height: 100dvh;
margin: 0;
padding: 0;
background-color: var(--zoomer--bg-color, white);
border: var(--zoomer--border-size) solid var(--zoomer--border-color, white);
overflow: hidden;
&--visible {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 99999;
display: block;
}
&__inner {
display: flex;
justify-content: stretch;
align-items: stretch;
flex-direction: column;
height: 100%;
background: url(https://www.pioneerdj.com/Content/img/loaders/loading_fff.gif) no-repeat 50% 50% / 100px;
& > * {
flex: 0 1 auto;
}
.zoomer-header {
flex: 0 0 auto;
}
.zoomer-visual {
flex: 1 1 100%;
}
}
}
New version but use the original HTML