File: /home/httpd/vhosts/rajlaw.com.tw/httpdocs/wp-content/plugins/blockart-blocks/assets/js/dics.js
'use strict';
/*
* Dics: Definitive image comparison slider. A multiple image vanilla comparison slider.
*
* By Abel Cabeza Román, a Codictados developer
* Src: https://github.com/abelcabezaroman/definitive-image-comparison-slider
* Example: http://codictados.com/portfolio/definitive-image-comparison-slider-demo/
*/
/**
*
*/
/**
*
* @type {{container: null, filters: null, hideTexts: null, textPosition: string, linesOrientation: string, rotate: number, arrayBackgroundColorText: null, arrayColorText: null, linesColor: null}}
*/
let defaultOptions = {
container: null,
// **REQUIRED**: HTML container | `document.querySelector('.b-dics')` |
filters: null,
// Array of CSS string filters |`['blur(3px)', 'grayscale(1)', 'sepia(1)', 'saturate(3)']` |
hideTexts: null,
// Show text only when you hover the image container |`true`,`false`|
textPosition: 'top',
// Set the prefer text position |`'center'`,`'top'`, `'right'`, `'bottom'`, `'left'` |
linesOrientation: 'horizontal',
// Change the orientation of lines |`'horizontal'`,`'vertical'` |
rotate: 0,
// Rotate the image container (not too useful but it's a beatiful effect. String of rotate CSS rule) |`'45deg'`|
arrayBackgroundColorText: null,
// Change the bacground-color of sections texts with an array |`['#000000', '#FFFFFF']`|
arrayColorText: null,
// Change the color of texts with an array |`['#FFFFFF', '#000000']`|
linesColor: null, // Change the lines and arrows color |`'rgb(0,0,0)'`|
};
/**
*
* @param options
* @constructor
*/
let Dics = function (options) {
this.options = utils.extend({}, [defaultOptions, options], {
clearEmpty: true,
});
this.container = this.options.container;
if (this.container == null) {
console.error('Container element not found!');
} else {
this._setOrientation(this.options.linesOrientation, this.container);
this.images = this._getImages();
this.sliders = [];
this._activeSlider = 0;
this._load(this.images[0]);
}
};
/**
*
* @private
*/
Dics.prototype._load = function (firstImage, maxCounter = 100000) {
if (firstImage.naturalWidth) {
this._buidAfterFirstImageLoad(firstImage);
window.addEventListener('resize', () => {
this._setContainerWidth(firstImage);
this._resetSizes();
});
} else {
if (maxCounter > 0) {
maxCounter--;
setTimeout(() => {
this._load(firstImage, maxCounter);
}, 100);
} else {
console.error('error loading images');
}
}
};
/**
*
* @private
*/
Dics.prototype._buidAfterFirstImageLoad = function (firstImage) {
this._setContainerWidth(firstImage);
this._build();
this._setEvents();
};
/**
*
* @private
*/
Dics.prototype._setContainerWidth = function (firstImage) {
this.options.container.style.height = `${this._calcContainerHeight(
firstImage,
)}px`;
};
/**
*
* @private
*/
Dics.prototype._setOpacityContainerForLoading = function (opacity) {
this.options.container.style.opacity = opacity;
};
/**
* Reset sizes on window size change
* @private
*/
Dics.prototype._resetSizes = function () {
let dics = this;
let imagesLength = dics.images.length;
let initialImagesContainerWidth =
dics.container.getBoundingClientRect()[dics.config.sizeField] /
imagesLength;
const sections$$ = dics.container.querySelectorAll(
"[data-function='b-dics__section']",
);
for (let i = 0; i < sections$$.length; i++) {
let section$$ = sections$$[i];
section$$.style.flex = `0 0 ${initialImagesContainerWidth}px`;
section$$.querySelector('.b-dics__image').style[
this.config.positionField
] = `${i * -initialImagesContainerWidth}px`;
const slider$$ = section$$.querySelector('.b-dics__slider');
if (slider$$) {
slider$$.style[this.config.positionField] = `${
initialImagesContainerWidth * (i + 1)
}px`;
}
}
};
/**
* Build HTML
* @private
*/
Dics.prototype._build = function () {
let dics = this;
dics._applyGlobalClass(dics.options);
let imagesLength = dics.images.length;
let initialImagesContainerWidth =
dics.container.getBoundingClientRect()[dics.config.sizeField] /
imagesLength;
for (let i = 0; i < imagesLength; i++) {
let image = dics.images[i];
let section = dics._createElement('div', 'b-dics__section');
let imageContainer = dics._createElement('div', 'b-dics__image-container');
let slider = dics._createSlider(i, initialImagesContainerWidth);
dics._createAltText(image, i, imageContainer);
dics._applyFilter(image, i, dics.options.filters);
dics._rotate(image, imageContainer);
section.setAttribute('data-function', 'b-dics__section');
section.style.flex = `0 0 ${initialImagesContainerWidth}px`;
image.classList.add('b-dics__image');
section.appendChild(imageContainer);
imageContainer.appendChild(image);
if (i < imagesLength - 1) {
section.appendChild(slider);
}
dics.container.appendChild(section);
image.style[this.config.positionField] = `${
i * -initialImagesContainerWidth
}px`;
}
this.sections = this._getSections();
this._setOpacityContainerForLoading(1);
};
/**
*
* @returns {NodeListOf<SVGElementTagNameMap[string]> | NodeListOf<HTMLElementTagNameMap[string]> | NodeListOf<Element>}
* @private
*/
Dics.prototype._getImages = function () {
return this.container.querySelectorAll('img');
};
/**
*
* @returns {NodeListOf<SVGElementTagNameMap[string]> | NodeListOf<HTMLElementTagNameMap[string]> | NodeListOf<Element>}
* @private
*/
Dics.prototype._getSections = function () {
return this.container.querySelectorAll('[data-function="b-dics__section"]');
};
/**
*
* @param elementClass
* @param className
* @returns {HTMLElement | HTMLSelectElement | HTMLLegendElement | HTMLTableCaptionElement | HTMLTextAreaElement | HTMLModElement | HTMLHRElement | HTMLOutputElement | HTMLPreElement | HTMLEmbedElement | HTMLCanvasElement | HTMLFrameSetElement | HTMLMarqueeElement | HTMLScriptElement | HTMLInputElement | HTMLUnknownElement | HTMLMetaElement | HTMLStyleElement | HTMLObjectElement | HTMLTemplateElement | HTMLBRElement | HTMLAudioElement | HTMLIFrameElement | HTMLMapElement | HTMLTableElement | HTMLAnchorElement | HTMLMenuElement | HTMLPictureElement | HTMLParagraphElement | HTMLTableDataCellElement | HTMLTableSectionElement | HTMLQuoteElement | HTMLTableHeaderCellElement | HTMLProgressElement | HTMLLIElement | HTMLTableRowElement | HTMLFontElement | HTMLSpanElement | HTMLTableColElement | HTMLOptGroupElement | HTMLDataElement | HTMLDListElement | HTMLFieldSetElement | HTMLSourceElement | HTMLBodyElement | HTMLDirectoryElement | HTMLDivElement | HTMLUListElement | HTMLHtmlElement | HTMLAreaElement | HTMLMeterElement | HTMLAppletElement | HTMLFrameElement | HTMLOptionElement | HTMLImageElement | HTMLLinkElement | HTMLHeadingElement | HTMLSlotElement | HTMLVideoElement | HTMLBaseFontElement | HTMLTitleElement | HTMLButtonElement | HTMLHeadElement | HTMLParamElement | HTMLTrackElement | HTMLOListElement | HTMLDataListElement | HTMLLabelElement | HTMLFormElement | HTMLTimeElement | HTMLBaseElement}
* @private
*/
Dics.prototype._createElement = function (elementClass, className) {
let newElement = document.createElement(elementClass);
newElement.classList.add(className);
return newElement;
};
/**
* Set need DOM events
* @private
*/
Dics.prototype._setEvents = function () {
let dics = this;
dics._disableImageDrag();
dics._isGoingRight = null;
let oldx = 0;
let listener = function (event) {
let xPageCoord = event.pageX ? event.pageX : event.touches[0].pageX;
if (xPageCoord < oldx) {
dics._isGoingRight = false;
} else if (xPageCoord > oldx) {
dics._isGoingRight = true;
}
oldx = xPageCoord;
let position = dics._calcPosition(event);
let beforeSectionsWidth = dics._beforeSectionsWidth(
dics.sections,
dics.images,
dics._activeSlider,
);
let calcMovePixels = position - beforeSectionsWidth;
dics.sliders[dics._activeSlider].style[
dics.config.positionField
] = `${position}px`;
dics._pushSections(calcMovePixels, position);
};
dics.container.addEventListener('click', listener);
for (let i = 0; i < dics.sliders.length; i++) {
let slider = dics.sliders[i];
utils.setMultiEvents(slider, ['mousedown', 'touchstart'], function (event) {
dics._activeSlider = i;
dics._clickPosition = dics._calcPosition(event);
slider.classList.add('b-dics__slider--active');
utils.setMultiEvents(
dics.container,
['mousemove', 'touchmove'],
listener,
);
});
}
let listener2 = function () {
let activeElements = dics.container.querySelectorAll(
'.b-dics__slider--active',
);
for (let activeElement of activeElements) {
activeElement.classList.remove('b-dics__slider--active');
utils.removeMultiEvents(
dics.container,
['mousemove', 'touchmove'],
listener,
);
}
};
utils.setMultiEvents(document.body, ['mouseup', 'touchend'], listener2);
};
/**
*
* @param sections
* @param images
* @param activeSlider
* @returns {number}
* @private
*/
Dics.prototype._beforeSectionsWidth = function (
sections,
images,
activeSlider,
) {
let width = 0;
for (let i = 0; i < sections.length; i++) {
let section = sections[i];
if (i !== activeSlider) {
width += section.getBoundingClientRect()[this.config.sizeField];
} else {
return width;
}
}
};
/**
*
* @returns {number}
* @private
*/
Dics.prototype._calcContainerHeight = function (firstImage) {
let imgHeight = firstImage.naturalHeight;
let imgWidth = firstImage.naturalWidth;
let containerWidth = this.options.container.getBoundingClientRect().width;
return (containerWidth / imgWidth) * imgHeight;
};
/**
*
* @param sections
* @param images
* @private
*/
Dics.prototype._setLeftToImages = function (sections, images) {
let size = 0;
for (let i = 0; i < images.length; i++) {
let image = images[i];
image.style[this.config.positionField] = `-${size}px`;
size += sections[i].getBoundingClientRect()[this.config.sizeField];
this.sliders[i].style[this.config.positionField] = `${size}px`;
}
};
/**
*
* @private
*/
Dics.prototype._disableImageDrag = function () {
for (let i = 0; i < this.images.length; i++) {
this.sliders[i].addEventListener('dragstart', function (e) {
e.preventDefault();
});
this.images[i].addEventListener('dragstart', function (e) {
e.preventDefault();
});
}
};
/**
*
* @param image
* @param index
* @param filters
* @private
*/
Dics.prototype._applyFilter = function (image, index, filters) {
if (filters) {
image.style.filter = filters[index];
}
};
/**
*
* @param options
* @private
*/
Dics.prototype._applyGlobalClass = function (options) {
let container = options.container;
if (options.hideTexts) {
container.classList.add('b-dics--hide-texts');
}
if (options.linesOrientation === 'vertical') {
container.classList.add('b-dics--vertical');
}
if (options.textPosition === 'center') {
container.classList.add('b-dics--tp-center');
} else if (options.textPosition === 'bottom') {
container.classList.add('b-dics--tp-bottom');
} else if (options.textPosition === 'bottom-left') {
container.classList.add('b-dics--tp-bottom-left');
} else if (options.textPosition === 'left') {
container.classList.add('b-dics--tp-left');
} else if (options.textPosition === 'right') {
container.classList.add('b-dics--tp-right');
}
};
Dics.prototype._createSlider = function (i, initialImagesContainerWidth) {
let slider = this._createElement('div', 'b-dics__slider');
let svg = `
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5330_2718)">
<path d="M16.622 9.42186L16.5593 18.6262L22.6907 14.0656L16.622 9.42186Z" fill="white"/>
</g>
<g clip-path="url(#clip1_5330_2718)">
<path d="M11.4594 18.6596L11.5222 9.45525L5.39074 14.0159L11.4594 18.6596Z" fill="white"/>
</g>
<circle cx="14" cy="14" r="12.8333" stroke="white" stroke-width="2.33333"/>
<defs>
<clipPath id="clip0_5330_2718">
<rect width="10.0475" height="7.06798" fill="white" transform="translate(23.0681 9.00047) rotate(90.3904)"/>
</clipPath>
<clipPath id="clip1_5330_2718">
<rect width="10.0475" height="7.06798" fill="white" transform="translate(4.93185 18.9995) rotate(-89.6096)"/>
</clipPath>
</defs>
</svg>
`;
// Append the SVG to the slider
slider.innerHTML = svg;
if (this.options.linesColor) {
slider.style.color = this.options.linesColor;
}
slider.style[this.config.positionField] = `${
initialImagesContainerWidth * (i + 1)
}px`;
this.sliders.push(slider);
return slider;
};
/**
*
* @param image
* @param i
* @param imageContainer
* @private
*/
Dics.prototype._createAltText = function (image, i, imageContainer) {
let textContent = image.getAttribute('alt');
if (textContent) {
let text = this._createElement('p', 'b-dics__text');
if (this.options.arrayBackgroundColorText) {
text.style.backgroundColor = this.options.arrayBackgroundColorText[i];
}
if (this.options.arrayColorText) {
text.style.color = this.options.arrayColorText[i];
}
text.appendChild(document.createTextNode(textContent));
imageContainer.appendChild(text);
}
};
/**
*
* @param image
* @param imageContainer
* @private
*/
Dics.prototype._rotate = function (image, imageContainer) {
image.style.rotate = `-${this.options.rotate}`;
imageContainer.style.rotate = this.options.rotate;
};
/**
*
* @private
*/
Dics.prototype._removeActiveElements = function () {
let activeElements = Dics.container.querySelectorAll(
'.b-dics__slider--active',
);
for (let activeElement of activeElements) {
activeElement.classList.remove('b-dics__slider--active');
utils.removeMultiEvents(
Dics.container,
['mousemove', 'touchmove'],
Dics.prototype._removeActiveElements,
);
}
};
/**
*
* @param linesOrientation
* @private
*/
Dics.prototype._setOrientation = function (linesOrientation) {
this.config = {};
if (linesOrientation === 'vertical') {
this.config.offsetSizeField = 'offsetHeight';
this.config.offsetPositionField = 'offsetTop';
this.config.sizeField = 'height';
this.config.positionField = 'top';
this.config.clientField = 'clientY';
this.config.pageField = 'pageY';
} else {
this.config.offsetSizeField = 'offsetWidth';
this.config.offsetPositionField = 'offsetLeft';
this.config.sizeField = 'width';
this.config.positionField = 'left';
this.config.clientField = 'clientX';
this.config.pageField = 'pageX';
}
};
/**
*
* @param event
* @returns {number}
* @private
*/
Dics.prototype._calcPosition = function (event) {
let containerCoords = this.container.getBoundingClientRect();
let pixel = !isNaN(event[this.config.clientField])
? event[this.config.clientField]
: event.touches[0][this.config.clientField];
return containerCoords[this.config.positionField] < pixel
? pixel - containerCoords[this.config.positionField]
: 0;
};
/**
*
* @private
*/
Dics.prototype._pushSections = function (calcMovePixels, position) {
// if (this._rePosUnderActualSections(position)) {
this._setFlex(position, this._isGoingRight);
let section = this.sections[this._activeSlider];
let postActualSection = this.sections[this._activeSlider + 1];
let sectionWidth =
postActualSection.getBoundingClientRect()[this.config.sizeField] -
(calcMovePixels -
this.sections[this._activeSlider].getBoundingClientRect()[
this.config.sizeField
]);
section.style.flex =
this._isGoingRight === true
? `2 0 ${calcMovePixels}px`
: `1 1 ${calcMovePixels}px`;
postActualSection.style.flex =
this._isGoingRight === true
? ` ${sectionWidth}px`
: `2 0 ${sectionWidth}px`;
this._setLeftToImages(this.sections, this.images); // }
};
/**
*
* @private
*/
Dics.prototype._setFlex = function (position, isGoingRight) {
let beforeSumSectionsSize = 0;
for (let i = 0; i < this.sections.length; i++) {
let section = this.sections[i];
const sectionSize = section.getBoundingClientRect()[this.config.sizeField];
beforeSumSectionsSize += sectionSize;
if (
(isGoingRight &&
position > beforeSumSectionsSize - sectionSize &&
i > this._activeSlider) ||
(!isGoingRight &&
position < beforeSumSectionsSize &&
i < this._activeSlider)
) {
section.style.flex = `1 100 ${sectionSize}px`;
} else {
section.style.flex = `0 0 ${sectionSize}px`;
}
}
};
/**
*
* @type {{extend: (function(*=, *, *): *), setMultiEvents: setMultiEvents, removeMultiEvents: removeMultiEvents, getConstructor: (function(*=): string)}}
*/
let utils = {
/**
* Native extend object
* @param target
* @param objects
* @param options
* @returns {*}
*/
extend: function (target, objects, options) {
for (let object in objects) {
if (objects.hasOwnProperty(object)) {
recursiveMerge(target, objects[object]);
}
}
function recursiveMerge(target, object) {
for (let property in object) {
if (object.hasOwnProperty(property)) {
let current = object[property];
if (utils.getConstructor(current) === 'Object') {
if (!target[property]) {
target[property] = {};
}
recursiveMerge(target[property], current);
} else {
// clearEmpty
if (options.clearEmpty) {
if (current == null) {
continue;
}
}
target[property] = current;
}
}
}
}
return target;
},
/**
* Set Multi addEventListener
* @param element
* @param events
* @param func
*/
setMultiEvents: function (element, events, func) {
for (let i = 0; i < events.length; i++) {
element.addEventListener(events[i], func);
}
},
/**
*
* @param element
* @param events
* @param func
*/
removeMultiEvents: function (element, events, func) {
for (let i = 0; i < events.length; i++) {
element.removeEventListener(events[i], func, false);
}
},
/**
* Get object constructor
* @param object
* @returns {string}
*/
getConstructor: function (object) {
return Object.prototype.toString.call(object).slice(8, -1);
},
};