zoomist.min.js 13 KB

1234567891011
  1. /*!
  2. * zoomist.js v1.0.2
  3. * https://github.com/cotton123236/zoomist#readme
  4. *
  5. * Copyright 2021-present Wilson Wu
  6. * Released under the MIT license
  7. *
  8. * Date: 2022-03-26T09:56:17.746Z
  9. */
  10. !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Zoomist=e()}(this,(function(){"use strict";const t="zoomist",e=["slider","zoomer"],o="zoomist-container",i="zoomist-slider",s="zoomist-in-zoomer",n="zoomist-out-zoomer",a="zoomist-zoomer-disable",r=!(!("undefined"!=typeof window&&void 0!==window.document)||!("ontouchstart"in window)),l=r?"touchstart":"mousedown",d=r?"touchmove":"mousemove",h=r?"touchend":"mouseup";var c={fill:"cover",src:"data-zoomist-src",draggable:!0,wheelable:!0,pinchable:!0,bounds:!0,zoomRatio:.1,maxRatio:!1,height:"auto"};const m={el:i,direction:"horizontal",maxRatio:2},u={inEl:s,outEl:n,disableOnBounds:!0},p={ready:null,zoom:null,wheel:null,dragStart:null,drag:null,dragEnd:null,pinchStart:null,pinch:null,pinchEnd:null,slideStart:null,slide:null,slideEnd:null,resize:null,reset:null,destroy:null,update:null},g=(t,e)=>{t||(t={});for(const[o,i]of Object.entries(e))t[o]=i},f=t=>Object.assign({},t),v=t=>"number"==typeof t&&!isNaN(t),w=t=>null!==z(t),z=t=>t instanceof HTMLElement?t:document.querySelector(t),E=t=>w(t)&&"IMG"===z(t).tagName,_=t=>"function"==typeof t,y=(t,e)=>{for(const[o,i]of Object.entries(e))t.style[o]=v(i)?`${i}px`:i},x=t=>{const e=!r||"wheel"===t.type;return{x:e?t.pageX:t.touches[0].pageX,y:e?t.pageY:t.touches[0].pageY,clientX:e?t.clientX:t.touches[0].clientX,clientY:e?t.clientY:t.touches[0].clientY}},b=t=>{const e=getComputedStyle(t).transform;let o=e.match(/^matrix3d\((.+)\)$/);return o?parseFloat(o[1].split(", ")[12]):(o=e.match(/^matrix\((.+)\)$/),o?parseFloat(o[1].split(", ")[4]):0)},Y=t=>{const e=getComputedStyle(t).transform;let o=e.match(/^matrix3d\((.+)\)$/);return o?parseFloat(o[1].split(", ")[13]):(o=e.match(/^matrix\((.+)\)$/),o?parseFloat(o[1].split(", ")[5]):0)},L=t=>+(Math.round(t+"e+2")+"e-2"),X=(t,e,o)=>Math.min(Math.max(t,e),o);var D={getContainerData(){return f(this.data.containerData)},getImageData(){return f(this.data.imageData)},getSliderValue(){return this.__modules__.slider?.value},getZoomRatio(){return this.ratio},zoom(t,e){const{image:o,data:i,options:s,ratio:n}=this,{bounds:r,maxRatio:l}=s;if(r&&1===n&&t<0)return;if(l&&n===l&&t>0)return;const{originImageData:d}=i,h=this.getContainerData(),c=this.getImageData(),m=o.getBoundingClientRect(),u=L(n*(t+1)),p=r&&u<1?1:l&&u>l?l:u,f=p/n-1,v=d.width*p,w=d.height*p,z=(h.width-v)/2,E=(h.height-w)/2,_=e?(c.width/2-e.clientX+m.left)*f+b(o):b(o),x=e?(c.height/2-e.clientY+m.top)*f+Y(o):Y(o),D=r?X(_,z,-z):_,R=r?X(x,E,-E):x,O={width:v,height:w,left:z,top:E};if(g(i.imageData,O),y(o,{...O,transform:`translate(${D}px, ${R}px)`}),this.ratio=p,this.emit("zoom",p),s.slider){const{slider:t}=this.__modules__,e=100*L(1-(t.maxRatio-p)/(t.maxRatio-1));t.value=X(e,0,100),this.slideTo(e,!0)}if(s.zoomer){const{zoomer:t}=this.__modules__;if(t.disableOnBounds){const{bounds:t}=s,{zoomerInEl:e,zoomerOutEl:o}=this.__modules__.zoomer;t&&1===this.ratio?o.classList.add(a):o.classList.remove(a),this.ratio===l?e.classList.add(a):e.classList.remove(a)}}return this},zoomTo(t){const{ratio:e}=this;if(t!==e){const o=t/e-1;this.zoom(o)}return this},move(t=0,e=0){const{image:o,data:i,options:s}=this,{imageData:n,dragData:a}=i,{top:r,left:l}=n,{transX:d,transY:h}=a,{bounds:c}=s,m=c?X(d-t,l,-l):d-t,u=c?X(h-e,r,-r):h-e,p=L(m),f=L(u);return g(a,{transX:p,transY:f}),o.style.transform=`translate(${p}px, ${f}px)`,this},moveTo(t,e){const{data:o,options:i}=this,{imageData:s,dragData:n}=o,{top:a,left:r}=s,{transX:l,transY:d}=n,{bounds:h}=i;t=t??Math.abs(r),e=e??Math.abs(a);const c=h?X(r+t+l,r,-r):r+t+l,m=h?X(a+e+d,a,-a):a+e+d;return this.move(c,m),this},slideTo(t,e){const{__modules__:o}=this;if(!o.slider)return;const{slider:i}=o,s="horizontal"===i.direction?"left":"top",n="horizontal"===i.direction?"":"-",a=X(t,0,100);if(i.sliderButton.style[s]=`${n}${a}%`,!e){const t=a/100,e=this.ratio<1?this.ratio:1,o=((this.ratio>i.maxRatio?this.ratio:i.maxRatio)-e)*t+e;this.zoomTo(o)}return this},reset(){const{image:t}=this;return this.zoomTo(1),y(t,{transform:"translate(0, 0)"}),this.emit("reset"),this},destroy(){const{element:e,wrapper:i}=this,{slider:s,zoomer:n}=this.__modules__;return e[t]=void 0,this.mounted=!1,s&&this.destroySlider(),n&&this.destroyZoomer(),i.remove(),e.style.removeProperty("width"),e.style.removeProperty("padding-bottom"),e.classList.remove(o),this.emit("destroy"),this},update(){return this.destroy().init(),this.emit("update"),this},on(t,e){if(!_(e))return this;const{__events__:o}=this;return t.split(" ").forEach((t=>{o[t]||(o[t]=[]),o[t].push(e)})),this},emit(...t){const{__events__:e}=this,o=t[0],i=t.slice(1,t.length);return e[o]?(e[o].forEach((t=>{_(t)&&t.apply(this,i)})),this):this}},R=t=>{const{element:e,wrapper:o,image:i,options:s,data:n}=t,{containerData:a,imageData:r,originImageData:c}=n;window.addEventListener("resize",(()=>{if(a.width===e.offsetWidth)return;const o=e.offsetWidth/a.width,s=e.offsetHeight/a.height,n=c.width*o,l=c.height*s,d=c.left*o,h=c.top*s,m=r.width*o,u=r.height*s,p=r.left*o,f=r.top*s,v=b(i)*o,w=Y(i)*s;g(a,{width:e.offsetWidth,height:e.offsetHeight}),g(c,{width:n,height:l,left:d,top:h}),g(r,{width:m,height:u,left:p,top:f}),y(t.image,{width:m,height:u,left:p,top:f,transform:`translate(${v}px, ${w}px)`}),t.emit("resize")})),t.dragging=!1,t.data.dragData={startX:0,startY:0,transX:0,transY:0},"contain"===s.fill&&s.bounds&&(s.bounds=!1);const{dragData:m}=n,u=e=>{if(!t.dragging)return;const o=e.touches&&2===e.touches.length,n=o?(e.touches[0].pageX+e.touches[1].pageX)/2:x(e).x,a=o?(e.touches[0].pageY+e.touches[1].pageY)/2:x(e).y;if(s.bounds){const t=m.startX-(m.transX-r.left),e=m.startX-(m.transX+r.left),o=m.startY-(m.transY-r.top),i=m.startY-(m.transY+r.top);n<t&&(m.startX+=n-t),n>e&&(m.startX+=n-e),a<o&&(m.startY+=a-o),a>i&&(m.startY+=a-i)}const l=L(n-m.startX+m.transX),d=L(a-m.startY+m.transY);i.style.transform=`translate(${l}px, ${d}px)`,t.emit("drag",{x:l,y:d},e)},p=e=>{t.dragging=!1,g(m,{transX:b(i),transY:Y(i)}),t.emit("dragEnd",{x:m.transX,y:m.transY},e),document.removeEventListener(d,u),document.removeEventListener(h,p)};t.pinching=!1,t.data.pinchData={dist:0,startX:0,startY:0};const f=e=>{if(!t.pinching)return;const{pinchData:o}=t.data,i=Math.hypot(e.touches[0].pageX-e.touches[1].pageX,e.touches[0].pageY-e.touches[1].pageY),s=L((i-o.dist)/100),n={clientX:(e.touches[0].clientX+e.touches[1].clientX)/2,clientY:(e.touches[0].clientY+e.touches[1].clientY)/2};t.zoom(s,n),o.dist=i,t.emit("pinch",e)},v=e=>{t.pinching=!1,t.emit("pinchEnd",e),document.removeEventListener(d,f),document.removeEventListener(h,v)};o.addEventListener(l,(e=>{(e=>{if(!s.draggable)return;if(2===e.which||3===e.which)return;const o=e.touches&&2===e.touches.length;g(m,{startX:o?(e.touches[0].pageX+e.touches[1].pageX)/2:x(e).x,startY:o?(e.touches[0].pageY+e.touches[1].pageY)/2:x(e).y,transX:b(i),transY:Y(i)}),t.dragging=!0,t.emit("dragStart",{x:m.transX,y:m.transY},e),document.addEventListener(d,u),document.addEventListener(h,p)})(e),(e=>{if(!s.pinchable)return;if(!e.touches||2!==e.touches.length)return;const{pinchData:o}=t.data;g(o,{dist:Math.hypot(e.touches[0].pageX-e.touches[1].pageX,e.touches[0].pageY-e.touches[1].pageY),startX:e.touches[0].clientX,startY:e.touches[0].clientY}),t.pinching=!0,t.emit("pinchStart",e),document.addEventListener(d,f),document.addEventListener(h,v)})(e)})),t.wheeling=!1;o.addEventListener("wheel",(e=>{if(!s.wheelable)return;e.preventDefault();const{zoomRatio:o}=s;if(t.wheeling)return;let i;t.wheeling=!0,setTimeout((()=>{t.wheeling=!1}),30),e.deltaY?i=e.deltaY>0?-1:1:e.wheelDelta?i=e.wheelDelta/120:e.detail&&(i=e.detail>0?-1:1),t.zoom(i*o,x(e)),t.emit("wheel",e)}))};var O={createModules(){const{options:t}=this;this.__modules__={},e.forEach((e=>{var o;t[e]&&this[`create${o=e,o.charAt(0).toUpperCase()+o.slice(1)}`]()}))},createSlider(){const{element:t,options:e,__modules__:o}=this;o.slider=Object.assign({},m,e.slider);const{slider:s}=o;e.maxRatio&&Object.assign(s,{maxRatio:e.maxRatio}),"horizontal"!==s.direction&&"vertical"!==s.direction&&(s.direction="horizontal"),s.value=0,s.mounted&&s.sliderMain.remove();const n=s.isCustomEl=s.el&&w(s.el),a=n?z(s.el):document.createElement("div");n||a.classList.add(i),a.innerHTML='\n <div class="zoomist-slider-main">\n <span class="zoomist-slider-bar"></span>\n <span class="zoomist-slider-button"></span>\n </div>\n',s.sliderEl=a,s.sliderMain=a.querySelector(".zoomist-slider-main"),s.sliderBar=a.querySelector(".zoomist-slider-bar"),s.sliderButton=a.querySelector(".zoomist-slider-button"),s.sliderMain.classList.add(`zoomist-slider-${s.direction}`),(t=>{const{slider:e}=t.__modules__;e.sliding=!1;const o="horizontal"===e.direction,i=i=>{const s=e.sliderMain.getBoundingClientRect(),n=o?x(i).clientX:-x(i).clientY,a=o?s.width:s.height,r=o?s.left:-s.bottom,l=X(L((n-r)/a),0,1),d=t.ratio<1?t.ratio:1,h=((t.ratio>e.maxRatio?t.ratio:e.maxRatio)-d)*l+d;t.zoomTo(h)},s=o=>{i(o),e.sliding=!0,t.emit("slideStart",t.getSliderValue(),o),document.addEventListener(d,n),document.addEventListener(h,a)},n=o=>{e.sliding&&(i(o),t.emit("slide",t.getSliderValue(),o))},a=o=>{e.sliding=!1,t.emit("slideEnd",t.getSliderValue(),o),document.removeEventListener(d,n),document.removeEventListener(h,a)};e.sliderMain.addEventListener(l,s),e.sliderMain.event=s})(this),s.mounted=!0,n||t.append(a)},destroySlider(){const{slider:t}=this.__modules__;t&&t.mounted&&(t.isCustomEl?t.sliderMain.remove():t.sliderEl.remove(),t.mounted=!1)},createZoomer(){const{element:t,options:e,__modules__:o}=this;o.zoomer=Object.assign({},u,e.zoomer);const{zoomer:i}=o;i.mounted&&i.zoomerEl&&i.sliderMain.remove();const r=i.isCustomInEl=i.inEl&&w(i.inEl),l=i.isCustomOutEl=i.outEl&&w(i.outEl),d=r?z(i.inEl):document.createElement("div"),h=l?z(i.outEl):document.createElement("div");if(r||(d.classList.add(s),d.innerHTML='\n<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 12 12">\n <polygon points="12,5.5 6.5,5.5 6.5,0 5.5,0 5.5,5.5 0,5.5 0,6.5 5.5,6.5 5.5,12 6.5,12 6.5,6.5 12,6.5 "/>\n</svg>\n'),l||(h.classList.add(n),h.innerHTML='\n<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 12 12">\n <rect y="5.5" width="12" height="1"/>\n</svg>\n'),i.zoomerInEl=d,i.zoomerOutEl=h,i.disableOnBounds){const{bounds:t,maxRatio:o}=e;t&&1===this.ratio&&h.classList.add(a),this.ratio===o&&d.classList.add(a)}if((t=>{const{zoomRatio:e}=t.options,{zoomer:o}=t.__modules__,i=()=>t.zoom(e),s=()=>t.zoom(-e);o.zoomerInEl.addEventListener("click",i),o.zoomerOutEl.addEventListener("click",s),o.zoomerInEl.event=i,o.zoomerOutEl.event=s})(this),i.mounted=!0,!r||!l){const e=document.createElement("div");e.classList.add("zoomist-zoomer"),r||e.append(d),l||e.append(h),i.zoomerEl=e,t.append(e)}},destroyZoomer(){const{zoomer:t}=this.__modules__;if(!t||!t.mounted)return;const e=t=>{t.removeEventListener("click",t.event),t.event=void 0,t.classList.remove(a)};t.isCustomInEl?e(t.zoomerInEl):t.zoomerInEl.remove(),t.isCustomOutEl?e(t.zoomerOutEl):t.zoomerOutEl.remove(),t.zoomerEl&&t.zoomerEl.remove(),t.mounted=!1}};class M{constructor(t,e={}){if(!t)throw new Error("The first argument is required.");if(!w(t))throw new Error("This element is not exist.");this.element=z(t),this.options=Object.assign({},c,(t=>{if(!(t=>"object"==typeof t&&null!==t)(t))return!1;try{const{constructor:e}=t,{prototype:o}=e,{hasOwnProperty:i}=Object.prototype;return e&&o&&i.call(o,"isPrototypeOf")}catch(t){return!1}})(e)&&e),this.init()}init(){const{element:e,options:o}=this,{src:i}=o;if(e[t])return;e[t]=this;const s=o.src="string"==typeof(n=i)&&""!==n||E(i)?i:c.src;var n;const a=E(s)?s.src:e.getAttribute(s);if(!a)throw new Error(`Cannot find src from ${s}`);this.create(a)}create(t){if(!t)return;const{options:e}=this;if(this.url=t,this.data={},this.ratio=1,this.__events__=p,e.on)for(const[t,o]of Object.entries(e.on))this.__events__[t]=[o];this.mount()}mount(){if(this.mounted)return;const{element:t,options:e,data:o,url:i}=this,{fill:s,maxRatio:n,height:a}=e;this.wrapper&&this.wrapper.remove();const r=document.createElement("div");r.classList.add("zoomist-wrapper");const l=document.createElement("img");l.classList.add("zoomist-image"),l.src=i,l.onload=()=>{this.wrapper=r,this.image=l;const{naturalWidth:i,naturalHeight:d}=l,h=i/d;a&&(y(t,{width:"100%"}),"auto"===a?y(t,{paddingBottom:`${L(d/i*100)}%`}):v(a)?y(t,{height:a}):a.indexOf("%")>-1&&y(t,{paddingBottom:a}));const{offsetWidth:c,offsetHeight:m}=t;this.data.containerData={width:c,height:m,aspectRatio:c/m};const{containerData:u}=o;let p;"cover"!==s&&"contain"!==s&&"none"!==s&&(e.fill="cover"),"contain"!==e.fill&&(p=u.aspectRatio===h?"both":u.aspectRatio>h?"width":"height"),"contain"===e.fill&&(p=u.aspectRatio===h?"both":u.aspectRatio>h?"height":"width");const g="none"===e.fill?i:"both"===p||"width"===p?u.width:u.height*h,f="none"===e.fill?d:"both"===p||"height"===p?u.height:u.width/h,w=(u.width-g)/2,z=(u.height-f)/2;this.data.originImageData={naturalWidth:i,naturalHeight:d,aspectRatio:h,width:g,height:f,left:w,top:z},this.data.imageData=Object.assign({},this.data.originImageData),y(l,{width:g,height:f,left:w,top:z}),(!v(n)||n<=1)&&!1!==n&&(e.maxRatio=!1),R(this),this.mounted=!0,this.render()}}render(){const{element:t,wrapper:e,image:i}=this;t.classList.add(o),e.append(i),t.append(e),this.createModules(),this.emit("ready")}}return Object.assign(M.prototype,D,O),M}));