compare-images-slider
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -1,4 +0,16 @@ | ||
/* compare-images-slider v1.0.0 | https://stamat.github.io/compare-images-slider/ | MIT License */ | ||
/* compare-images-slider v1.0.1 | https://stamat.github.io/compare-images-slider/ | MIT License */ | ||
(() => { | ||
// node_modules/book-of-spells/src/helpers.mjs | ||
function shallowMerge(target, source) { | ||
for (const key in source) { | ||
target[key] = source[key]; | ||
} | ||
return target; | ||
} | ||
function isObject(o) { | ||
return typeof o === "object" && !Array.isArray(o) && o !== null; | ||
} | ||
function isFunction(o) { | ||
return typeof o === "function"; | ||
} | ||
function percentage(num, total) { | ||
@@ -10,19 +22,55 @@ if (!num || !total || Number.isNaN(num) || Number.isNaN(total)) | ||
// src/scripts/compare-images-slider.js | ||
function onDrag(element, callback) { | ||
let startX = 0; | ||
let startY = 0; | ||
let endX = 0; | ||
let endY = 0; | ||
// node_modules/book-of-spells/src/dom.mjs | ||
function drag(element, opts) { | ||
if (!element || !(element instanceof Element)) | ||
return; | ||
if (element.getAttribute("drag-enabled") === "true") | ||
return; | ||
let x = 0; | ||
let y = 0; | ||
let prevX = 0; | ||
let prevY = 0; | ||
let velocityX = 0; | ||
let velocityY = 0; | ||
let dragging = false; | ||
let rect = element.getBoundingClientRect(); | ||
let rect = null; | ||
let inertiaId = null; | ||
const options = { | ||
inertia: false, | ||
bounce: false, | ||
friction: 0.9, | ||
bounceFactor: 0.2, | ||
callback: null, | ||
preventDefaultTouch: true | ||
}; | ||
if (isFunction(opts)) { | ||
options.callback = opts; | ||
} else if (isObject(opts)) { | ||
shallowMerge(options, opts); | ||
} | ||
options.friction = Math.abs(options.friction); | ||
options.bounceFactor = Math.abs(options.bounceFactor); | ||
element.setAttribute("drag-enabled", "true"); | ||
element.setAttribute("dragging", "false"); | ||
const calcPageRelativeRect = function() { | ||
const origRect = element.getBoundingClientRect(); | ||
const rect2 = { | ||
top: origRect.top + window.scrollY, | ||
left: origRect.left + window.scrollX, | ||
width: origRect.width, | ||
height: origRect.height | ||
}; | ||
return rect2; | ||
}; | ||
rect = calcPageRelativeRect(); | ||
const handleStart = function(e) { | ||
const carrier = e.type === "touchstart" ? e.touches[0] : e; | ||
startX = carrier.clientX; | ||
startY = carrier.clientY; | ||
setXY(e); | ||
dragging = true; | ||
rect = element.getBoundingClientRect(); | ||
const xPercentage = percentage(startX - rect.left, rect.width); | ||
const yPercentage = percentage(startY - rect.top, rect.height); | ||
const event = new CustomEvent("dragstart", { detail: { target: element, startX, startY, rect, xPercentage, yPercentage } }); | ||
rect = calcPageRelativeRect(); | ||
element.setAttribute("dragging", "true"); | ||
if (inertiaId) { | ||
cancelAnimationFrame(inertiaId); | ||
inertiaId = null; | ||
} | ||
const event = new CustomEvent("dragstart", { detail: getDetail() }); | ||
element.dispatchEvent(event); | ||
@@ -33,49 +81,97 @@ }; | ||
return; | ||
const carrier = e.type === "touchmove" ? e.touches[0] : e; | ||
endX = carrier.clientX; | ||
endY = carrier.clientY; | ||
handleDragGesture(); | ||
setXY(e); | ||
velocityX = x - prevX; | ||
velocityY = y - prevY; | ||
const detail = getDetail(); | ||
if (options.callback) | ||
options.callback(detail); | ||
const event = new CustomEvent("drag", { detail }); | ||
element.dispatchEvent(event); | ||
}; | ||
const handleEnd = function() { | ||
dragging = false; | ||
const event = new CustomEvent("dragend", { detail: { target: element, startX, startY, rect, endX, endY } }); | ||
element.setAttribute("dragging", "false"); | ||
if (options.inertia) | ||
inertiaId = requestAnimationFrame(inertia); | ||
const event = new CustomEvent("dragend", { detail: getDetail() }); | ||
element.dispatchEvent(event); | ||
}; | ||
const handleDragGesture = function() { | ||
const deltaX = endX - startX; | ||
const deltaY = endY - startY; | ||
const left = deltaX < 0; | ||
const up = deltaY < 0; | ||
const xPercentage = percentage(endX - rect.left, rect.width); | ||
const yPercentage = percentage(endY - rect.top, rect.height); | ||
const setXY = function(e) { | ||
const carrier = e.touches ? e.touches[0] : e; | ||
if (e.touches && options.preventDefaultTouch) | ||
e.preventDefault(); | ||
prevX = x; | ||
prevY = y; | ||
x = carrier.pageX; | ||
y = carrier.pageY; | ||
}; | ||
const getDetail = function() { | ||
const relativeX = x - rect.left; | ||
const relativeY = y - rect.top; | ||
const xPercentage = percentage(relativeX, rect.width); | ||
const yPercentage = percentage(relativeY, rect.height); | ||
const detail = { | ||
target: element, | ||
deltaX, | ||
deltaY, | ||
startX, | ||
startY, | ||
endX, | ||
endY, | ||
horizontalDirection: left ? "left" : "right", | ||
verticalDirection: up ? "up" : "down", | ||
x, | ||
y, | ||
relativeX, | ||
relativeY, | ||
xPercentage, | ||
yPercentage | ||
yPercentage, | ||
velocityX, | ||
velocityY, | ||
prevX, | ||
prevY | ||
}; | ||
if (xPercentage < 0) { | ||
if (xPercentage < 0) | ||
detail.xPercentage = 0; | ||
} | ||
if (xPercentage > 100) { | ||
if (xPercentage > 100) | ||
detail.xPercentage = 100; | ||
} | ||
if (yPercentage < 0) { | ||
if (yPercentage < 0) | ||
detail.yPercentage = 0; | ||
} | ||
if (yPercentage > 100) { | ||
if (yPercentage > 100) | ||
detail.yPercentage = 100; | ||
return detail; | ||
}; | ||
const inertia = function() { | ||
x += velocityX; | ||
y += velocityY; | ||
velocityX *= options.friction; | ||
velocityY *= options.friction; | ||
if (options.bounce) { | ||
if (x < rect.left) { | ||
x = rect.left; | ||
velocityX *= -options.bounceFactor; | ||
} | ||
if (x > rect.width + rect.left) { | ||
x = rect.width + rect.left; | ||
velocityX *= -options.bounceFactor; | ||
} | ||
if (y < rect.top) { | ||
y = rect.top; | ||
velocityY *= -options.bounceFactor; | ||
} | ||
if (y > rect.height + rect.top) { | ||
y = rect.height + rect.top; | ||
velocityY *= -options.bounceFactor; | ||
} | ||
} | ||
if (callback) { | ||
callback(detail); | ||
if (Math.abs(velocityX) < 0.1) | ||
velocityX = 0; | ||
if (Math.abs(velocityY) < 0.1) | ||
velocityY = 0; | ||
const detail = getDetail(); | ||
if (velocityX !== 0 || velocityY !== 0) { | ||
if (options.callback) | ||
options.callback(detail); | ||
const event = new CustomEvent("draginertia", { detail }); | ||
element.dispatchEvent(event); | ||
inertiaId = requestAnimationFrame(inertia); | ||
} else { | ||
inertiaId = null; | ||
if (options.callback) | ||
options.callback(detail); | ||
const event = new CustomEvent("draginertiaend", { detail }); | ||
element.dispatchEvent(event); | ||
} | ||
const event = new CustomEvent("drag", { detail }); | ||
element.dispatchEvent(event); | ||
}; | ||
@@ -96,5 +192,11 @@ element.addEventListener("mousedown", handleStart); | ||
element.removeEventListener("touchend", handleEnd); | ||
if (inertiaId) { | ||
cancelAnimationFrame(inertiaId); | ||
inertiaId = null; | ||
} | ||
} | ||
}; | ||
} | ||
// src/scripts/compare-images-slider.js | ||
var CompareImagesSlider = class { | ||
@@ -106,2 +208,17 @@ constructor(element, options) { | ||
this.handle = this.element.querySelector(".handle"); | ||
this.options = { | ||
inertia: false, | ||
bounce: false, | ||
friction: 0.9, | ||
bounceFactor: 0.1, | ||
onlyHandle: true, | ||
vertical: false | ||
}; | ||
if (options) | ||
shallowMerge(this.options, options); | ||
this.checkAndApplyAttribute("vertical"); | ||
if (this.options.vertical && !(this.element.dataset.vertical || this.element.hasAttribute("vertical"))) | ||
this.element.setAttribute("vertical", ""); | ||
if (this.options.onlyHandle) | ||
this.options.preventDefaultTouch = false; | ||
window.addEventListener("resize", () => { | ||
@@ -111,6 +228,44 @@ requestAnimationFrame(this.setupSecondImage.bind(this)); | ||
this.setupSecondImage(); | ||
this.drag = onDrag(this.element); | ||
this.element.addEventListener("dragstart", this.updateVisibleHandler.bind(this)); | ||
this.element.addEventListener("drag", this.updateVisibleHandler.bind(this)); | ||
this.drag = drag(this.element, this.options); | ||
this.handleDragBound = false; | ||
this.boundUpdateVisibleHandler = this.updateVisibleHandler.bind(this); | ||
const preventDefault = (e) => { | ||
if (this.handleDragBound) | ||
e.preventDefault(); | ||
}; | ||
const addEventListeners = () => { | ||
if (this.handleDragBound) | ||
return; | ||
this.handleDragBound = true; | ||
this.element.addEventListener("dragstart", this.boundUpdateVisibleHandler); | ||
this.element.addEventListener("drag", this.boundUpdateVisibleHandler); | ||
this.element.addEventListener("draginertia", this.boundUpdateVisibleHandler); | ||
this.element.addEventListener("draginertiaend", () => { | ||
this.element.removeEventListener("draginertia", this.boundUpdateVisibleHandler); | ||
}); | ||
this.element.addEventListener("touchstart", preventDefault); | ||
}; | ||
const removeEventListeners = () => { | ||
if (!this.handleDragBound) | ||
return; | ||
this.handleDragBound = false; | ||
this.element.removeEventListener("dragstart", this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener("drag", this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener("touchstart", preventDefault); | ||
}; | ||
if (this.options.onlyHandle) { | ||
this.handle.addEventListener("mousedown", addEventListeners); | ||
this.handle.addEventListener("touchstart", addEventListeners); | ||
document.addEventListener("mouseup", removeEventListeners); | ||
document.addEventListener("touchend", removeEventListeners); | ||
} else { | ||
this.element.addEventListener("dragstart", this.boundUpdateVisibleHandler); | ||
this.element.addEventListener("drag", this.boundUpdateVisibleHandler); | ||
this.element.addEventListener("draginertia", this.boundUpdateVisibleHandler); | ||
} | ||
} | ||
checkAndApplyAttribute(attribute) { | ||
if (this.element.dataset[attribute] || this.element.hasAttribute(attribute)) | ||
this.options[attribute] = true; | ||
} | ||
setupSecondImage() { | ||
@@ -121,2 +276,7 @@ const width = this.element.offsetWidth + "px"; | ||
updateVisibleHandler(e) { | ||
if (this.options.vertical) { | ||
this.frame.style.height = e.detail.yPercentage + "%"; | ||
this.handle.style.top = e.detail.yPercentage + "%"; | ||
return; | ||
} | ||
this.frame.style.width = e.detail.xPercentage + "%"; | ||
@@ -127,4 +287,5 @@ this.handle.style.left = e.detail.xPercentage + "%"; | ||
this.drag.destroy(); | ||
this.element.removeEventListener("dragstart", this.updateVisibleHandler.bind(this)); | ||
this.element.removeEventListener("drag", this.updateVisibleHandler.bind(this)); | ||
this.element.removeEventListener("dragstart", this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener("drag", this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener("draginertia", this.boundUpdateVisibleHandler); | ||
} | ||
@@ -131,0 +292,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
/* compare-images-slider v1.0.0 | https://stamat.github.io/compare-images-slider/ | MIT License */ | ||
(()=>{function u(e,s){return!e||!s||Number.isNaN(e)||Number.isNaN(s)?0:e/s*100}function w(e,s){let r=0,o=0,d=0,c=0,m=!1,n=e.getBoundingClientRect();const v=function(t){const i=t.type==="touchstart"?t.touches[0]:t;r=i.clientX,o=i.clientY,m=!0,n=e.getBoundingClientRect();const f=u(r-n.left,n.width),p=u(o-n.top,n.height),h=new CustomEvent("dragstart",{detail:{target:e,startX:r,startY:o,rect:n,xPercentage:f,yPercentage:p}});e.dispatchEvent(h)},g=function(t){if(!m)return;const i=t.type==="touchmove"?t.touches[0]:t;d=i.clientX,c=i.clientY,y()},l=function(){m=!1;const t=new CustomEvent("dragend",{detail:{target:e,startX:r,startY:o,rect:n,endX:d,endY:c}});e.dispatchEvent(t)},y=function(){const t=d-r,i=c-o,f=t<0,p=i<0,h=u(d-n.left,n.width),E=u(c-n.top,n.height),a={target:e,deltaX:t,deltaY:i,startX:r,startY:o,endX:d,endY:c,horizontalDirection:f?"left":"right",verticalDirection:p?"up":"down",xPercentage:h,yPercentage:E};h<0&&(a.xPercentage=0),h>100&&(a.xPercentage=100),E<0&&(a.yPercentage=0),E>100&&(a.yPercentage=100),s&&s(a);const b=new CustomEvent("drag",{detail:a});e.dispatchEvent(b)};return e.addEventListener("mousedown",v),e.addEventListener("mousemove",g),e.addEventListener("mouseup",l),e.addEventListener("touchstart",v),e.addEventListener("touchmove",g),e.addEventListener("touchend",l),{destroy:function(){e.removeEventListener("mousedown",v),e.removeEventListener("mousemove",g),e.removeEventListener("mouseup",l),e.removeEventListener("touchstart",v),e.removeEventListener("touchmove",g),e.removeEventListener("touchend",l)}}}var L=class{constructor(e,s){this.element=e,this.frame=this.element.querySelector(".frame"),this.second=this.frame.querySelector(":scope > img"),this.handle=this.element.querySelector(".handle"),window.addEventListener("resize",()=>{requestAnimationFrame(this.setupSecondImage.bind(this))}),this.setupSecondImage(),this.drag=w(this.element),this.element.addEventListener("dragstart",this.updateVisibleHandler.bind(this)),this.element.addEventListener("drag",this.updateVisibleHandler.bind(this))}setupSecondImage(){const e=this.element.offsetWidth+"px";this.second.style.width=e}updateVisibleHandler(e){this.frame.style.width=e.detail.xPercentage+"%",this.handle.style.left=e.detail.xPercentage+"%"}destroy(){this.drag.destroy(),this.element.removeEventListener("dragstart",this.updateVisibleHandler.bind(this)),this.element.removeEventListener("drag",this.updateVisibleHandler.bind(this))}};window.CompareImagesSlider||(window.CompareImagesSlider=L,document.dispatchEvent(new CustomEvent("CompareImagesSliderLoaded")))})(); | ||
/* compare-images-slider v1.0.1 | https://stamat.github.io/compare-images-slider/ | MIT License */ | ||
(()=>{function y(e,s){for(const a in s)e[a]=s[a];return e}function F(e){return typeof e=="object"&&!Array.isArray(e)&&e!==null}function D(e){return typeof e=="function"}function w(e,s){return!e||!s||Number.isNaN(e)||Number.isNaN(s)?0:e/s*100}function U(e,s){if(!e||!(e instanceof Element)||e.getAttribute("drag-enabled")==="true")return;let a=0,o=0,h=0,u=0,d=0,l=0,E=!1,i=null,c=null;const n={inertia:!1,bounce:!1,friction:.9,bounceFactor:.2,callback:null,preventDefaultTouch:!0};D(s)?n.callback=s:F(s)&&y(n,s),n.friction=Math.abs(n.friction),n.bounceFactor=Math.abs(n.bounceFactor),e.setAttribute("drag-enabled","true"),e.setAttribute("dragging","false");const A=function(){const t=e.getBoundingClientRect();return{top:t.top+window.scrollY,left:t.left+window.scrollX,width:t.width,height:t.height}};i=A();const g=function(t){H(t),E=!0,i=A(),e.setAttribute("dragging","true"),c&&(cancelAnimationFrame(c),c=null);const r=new CustomEvent("dragstart",{detail:m()});e.dispatchEvent(r)},b=function(t){if(!E)return;H(t),d=a-h,l=o-u;const r=m();n.callback&&n.callback(r);const f=new CustomEvent("drag",{detail:r});e.dispatchEvent(f)},p=function(){E=!1,e.setAttribute("dragging","false"),n.inertia&&(c=requestAnimationFrame(V));const t=new CustomEvent("dragend",{detail:m()});e.dispatchEvent(t)},H=function(t){const r=t.touches?t.touches[0]:t;t.touches&&n.preventDefaultTouch&&t.preventDefault(),h=a,u=o,a=r.pageX,o=r.pageY},m=function(){const t=a-i.left,r=o-i.top,f=w(t,i.width),L=w(r,i.height),v={target:e,x:a,y:o,relativeX:t,relativeY:r,xPercentage:f,yPercentage:L,velocityX:d,velocityY:l,prevX:h,prevY:u};return f<0&&(v.xPercentage=0),f>100&&(v.xPercentage=100),L<0&&(v.yPercentage=0),L>100&&(v.yPercentage=100),v},V=function(){a+=d,o+=l,d*=n.friction,l*=n.friction,n.bounce&&(a<i.left&&(a=i.left,d*=-n.bounceFactor),a>i.width+i.left&&(a=i.width+i.left,d*=-n.bounceFactor),o<i.top&&(o=i.top,l*=-n.bounceFactor),o>i.height+i.top&&(o=i.height+i.top,l*=-n.bounceFactor)),Math.abs(d)<.1&&(d=0),Math.abs(l)<.1&&(l=0);const t=m();if(d!==0||l!==0){n.callback&&n.callback(t);const r=new CustomEvent("draginertia",{detail:t});e.dispatchEvent(r),c=requestAnimationFrame(V)}else{c=null,n.callback&&n.callback(t);const r=new CustomEvent("draginertiaend",{detail:t});e.dispatchEvent(r)}};return e.addEventListener("mousedown",g),e.addEventListener("mousemove",b),e.addEventListener("mouseup",p),e.addEventListener("touchstart",g),e.addEventListener("touchmove",b),e.addEventListener("touchend",p),{destroy:function(){e.removeEventListener("mousedown",g),e.removeEventListener("mousemove",b),e.removeEventListener("mouseup",p),e.removeEventListener("touchstart",g),e.removeEventListener("touchmove",b),e.removeEventListener("touchend",p),c&&(cancelAnimationFrame(c),c=null)}}}var k=class{constructor(e,s){this.element=e,this.frame=this.element.querySelector(".frame"),this.second=this.frame.querySelector(":scope > img"),this.handle=this.element.querySelector(".handle"),this.options={inertia:!1,bounce:!1,friction:.9,bounceFactor:.1,onlyHandle:!0,vertical:!1},s&&y(this.options,s),this.checkAndApplyAttribute("vertical"),this.options.vertical&&!(this.element.dataset.vertical||this.element.hasAttribute("vertical"))&&this.element.setAttribute("vertical",""),this.options.onlyHandle&&(this.options.preventDefaultTouch=!1),window.addEventListener("resize",()=>{requestAnimationFrame(this.setupSecondImage.bind(this))}),this.setupSecondImage(),this.drag=U(this.element,this.options),this.handleDragBound=!1,this.boundUpdateVisibleHandler=this.updateVisibleHandler.bind(this);const a=u=>{this.handleDragBound&&u.preventDefault()},o=()=>{this.handleDragBound||(this.handleDragBound=!0,this.element.addEventListener("dragstart",this.boundUpdateVisibleHandler),this.element.addEventListener("drag",this.boundUpdateVisibleHandler),this.element.addEventListener("draginertia",this.boundUpdateVisibleHandler),this.element.addEventListener("draginertiaend",()=>{this.element.removeEventListener("draginertia",this.boundUpdateVisibleHandler)}),this.element.addEventListener("touchstart",a))},h=()=>{this.handleDragBound&&(this.handleDragBound=!1,this.element.removeEventListener("dragstart",this.boundUpdateVisibleHandler),this.element.removeEventListener("drag",this.boundUpdateVisibleHandler),this.element.removeEventListener("touchstart",a))};this.options.onlyHandle?(this.handle.addEventListener("mousedown",o),this.handle.addEventListener("touchstart",o),document.addEventListener("mouseup",h),document.addEventListener("touchend",h)):(this.element.addEventListener("dragstart",this.boundUpdateVisibleHandler),this.element.addEventListener("drag",this.boundUpdateVisibleHandler),this.element.addEventListener("draginertia",this.boundUpdateVisibleHandler))}checkAndApplyAttribute(e){(this.element.dataset[e]||this.element.hasAttribute(e))&&(this.options[e]=!0)}setupSecondImage(){const e=this.element.offsetWidth+"px";this.second.style.width=e}updateVisibleHandler(e){if(this.options.vertical){this.frame.style.height=e.detail.yPercentage+"%",this.handle.style.top=e.detail.yPercentage+"%";return}this.frame.style.width=e.detail.xPercentage+"%",this.handle.style.left=e.detail.xPercentage+"%"}destroy(){this.drag.destroy(),this.element.removeEventListener("dragstart",this.boundUpdateVisibleHandler),this.element.removeEventListener("drag",this.boundUpdateVisibleHandler),this.element.removeEventListener("draginertia",this.boundUpdateVisibleHandler)}};window.CompareImagesSlider||(window.CompareImagesSlider=k,document.dispatchEvent(new CustomEvent("CompareImagesSliderLoaded")))})(); |
{ | ||
"name": "compare-images-slider", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "A simple slider for comparing two images.", | ||
@@ -34,4 +34,4 @@ "main": "src/scripts/compare-images-slider.js", | ||
"dependencies": { | ||
"book-of-spells": "^1.0.22" | ||
"book-of-spells": "^1.0.31" | ||
} | ||
} |
@@ -54,11 +54,23 @@ # ↔️ Compare Images Slider [](https://www.npmjs.com/package/compare-images-slider) [](https://github.com/stamat/compare-images-slider/blob/main/LICENSE) | ||
Coming soon... | ||
```javascript | ||
// Default options | ||
const options = { | ||
inertia: false, // inertia physics, you can flick the handle | ||
friction: 0.9, // the friction of the inertia | ||
bounce: false, // will bounce back when intertia is enabled and the boundary is reached | ||
bounceFactor: 0.1, // the force of the bounce | ||
vertical: false // vertical slider | ||
onlyHandle: true // only the handle is draggable | ||
} | ||
new CompareImagesSlider(slider, options); | ||
``` | ||
## TODO: | ||
- [ ] Add options | ||
- [ ] Scroll block on drag | ||
- [ ] Vertical option | ||
- [ ] Add factory class, migrate the general factory class to the book of spells prior to that | ||
- [ ] Refactor onDrag and move it to the book of spells | ||
- [x] Add options | ||
- [x] Scroll block on drag | ||
- [x] Vertical option | ||
- [ ] Add factory class, migrate the general factory class to the book of spells prior to that? Better turn this into custom element! | ||
- [x] Refactor onDrag and move it to the book of spells | ||
- [ ] Add initialized state, don't initialize twice | ||
@@ -65,0 +77,0 @@ |
@@ -8,28 +8,48 @@ --- | ||
<div class="container mb-64"> | ||
<h1>{{ site.title }}</h1> | ||
<p class="p1">{{ site.description }}</p> | ||
<div class="js-compare-images-slider compare-images-slider"> | ||
<img width="1680" height="1120" src="{{ relativePathPrefix }}dist/assets/img.jpg" loading="lazy" alt=""> | ||
<div class="frame"> | ||
<img width="1680" height="1120" src="{{ relativePathPrefix }}dist/assets/img-alt.jpg" loading="lazy" alt=""> | ||
</div> | ||
<span class="handle"></span> | ||
<h1 class="mb-0 mt-lg-128 mt-80">{{ site.title }}</h1> | ||
<p class="p1 mb-64 mt-16 text-gray">{{ site.description }}</p> | ||
<div class="js-compare-images-slider compare-images-slider"> | ||
<img width="1680" height="1120" src="{{ relativePathPrefix }}dist/assets/img.jpg" loading="lazy" alt=""> | ||
<div class="frame"> | ||
<img width="1680" height="1120" src="{{ relativePathPrefix }}dist/assets/img-alt.jpg" loading="lazy" alt=""> | ||
</div> | ||
<span class="handle"></span> | ||
</div> | ||
<script> | ||
const slider = document.querySelector('.js-compare-images-slider'); | ||
if (window.CompareImagesSlider) { | ||
const compareImagesSlider = new CompareImagesSlider(slider); | ||
} else { | ||
document.addEventListener('CompareImagesSliderLoaded', function() { | ||
const compareImagesSlider = new CompareImagesSlider(slider); | ||
}); | ||
Photo by <a href="https://unsplash.com/@necone?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Nenad Radojčić</a> on <a href="https://unsplash.com/photos/gray-concrete-building-under-white-sky-during-daytime-JBm5eNo6B4E?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a> | ||
<div class="js-compare-images-slider compare-images-slider" vertical> | ||
<img width="1680" height="1120" src="{{ relativePathPrefix }}dist/assets/img2.jpg" loading="lazy" alt=""> | ||
<div class="frame"> | ||
<img width="1680" height="1120" src="{{ relativePathPrefix }}dist/assets/img2-alt.jpg" loading="lazy" alt=""> | ||
</div> | ||
<span class="handle"></span> | ||
</div> | ||
Photo by <a href="https://unsplash.com/@valentinsalja?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Valentin Salja</a> on <a href="https://unsplash.com/photos/withered-tree-covered-in-snow-AqcD0Q1JLpE?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a> | ||
<script> | ||
const sliders = document.querySelectorAll('.js-compare-images-slider'); | ||
const options = { | ||
inertia: true | ||
} | ||
if (window.CompareImagesSlider) { | ||
for (let i = 0; i < sliders.length; i++) { | ||
const compareImagesSlider = new CompareImagesSlider(sliders[i], options); | ||
} | ||
</script> | ||
} else { | ||
document.addEventListener('CompareImagesSliderLoaded', function() { | ||
for (let i = 0; i < sliders.length; i++) { | ||
const compareImagesSlider = new CompareImagesSlider(sliders[i], options); | ||
} | ||
}); | ||
} | ||
</script> | ||
Photo by <a href="https://unsplash.com/@necone?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Nenad Radojčić</a> on <a href="https://unsplash.com/photos/gray-concrete-building-under-white-sky-during-daytime-JBm5eNo6B4E?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a> | ||
<div class="my-64 text-right text-gray text-italic"> | ||
Made with ❤️ by <a href="https://github.com/stamat">@stamat</a>. | ||
</div> | ||
@@ -1,117 +0,75 @@ | ||
import { percentage } from 'book-of-spells' | ||
import { shallowMerge, drag } from 'book-of-spells'; | ||
function onDrag(element, callback) { | ||
let startX = 0; | ||
let startY = 0; | ||
let endX = 0; | ||
let endY = 0; | ||
let dragging = false; | ||
let rect = element.getBoundingClientRect(); | ||
export default class CompareImagesSlider { | ||
constructor(element, options) { | ||
this.element = element; | ||
this.frame = this.element.querySelector('.frame'); | ||
this.second = this.frame.querySelector(':scope > img'); | ||
this.handle = this.element.querySelector('.handle'); | ||
const handleStart = function(e) { | ||
const carrier = e.type === 'touchstart' ? e.touches[0] : e; | ||
startX = carrier.clientX; | ||
startY = carrier.clientY; | ||
dragging = true; | ||
rect = element.getBoundingClientRect(); | ||
const xPercentage = percentage(startX - rect.left, rect.width); | ||
const yPercentage = percentage(startY - rect.top, rect.height); | ||
const event = new CustomEvent('dragstart', { detail: { target: element, startX, startY, rect, xPercentage, yPercentage } }); | ||
element.dispatchEvent(event); | ||
}; | ||
this.options = { | ||
inertia: false, | ||
bounce: false, | ||
friction: 0.9, | ||
bounceFactor: 0.1, | ||
onlyHandle: true, | ||
vertical: false | ||
} | ||
const handleMove = function(e) { | ||
if (!dragging) return; | ||
const carrier = e.type === 'touchmove' ? e.touches[0] : e; | ||
endX = carrier.clientX; | ||
endY = carrier.clientY; | ||
handleDragGesture(); | ||
}; | ||
if (options) shallowMerge(this.options, options); | ||
const handleEnd = function() { | ||
dragging = false; | ||
const event = new CustomEvent('dragend', { detail: { target: element, startX, startY, rect, endX, endY } }); | ||
element.dispatchEvent(event); | ||
}; | ||
this.checkAndApplyAttribute('vertical'); | ||
if (this.options.vertical && !(this.element.dataset.vertical || this.element.hasAttribute('vertical'))) this.element.setAttribute('vertical', ''); | ||
if (this.options.onlyHandle) this.options.preventDefaultTouch = false; | ||
const handleDragGesture = function() { | ||
const deltaX = endX - startX; | ||
const deltaY = endY - startY; | ||
const left = deltaX < 0; | ||
const up = deltaY < 0; | ||
const xPercentage = percentage(endX - rect.left, rect.width); | ||
const yPercentage = percentage(endY - rect.top, rect.height); | ||
window.addEventListener('resize', () => { | ||
requestAnimationFrame(this.setupSecondImage.bind(this)); | ||
}); | ||
this.setupSecondImage(); | ||
const detail = { | ||
target: element, | ||
deltaX: deltaX, | ||
deltaY: deltaY, | ||
startX: startX, | ||
startY: startY, | ||
endX: endX, | ||
endY: endY, | ||
horizontalDirection: left ? 'left' : 'right', | ||
verticalDirection: up ? 'up' : 'down', | ||
xPercentage: xPercentage, | ||
yPercentage: yPercentage | ||
}; | ||
this.drag = drag(this.element, this.options); | ||
if (xPercentage < 0) { | ||
detail.xPercentage = 0; | ||
} | ||
this.handleDragBound = false; | ||
this.boundUpdateVisibleHandler = this.updateVisibleHandler.bind(this); | ||
if (xPercentage > 100) { | ||
detail.xPercentage = 100; | ||
const preventDefault = (e) => { | ||
if (this.handleDragBound) e.preventDefault(); | ||
} | ||
if (yPercentage < 0) { | ||
detail.yPercentage = 0; | ||
} | ||
const addEventListeners = () => { | ||
if (this.handleDragBound) return; | ||
this.handleDragBound = true; | ||
if (yPercentage > 100) { | ||
detail.yPercentage = 100; | ||
} | ||
this.element.addEventListener('dragstart', this.boundUpdateVisibleHandler); | ||
this.element.addEventListener('drag', this.boundUpdateVisibleHandler); | ||
this.element.addEventListener('draginertia', this.boundUpdateVisibleHandler); | ||
this.element.addEventListener('draginertiaend', () => { | ||
this.element.removeEventListener('draginertia', this.boundUpdateVisibleHandler); | ||
}); | ||
if (callback) { | ||
callback(detail); | ||
} | ||
this.element.addEventListener('touchstart', preventDefault); | ||
}; | ||
const removeEventListeners = () => { | ||
if (!this.handleDragBound) return; | ||
this.handleDragBound = false; | ||
this.element.removeEventListener('dragstart', this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener('drag', this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener('touchstart', preventDefault); | ||
}; | ||
const event = new CustomEvent('drag', { detail: detail }); | ||
element.dispatchEvent(event); | ||
}; | ||
element.addEventListener('mousedown', handleStart); | ||
element.addEventListener('mousemove', handleMove); | ||
element.addEventListener('mouseup', handleEnd); | ||
element.addEventListener('touchstart', handleStart); | ||
element.addEventListener('touchmove', handleMove); | ||
element.addEventListener('touchend', handleEnd); | ||
return { | ||
destroy: function() { | ||
element.removeEventListener('mousedown', handleStart); | ||
element.removeEventListener('mousemove', handleMove); | ||
element.removeEventListener('mouseup', handleEnd); | ||
element.removeEventListener('touchstart', handleStart); | ||
element.removeEventListener('touchmove', handleMove); | ||
element.removeEventListener('touchend', handleEnd); | ||
if (this.options.onlyHandle) { | ||
this.handle.addEventListener('mousedown', addEventListeners); | ||
this.handle.addEventListener('touchstart', addEventListeners); | ||
document.addEventListener('mouseup', removeEventListeners); | ||
document.addEventListener('touchend', removeEventListeners); | ||
} else { | ||
this.element.addEventListener('dragstart', this.boundUpdateVisibleHandler); | ||
this.element.addEventListener('drag', this.boundUpdateVisibleHandler); | ||
this.element.addEventListener('draginertia', this.boundUpdateVisibleHandler); | ||
} | ||
}; | ||
} | ||
} | ||
export default class CompareImagesSlider { | ||
constructor(element, options) { | ||
this.element = element; | ||
this.frame = this.element.querySelector('.frame'); | ||
this.second = this.frame.querySelector(':scope > img'); | ||
this.handle = this.element.querySelector('.handle'); | ||
window.addEventListener('resize', () => { | ||
requestAnimationFrame(this.setupSecondImage.bind(this)); | ||
}); | ||
this.setupSecondImage(); | ||
this.drag = onDrag(this.element); | ||
this.element.addEventListener('dragstart', this.updateVisibleHandler.bind(this)); | ||
this.element.addEventListener('drag', this.updateVisibleHandler.bind(this)); | ||
checkAndApplyAttribute(attribute) { | ||
if (this.element.dataset[attribute] || this.element.hasAttribute(attribute)) this.options[attribute] = true; | ||
} | ||
@@ -125,2 +83,8 @@ | ||
updateVisibleHandler(e) { | ||
if (this.options.vertical) { | ||
this.frame.style.height = e.detail.yPercentage + '%'; | ||
this.handle.style.top = e.detail.yPercentage + '%'; | ||
return; | ||
} | ||
this.frame.style.width = e.detail.xPercentage + '%'; | ||
@@ -132,5 +96,6 @@ this.handle.style.left = e.detail.xPercentage + '%'; | ||
this.drag.destroy(); | ||
this.element.removeEventListener('dragstart', this.updateVisibleHandler.bind(this)); | ||
this.element.removeEventListener('drag', this.updateVisibleHandler.bind(this)); | ||
this.element.removeEventListener('dragstart', this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener('drag', this.boundUpdateVisibleHandler); | ||
this.element.removeEventListener('draginertia', this.boundUpdateVisibleHandler); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1336535
30
6992
80
Updatedbook-of-spells@^1.0.31