From ceb399bc019d01e31fba1b4358c8a9b09451f5e0 Mon Sep 17 00:00:00 2001 From: Robin Bisping Date: Mon, 1 Jun 2026 14:22:09 +0200 Subject: [PATCH] fix: prevent broken crop when minResolution is unreachable --- examples/srcissors.js | 2 +- examples/srcissors.js.map | 2 +- src/crop.js | 17 +++++++++++++++-- srcissors.js | 2 +- srcissors.js.map | 2 +- test/specs/srcissors_spec.js | 30 ++++++++++++++++++++++++++++++ 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/examples/srcissors.js b/examples/srcissors.js index 903213a..b653cb3 100644 --- a/examples/srcissors.js +++ b/examples/srcissors.js @@ -1,2 +1,2 @@ -import{default as i}from"jquery";class t{constructor({onReady:i,img:t,opacity:e,outline:s}){this.onReady=i,this.img=t,this.opacity=e,this.outline=s,this.x=this.y=0,this.width=this.height=0,this.img.on("load",()=>{const i=this.img.width(),t=this.img.height();this.ratio=i/t,this.onReady({width:i,height:t}),this.img.show()})}setImage({url:i}){this.url=i,this.img.attr("src",this.url),this.outline&&this.setBackgroundImage({url:this.url})}setBackgroundImage({url:t}){if(this.opacity>0){const e=i("").css({opacity:this.opacity}).attr("src",t);this.outline.append(e)}}reset(){this.url=void 0,this.x=this.y=0,this.width=this.height=0,this.img.attr("src",""),this.img.css({width:"",height:"",transform:""}),this.outline&&this.outline.css({transform:""}).html("")}setWidth(i){this.img.css({width:`${i}px`,height:"auto"});const t=i/this.ratio;this.updateImageDimensions({width:i,height:t})}setHeight(i){this.img.css({width:"auto",height:`${i}px`});const t=i*this.ratio;this.updateImageDimensions({width:t,height:i})}updateImageDimensions({width:i,height:t}){this.width=i,this.height=t,this.outline&&this.outline.css({width:`${this.width}px`,height:`${this.height}px`})}pan(i,t){this.x=i,this.y=t;const e=Math.round(this.x),s=Math.round(this.y);this.img.css({transform:`translate(-${e}px, -${s}px)`}),this.outline&&this.outline.css({transform:`translate(-${e}px, -${s}px)`})}}const e=function(i){return i.type.includes("touch")?{pageX:i.originalEvent.changedTouches[0].pageX,pageY:i.originalEvent.changedTouches[0].pageY}:{pageX:i.pageX,pageY:i.pageY}};class s{constructor({parent:i,view:t,horizontal:e,vertical:s,actions:h}){this.parent=i,this.view=t,this.doubleClickThreshold=300,h.pan&&this.pan(),h.zoomOnDoubleClick&&this.doubleClick(),h.resize&&this.resizeView({horizontal:h.resizeHorizontal,vertical:h.resizeVertical}),this.preventBrowserDragDrop(),this.responsiveArena()}pan(){const t=i(document);this.view.on("mousedown.srcissors touchstart.srcissors",i=>{const s={startX:this.parent.preview.x,startY:this.parent.preview.y};i.preventDefault(),t.on("mousemove.srcissors-pan touchmove.srcissors-pan",t=>{const{pageX:h,pageY:n}=e(t),{pageX:o,pageY:a}=e(i);s.dx=h-o,s.dy=n-a,this.parent.onPan(s)}).on("mouseup.srcissors-pan touchend.srcissors-pan",()=>{t.off("mouseup.srcissors-pan touchend.srcissors-pan"),t.off("mousemove.srcissors-pan touchmove.srcissors-pan"),null!=s.dx&&this.parent.onPanEnd()})})}doubleClick(){let i;this.view.on("mousedown.srcissors touchstart.srcissors",t=>{const s=(new Date).getTime();i&&i>s-this.doubleClickThreshold&&this.parent.onDoubleClick(e(t)),i=s})}preventBrowserDragDrop(){this.view.on("dragstart.srcissors",()=>!1)}resizeView({horizontal:t,vertical:e}){const s=i("
");s.addClass("resize-handler");let h=[];t&&(h=h.concat(["right","left"])),e&&(h=h.concat(["top","bottom"])),h.forEach(i=>{const t=s.clone();t.addClass(`resize-handler-${i}`),t.on("mousedown.srcissors touchstart.srcissors",this.getResizeMouseDown(i)),this.view.append(t)})}getResizeMouseDown(t){const s=i(document);return i=>{let{pageX:h,pageY:n}=e(i);i.stopPropagation(),s.on("mousemove.srcissors-resize touchmove.srcissors-resize",i=>{let s,o;const{pageX:a,pageY:r}=e(i);switch(t){case"top":case"bottom":o=r-n,"top"===t&&(o=-o),n=r;break;case"left":case"right":s=a-h,"left"===t&&(s=-s),h=a}this.parent.onResize({position:t,dx:s,dy:o})}).on("mouseup.srcissors-resize touchend.srcissors-resize",()=>{s.off("mouseup.srcissors-resize touchmove.srcissors-resize"),s.off("mousemove.srcissors-resize touchend.srcissors-resize"),this.parent.onResizeEnd({position:t})})}}responsiveArena(){}}class h{constructor({arena:e,view:s,img:h,outline:n,url:o,fixedWidth:a,fixedHeight:r,minViewWidth:g,minViewHeight:d,minViewRatio:m,maxViewRatio:w,originalSize:l,crop:c,zoomStep:u,maxArea:p,actions:v,minResolution:x,surroundingImageOpacity:R,showSurroundingImage:z}){this.onPreviewReady=this.onPreviewReady.bind(this),this.arena=e,this.view=s,this.img=h,this.outline=n,this.fixedWidth=a,this.fixedHeight=r,this.minViewWidth=g,this.minViewHeight=d,this.minViewRatio=m,this.maxViewRatio=w,this.originalSize=l,this.actions=v,this.minResolution=x,this.surroundingImageOpacity=R,this.loadingCssClass="crop-view--is-loading",this.panningCssClass="crop-view--is-panning",this.outlineCssClass="crop-outline--active",this.isPanning=!1,this.initialCrop=c,this.loadEvent=i.Callbacks(),this.changeEvent=i.Callbacks(),this.initializeReadyState(),this.zoomInStep=u,this.zoomOutStep=1/this.zoomInStep,this.arenaWidth=this.arena.width(),this.arenaHeight=this.arena.height(),p&&(this.maxArea=this.arenaWidth*this.arenaHeight*p),this.outline&&this.setSurroundingImageVisibility(z),this.preview=new t({onReady:this.onPreviewReady,img:this.img,outline:this.outline,opacity:this.surroundingImageOpacity}),this.setImage(o)}initializeReadyState(){this.isReady=!1,null!=this.readyEvent&&this.readyEvent.empty(),this.readyEvent=i.Callbacks("memory once")}setImage(i){i!==this.preview.url&&(this.isInitialized&&this.preview.reset(),this.initializeReadyState(),this.view.addClass(this.loadingCssClass),this.preview.setImage({url:i}))}setSurroundingImageVisibility(i){this.surroundingImageOpacity=parseFloat(this.surroundingImageOpacity||.2),"always"===i?this.outline.css("opacity",1):"panning"===i?this.outline.css("opacity",null):(this.outline.css("opacity",0),this.surroundingImageOpacity=0)}reset(){this.isReady&&(this.resize({width:this.imageWidth,height:this.imageHeight}),this.zoomAllOut())}onPreviewReady(i){this.checkRatio(i);const{width:t,height:e}=this.originalSize||i;let h;this.preview.updateImageDimensions({width:t,height:e}),this.isInitialized||(this.events=new s({parent:this,view:this.view,actions:this.actions})),this.imageWidth=t,this.imageHeight=e,this.imageRatio=this.imageWidth/this.imageHeight;const n=this.imageWidth*this.imageHeight;if(this.minResolution&&this.minResolution>n&&delete this.minResolution,this.minResolution){const i=this.minResolution/(this.imageHeight*this.imageHeight);(!this.minViewRatio||this.minViewRatiot)&&(this.maxViewRatio=t)}this.calcMaxMinDimensions(),this.fixedWidth&&(h="width"),this.fixedHeight&&(h="height"),this.setViewDimensions({width:this.imageWidth,height:this.imageHeight,keepDimension:h}),this.isReady=!0,this.view.removeClass(this.loadingCssClass),this.isInitialized||null==this.initialCrop?(this.zoomAllOut(),this.center()):this.setCrop(this.initialCrop),this.isInitialized=!0,this.readyEvent.fire(),this.loadEvent.fire()}setCrop({x:i,y:t,width:e,height:s}){if(!this.isReady)return void this.on("ready",()=>this.setCrop({x:i,y:t,width:e,height:s}));this.resize({width:e,height:s});const h=this.viewWidth/e,n=this.imageWidth*h;this.zoom({width:n}),this.pan({x:i*h,y:t*h})}getCrop(){const i=this.preview.width/this.imageWidth,t={x:this.preview.x/i,y:this.preview.y/i,width:this.viewWidth/i,height:this.viewHeight/i};return this.roundCrop(t),this.validateCrop(t),t}roundCrop(i){for(const t in i){const e=i[t];i[t]=Math.round(e)}}validateCrop(i){const{x:t,y:e,width:s,height:h}=i;return t<0&&(i.x=0),e<0&&(i.y=0),t+s>this.imageWidth&&(i.width=this.imageWidth-t),e+h>this.imageHeight&&(i.height=this.imageHeight-e),i}setRatio(i,t){let e,s;if(this.isReady)return i=this.enforceValidRatio(i),"height"===t?(e=this.viewHeight,s=e*i):(s=this.viewWidth,e=s/i),this.resizeFocusPoint=this.getFocusPoint(),this.resize({width:s,height:e});this.on("ready",()=>this.setRatio(i,t))}onPan(i){this.isPanning||(this.isPanning=!0,this.arena.addClass(this.panningCssClass),this.outline.addClass(this.outlineCssClass));const t=i.startX-i.dx,e=i.startY-i.dy;this.pan({x:t,y:e})}onPanEnd(){return this.isPanning=!1,this.arena.removeClass(this.panningCssClass),this.outline.removeClass(this.outlineCssClass)}onDoubleClick({pageX:i,pageY:t}){const{left:e,top:s}=this.view[0].getBoundingClientRect(),h=i-e,n=t-s;this.zoomIn({viewX:h,viewY:n})}onResize({position:i,dx:t,dy:e}){this.isResizing||(this.isResizing=!0,this.resizeFocusPoint=this.getFocusPoint()),["top","bottom"].includes(i)?(e*=2,this.resize({width:this.viewWidth,height:this.viewHeight+e,keepDimension:"height"})):["left","right"].includes(i)&&(t*=2,this.resize({width:this.viewWidth+t,height:this.viewHeight,keepDimension:"width"}))}onResizeEnd(){this.isResizing=!1,this.resizeFocusPoint=void 0}resize({width:i,height:t,keepDimension:e}){this.setViewDimensions({width:i,height:t,keepDimension:e}),this.resizeFocusPoint&&(this.resizeFocusPoint.viewX=this.viewWidth/2,this.resizeFocusPoint.viewY=this.viewHeight/2),this.zoom({width:this.preview.width,height:this.preview.height,focusPoint:this.resizeFocusPoint})}setViewDimensions({width:i,height:t,keepDimension:e}){if(this.maxArea&&({width:i,height:t}=this.enforceMaxArea({width:i,height:t,keepDimension:e})),({width:i,height:t}=this.enforceViewDimensions({width:i,height:t,keepDimension:e})),this.view.css({width:i,height:t}),this.viewWidth=i,this.viewHeight=t,this.viewRatio=i/t,this.minResolution){const i=Math.sqrt(this.minResolution*this.viewRatio),t=Math.sqrt(this.minResolution/this.viewRatio);this.maxImageWidth=this.viewWidth/i*this.imageWidth,this.maxImageHeight=this.viewHeight/t*this.imageHeight}this.fireChange()}zoomAllOut(){this.isWidthRestricting()?this.zoom({width:this.viewWidth}):this.zoom({height:this.viewHeight})}zoomIn(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomInStep:i.height=this.preview.height*this.zoomInStep,this.zoom(i)}zoomOut(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomOutStep:i.height=this.preview.height*this.zoomOutStep,this.zoom(i)}zoom({width:i,height:t,viewX:e,viewY:s,focusPoint:h}){null==h&&(h=this.getFocusPoint({viewX:e,viewY:s})),({width:i,height:t}=this.enforceZoom({width:i,height:t})),null!=i?(this.preview.setWidth(i),this.fireChange()):null!=t&&(this.preview.setHeight(t),this.fireChange()),this.focus(h)}getFocusPoint(i){null==i&&(i={});let{viewX:t,viewY:e}=i;null==t&&(t=this.viewWidth/2),null==e&&(e=this.viewHeight/2);const s=this.preview.x+t,h=this.preview.y+e;return{percentX:s/this.preview.width,percentY:h/this.preview.height,viewX:t,viewY:e}}focus({percentX:i,percentY:t,viewX:e,viewY:s}){let h=this.preview.width*i,n=this.preview.height*t;h-=e,n-=s,this.pan({x:h,y:n})}center(){const i=(this.preview.width-this.viewWidth)/2,t=(this.preview.height-this.viewHeight)/2;this.pan({x:i,y:t})}pan(i){i=this.enforceXy(i),this.preview.pan(i.x,i.y),this.fireChange()}enforceXy({x:i,y:t}){return i>this.preview.width-this.viewWidth&&(i=this.preview.width-this.viewWidth),i<0&&(i=0),t>this.preview.height-this.viewHeight&&(t=this.preview.height-this.viewHeight),t<0&&(t=0),{x:i,y:t}}enforceZoom({width:i,height:t}){return null!=i&&this.maxImageWidth&&i>this.maxImageWidth?{width:this.maxImageWidth}:null!=i&&ithis.maxImageHeight?{height:this.maxImageHeight}:null!=t&&tthis.maxWidth||tthis.maxHeight||sthis.maxViewRatio)}isValidRatio(i){return!(ithis.maxViewRatio)}enforceValidRatio(i){return ithis.maxViewRatio?this.maxViewRatio:i}enforceViewDimensions({width:i,height:t,keepDimension:e}){let s,h,n;return ithis.maxWidth&&(h=this.maxWidth),tthis.maxHeight&&(s=this.maxHeight),e?(h&&(i=h),s&&(t=s),n=i/t,this.isValidRatio(n)||(n=this.enforceValidRatio(n),({width:i,height:t}=this.getRatioBox({ratio:n,width:i,height:t,keepDimension:e})),(i>this.arenaWidth||t>this.arenaHeight)&&({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n)))):(h||s)&&(n=this.enforceValidRatio(i/t),({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n))),{width:i,height:t}}enforceMaxArea({width:i,height:t,keepDimension:e}){let s=i/t;return"width"===e?s=i/(t=this.maxArea/i):"height"===e?s=(i=this.maxArea/t)/t:t=(i=Math.sqrt(this.maxArea*s))/s,this.isValidRatio(s)||(s=this.enforceValidRatio(s),t=(i=Math.sqrt(this.maxArea*s))/s),{width:i,height:t}}checkRatio(i){if(this.originalSize){const t=this.originalSize.width/this.originalSize.height,e=i.width/i.height,s=(e-t)/t*100;if(Math.abs(s)>1)throw new Error(`srcissors: Displayed image has a different image ratio than the one configured in 'originalRatio': ${t} vs ${e}`)}}isWidthRestricting(){return this.viewRatio>=this.imageRatio}getRatioBox({ratio:i,width:t,height:e,keepDimension:s}){return"width"===s||null==e?e=t/i:"height"===s||null==t?t=e*i:e=t/i,{width:t,height:e}}centerAlign(i,t,e){let s,h,n,o;return i/t>e?(h=t*e,n=(i-h)/2):(s=i/e,o=(t-s)/2),{x:n||0,y:o||0,width:h||i,height:s||t}}min(i){let t=i[0];for(const e of i)e{this.changeDispatch=void 0,this.changeEvent.fire(this.getCrop())},0))}debug(){const i=i=>Math.round(10*i)/10,t={arena:`${i(this.arenaWidth)}x${i(this.arenaHeight)}`,view:`${i(this.viewWidth)}x${i(this.viewHeight)}`,image:`${i(this.imageWidth)}x${i(this.imageHeight)}`,preview:`${i(this.preview.width)}x${i(this.preview.height)}`,previewXy:`${i(this.preview.x)}x${i(this.preview.y)}`};return console.log(t),t}}const n={new({arena:t,url:e,fixedWidth:s,fixedHeight:n,minWidth:o,minHeight:a,minRatio:r,maxRatio:g,maxArea:d,originalSize:m,zoomStep:w,crop:l,actions:c,minResolution:u,surroundingImageOpacity:p,showSurroundingImage:v}){const x=(t=i(t)).find(".crop-view"),R=x.find(".crop-preview"),z=i("");R.append(z);let f=x.find(".crop-outline");f.length||(f=void 0);const y={pan:!0,zoomOnDoubleClick:!0,resize:!0,resizeHorizontal:!s,resizeVertical:!n};return i.extend(y,c),null==w&&(w=1.25),null==o&&(o=50),null==a&&(a=50),new h({url:e,crop:l,arena:t,view:x,img:z,outline:f,showSurroundingImage:v,surroundingImageOpacity:p,fixedWidth:s,fixedHeight:n,minViewWidth:o,minViewHeight:a,minViewRatio:r,maxViewRatio:g,maxArea:d,originalSize:m,zoomStep:w,actions:y,minResolution:u})}};export{n as default}; +import{default as i}from"jquery";class t{constructor({onReady:i,img:t,opacity:e,outline:s}){this.onReady=i,this.img=t,this.opacity=e,this.outline=s,this.x=this.y=0,this.width=this.height=0,this.img.on("load",()=>{const i=this.img.width(),t=this.img.height();this.ratio=i/t,this.onReady({width:i,height:t}),this.img.show()})}setImage({url:i}){this.url=i,this.img.attr("src",this.url),this.outline&&this.setBackgroundImage({url:this.url})}setBackgroundImage({url:t}){if(this.opacity>0){const e=i("").css({opacity:this.opacity}).attr("src",t);this.outline.append(e)}}reset(){this.url=void 0,this.x=this.y=0,this.width=this.height=0,this.img.attr("src",""),this.img.css({width:"",height:"",transform:""}),this.outline&&this.outline.css({transform:""}).html("")}setWidth(i){this.img.css({width:`${i}px`,height:"auto"});const t=i/this.ratio;this.updateImageDimensions({width:i,height:t})}setHeight(i){this.img.css({width:"auto",height:`${i}px`});const t=i*this.ratio;this.updateImageDimensions({width:t,height:i})}updateImageDimensions({width:i,height:t}){this.width=i,this.height=t,this.outline&&this.outline.css({width:`${this.width}px`,height:`${this.height}px`})}pan(i,t){this.x=i,this.y=t;const e=Math.round(this.x),s=Math.round(this.y);this.img.css({transform:`translate(-${e}px, -${s}px)`}),this.outline&&this.outline.css({transform:`translate(-${e}px, -${s}px)`})}}const e=function(i){return i.type.includes("touch")?{pageX:i.originalEvent.changedTouches[0].pageX,pageY:i.originalEvent.changedTouches[0].pageY}:{pageX:i.pageX,pageY:i.pageY}};class s{constructor({parent:i,view:t,horizontal:e,vertical:s,actions:h}){this.parent=i,this.view=t,this.doubleClickThreshold=300,h.pan&&this.pan(),h.zoomOnDoubleClick&&this.doubleClick(),h.resize&&this.resizeView({horizontal:h.resizeHorizontal,vertical:h.resizeVertical}),this.preventBrowserDragDrop(),this.responsiveArena()}pan(){const t=i(document);this.view.on("mousedown.srcissors touchstart.srcissors",i=>{const s={startX:this.parent.preview.x,startY:this.parent.preview.y};i.preventDefault(),t.on("mousemove.srcissors-pan touchmove.srcissors-pan",t=>{const{pageX:h,pageY:n}=e(t),{pageX:o,pageY:a}=e(i);s.dx=h-o,s.dy=n-a,this.parent.onPan(s)}).on("mouseup.srcissors-pan touchend.srcissors-pan",()=>{t.off("mouseup.srcissors-pan touchend.srcissors-pan"),t.off("mousemove.srcissors-pan touchmove.srcissors-pan"),null!=s.dx&&this.parent.onPanEnd()})})}doubleClick(){let i;this.view.on("mousedown.srcissors touchstart.srcissors",t=>{const s=(new Date).getTime();i&&i>s-this.doubleClickThreshold&&this.parent.onDoubleClick(e(t)),i=s})}preventBrowserDragDrop(){this.view.on("dragstart.srcissors",()=>!1)}resizeView({horizontal:t,vertical:e}){const s=i("
");s.addClass("resize-handler");let h=[];t&&(h=h.concat(["right","left"])),e&&(h=h.concat(["top","bottom"])),h.forEach(i=>{const t=s.clone();t.addClass(`resize-handler-${i}`),t.on("mousedown.srcissors touchstart.srcissors",this.getResizeMouseDown(i)),this.view.append(t)})}getResizeMouseDown(t){const s=i(document);return i=>{let{pageX:h,pageY:n}=e(i);i.stopPropagation(),s.on("mousemove.srcissors-resize touchmove.srcissors-resize",i=>{let s,o;const{pageX:a,pageY:r}=e(i);switch(t){case"top":case"bottom":o=r-n,"top"===t&&(o=-o),n=r;break;case"left":case"right":s=a-h,"left"===t&&(s=-s),h=a}this.parent.onResize({position:t,dx:s,dy:o})}).on("mouseup.srcissors-resize touchend.srcissors-resize",()=>{s.off("mouseup.srcissors-resize touchmove.srcissors-resize"),s.off("mousemove.srcissors-resize touchend.srcissors-resize"),this.parent.onResizeEnd({position:t})})}}responsiveArena(){}}class h{constructor({arena:e,view:s,img:h,outline:n,url:o,fixedWidth:a,fixedHeight:r,minViewWidth:g,minViewHeight:d,minViewRatio:m,maxViewRatio:w,originalSize:l,crop:c,zoomStep:u,maxArea:p,actions:v,minResolution:x,surroundingImageOpacity:R,showSurroundingImage:z}){this.onPreviewReady=this.onPreviewReady.bind(this),this.arena=e,this.view=s,this.img=h,this.outline=n,this.fixedWidth=a,this.fixedHeight=r,this.minViewWidth=g,this.minViewHeight=d,this.minViewRatio=m,this.maxViewRatio=w,this.originalSize=l,this.actions=v,this.minResolution=x,this.surroundingImageOpacity=R,this.loadingCssClass="crop-view--is-loading",this.panningCssClass="crop-view--is-panning",this.outlineCssClass="crop-outline--active",this.isPanning=!1,this.initialCrop=c,this.loadEvent=i.Callbacks(),this.changeEvent=i.Callbacks(),this.initializeReadyState(),this.zoomInStep=u,this.zoomOutStep=1/this.zoomInStep,this.arenaWidth=this.arena.width(),this.arenaHeight=this.arena.height(),p&&(this.maxArea=this.arenaWidth*this.arenaHeight*p),this.outline&&this.setSurroundingImageVisibility(z),this.preview=new t({onReady:this.onPreviewReady,img:this.img,outline:this.outline,opacity:this.surroundingImageOpacity}),this.setImage(o)}initializeReadyState(){this.isReady=!1,null!=this.readyEvent&&this.readyEvent.empty(),this.readyEvent=i.Callbacks("memory once")}setImage(i){i!==this.preview.url&&(this.isInitialized&&this.preview.reset(),this.initializeReadyState(),this.view.addClass(this.loadingCssClass),this.preview.setImage({url:i}))}setSurroundingImageVisibility(i){this.surroundingImageOpacity=parseFloat(this.surroundingImageOpacity||.2),"always"===i?this.outline.css("opacity",1):"panning"===i?this.outline.css("opacity",null):(this.outline.css("opacity",0),this.surroundingImageOpacity=0)}reset(){this.isReady&&(this.resize({width:this.imageWidth,height:this.imageHeight}),this.zoomAllOut())}onPreviewReady(i){this.checkRatio(i);const{width:t,height:e}=this.originalSize||i;let h;this.preview.updateImageDimensions({width:t,height:e}),this.isInitialized||(this.events=new s({parent:this,view:this.view,actions:this.actions})),this.imageWidth=t,this.imageHeight=e,this.imageRatio=this.imageWidth/this.imageHeight;const n=this.imageWidth*this.imageHeight;if(this.minResolution&&this.minResolution>n&&delete this.minResolution,this.minResolution){const i=this.minResolution/(this.imageHeight*this.imageHeight);(!this.minViewRatio||this.minViewRatiot)&&(this.maxViewRatio=t)}this.calcMaxMinDimensions(),this.fixedWidth&&(h="width"),this.fixedHeight&&(h="height"),this.setViewDimensions({width:this.imageWidth,height:this.imageHeight,keepDimension:h}),this.isReady=!0,this.view.removeClass(this.loadingCssClass),this.isInitialized||null==this.initialCrop?(this.zoomAllOut(),this.center()):this.setCrop(this.initialCrop),this.isInitialized=!0,this.readyEvent.fire(),this.loadEvent.fire()}setCrop({x:i,y:t,width:e,height:s}){if(!this.isReady)return void this.on("ready",()=>this.setCrop({x:i,y:t,width:e,height:s}));this.resize({width:e,height:s});const h=this.viewWidth/e,n=this.imageWidth*h;this.zoom({width:n}),this.pan({x:i*h,y:t*h})}getCrop(){const i=this.preview.width/this.imageWidth,t={x:this.preview.x/i,y:this.preview.y/i,width:this.viewWidth/i,height:this.viewHeight/i};return this.roundCrop(t),this.validateCrop(t),t}roundCrop(i){for(const t in i){const e=i[t];i[t]=Math.round(e)}}validateCrop(i){const{x:t,y:e,width:s,height:h}=i;return t<0&&(i.x=0),e<0&&(i.y=0),t+s>this.imageWidth&&(i.width=this.imageWidth-t),e+h>this.imageHeight&&(i.height=this.imageHeight-e),i}setRatio(i,t){let e,s;if(this.isReady)return i=this.enforceValidRatio(i),"height"===t?(e=this.viewHeight,s=e*i):(s=this.viewWidth,e=s/i),this.resizeFocusPoint=this.getFocusPoint(),this.resize({width:s,height:e});this.on("ready",()=>this.setRatio(i,t))}onPan(i){this.isPanning||(this.isPanning=!0,this.arena.addClass(this.panningCssClass),this.outline.addClass(this.outlineCssClass));const t=i.startX-i.dx,e=i.startY-i.dy;this.pan({x:t,y:e})}onPanEnd(){return this.isPanning=!1,this.arena.removeClass(this.panningCssClass),this.outline.removeClass(this.outlineCssClass)}onDoubleClick({pageX:i,pageY:t}){const{left:e,top:s}=this.view[0].getBoundingClientRect(),h=i-e,n=t-s;this.zoomIn({viewX:h,viewY:n})}onResize({position:i,dx:t,dy:e}){this.isResizing||(this.isResizing=!0,this.resizeFocusPoint=this.getFocusPoint()),["top","bottom"].includes(i)?(e*=2,this.resize({width:this.viewWidth,height:this.viewHeight+e,keepDimension:"height"})):["left","right"].includes(i)&&(t*=2,this.resize({width:this.viewWidth+t,height:this.viewHeight,keepDimension:"width"}))}onResizeEnd(){this.isResizing=!1,this.resizeFocusPoint=void 0}resize({width:i,height:t,keepDimension:e}){this.setViewDimensions({width:i,height:t,keepDimension:e}),this.resizeFocusPoint&&(this.resizeFocusPoint.viewX=this.viewWidth/2,this.resizeFocusPoint.viewY=this.viewHeight/2),this.zoom({width:this.preview.width,height:this.preview.height,focusPoint:this.resizeFocusPoint})}setViewDimensions({width:i,height:t,keepDimension:e}){if(this.maxArea&&({width:i,height:t}=this.enforceMaxArea({width:i,height:t,keepDimension:e})),({width:i,height:t}=this.enforceViewDimensions({width:i,height:t,keepDimension:e})),this.view.css({width:i,height:t}),this.viewWidth=i,this.viewHeight=t,this.viewRatio=i/t,this.minResolution){const i=Math.sqrt(this.minResolution*this.viewRatio),t=Math.sqrt(this.minResolution/this.viewRatio),e=this.viewWidth/i*this.imageWidth,s=this.viewHeight/t*this.imageHeight;e>=this.viewWidth&&s>=this.viewHeight?(this.maxImageWidth=e,this.maxImageHeight=s):(this.maxImageWidth=Math.max(this.viewWidth,this.viewHeight*this.imageRatio),this.maxImageHeight=this.maxImageWidth/this.imageRatio)}this.fireChange()}zoomAllOut(){this.isWidthRestricting()?this.zoom({width:this.viewWidth}):this.zoom({height:this.viewHeight})}zoomIn(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomInStep:i.height=this.preview.height*this.zoomInStep,this.zoom(i)}zoomOut(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomOutStep:i.height=this.preview.height*this.zoomOutStep,this.zoom(i)}zoom({width:i,height:t,viewX:e,viewY:s,focusPoint:h}){null==h&&(h=this.getFocusPoint({viewX:e,viewY:s})),({width:i,height:t}=this.enforceZoom({width:i,height:t})),null!=i?(this.preview.setWidth(i),this.fireChange()):null!=t&&(this.preview.setHeight(t),this.fireChange()),this.focus(h)}getFocusPoint(i){null==i&&(i={});let{viewX:t,viewY:e}=i;null==t&&(t=this.viewWidth/2),null==e&&(e=this.viewHeight/2);const s=this.preview.x+t,h=this.preview.y+e;return{percentX:s/this.preview.width,percentY:h/this.preview.height,viewX:t,viewY:e}}focus({percentX:i,percentY:t,viewX:e,viewY:s}){let h=this.preview.width*i,n=this.preview.height*t;h-=e,n-=s,this.pan({x:h,y:n})}center(){const i=(this.preview.width-this.viewWidth)/2,t=(this.preview.height-this.viewHeight)/2;this.pan({x:i,y:t})}pan(i){i=this.enforceXy(i),this.preview.pan(i.x,i.y),this.fireChange()}enforceXy({x:i,y:t}){return i>this.preview.width-this.viewWidth&&(i=this.preview.width-this.viewWidth),i<0&&(i=0),t>this.preview.height-this.viewHeight&&(t=this.preview.height-this.viewHeight),t<0&&(t=0),{x:i,y:t}}enforceZoom({width:i,height:t}){return null!=i&&this.maxImageWidth&&i>this.maxImageWidth?{width:this.maxImageWidth}:null!=i&&ithis.maxImageHeight?{height:this.maxImageHeight}:null!=t&&tthis.maxWidth||tthis.maxHeight||sthis.maxViewRatio)}isValidRatio(i){return!(ithis.maxViewRatio)}enforceValidRatio(i){return ithis.maxViewRatio?this.maxViewRatio:i}enforceViewDimensions({width:i,height:t,keepDimension:e}){let s,h,n;return ithis.maxWidth&&(h=this.maxWidth),tthis.maxHeight&&(s=this.maxHeight),e?(h&&(i=h),s&&(t=s),n=i/t,this.isValidRatio(n)||(n=this.enforceValidRatio(n),({width:i,height:t}=this.getRatioBox({ratio:n,width:i,height:t,keepDimension:e})),(i>this.arenaWidth||t>this.arenaHeight)&&({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n)))):(h||s)&&(n=this.enforceValidRatio(i/t),({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n))),{width:i,height:t}}enforceMaxArea({width:i,height:t,keepDimension:e}){let s=i/t;return"width"===e?s=i/(t=this.maxArea/i):"height"===e?s=(i=this.maxArea/t)/t:t=(i=Math.sqrt(this.maxArea*s))/s,this.isValidRatio(s)||(s=this.enforceValidRatio(s),t=(i=Math.sqrt(this.maxArea*s))/s),{width:i,height:t}}checkRatio(i){if(this.originalSize){const t=this.originalSize.width/this.originalSize.height,e=i.width/i.height,s=(e-t)/t*100;if(Math.abs(s)>1)throw new Error(`srcissors: Displayed image has a different image ratio than the one configured in 'originalRatio': ${t} vs ${e}`)}}isWidthRestricting(){return this.viewRatio>=this.imageRatio}getRatioBox({ratio:i,width:t,height:e,keepDimension:s}){return"width"===s||null==e?e=t/i:"height"===s||null==t?t=e*i:e=t/i,{width:t,height:e}}centerAlign(i,t,e){let s,h,n,o;return i/t>e?(h=t*e,n=(i-h)/2):(s=i/e,o=(t-s)/2),{x:n||0,y:o||0,width:h||i,height:s||t}}min(i){let t=i[0];for(const e of i)e{this.changeDispatch=void 0,this.changeEvent.fire(this.getCrop())},0))}debug(){const i=i=>Math.round(10*i)/10,t={arena:`${i(this.arenaWidth)}x${i(this.arenaHeight)}`,view:`${i(this.viewWidth)}x${i(this.viewHeight)}`,image:`${i(this.imageWidth)}x${i(this.imageHeight)}`,preview:`${i(this.preview.width)}x${i(this.preview.height)}`,previewXy:`${i(this.preview.x)}x${i(this.preview.y)}`};return console.log(t),t}}const n={new({arena:t,url:e,fixedWidth:s,fixedHeight:n,minWidth:o,minHeight:a,minRatio:r,maxRatio:g,maxArea:d,originalSize:m,zoomStep:w,crop:l,actions:c,minResolution:u,surroundingImageOpacity:p,showSurroundingImage:v}){const x=(t=i(t)).find(".crop-view"),R=x.find(".crop-preview"),z=i("");R.append(z);let f=x.find(".crop-outline");f.length||(f=void 0);const y={pan:!0,zoomOnDoubleClick:!0,resize:!0,resizeHorizontal:!s,resizeVertical:!n};return i.extend(y,c),null==w&&(w=1.25),null==o&&(o=50),null==a&&(a=50),new h({url:e,crop:l,arena:t,view:x,img:z,outline:f,showSurroundingImage:v,surroundingImageOpacity:p,fixedWidth:s,fixedHeight:n,minViewWidth:o,minViewHeight:a,minViewRatio:r,maxViewRatio:g,maxArea:d,originalSize:m,zoomStep:w,actions:y,minResolution:u})}};export{n as default}; //# sourceMappingURL=srcissors.js.map \ No newline at end of file diff --git a/examples/srcissors.js.map b/examples/srcissors.js.map index 6df6d40..ff99106 100644 --- a/examples/srcissors.js.map +++ b/examples/srcissors.js.map @@ -1 +1 @@ -{"version":3,"file":"./srcissors.js","mappings":"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","sources":["webpack://srcissors/./src/preview.js","webpack://srcissors/./src/events.js","webpack://srcissors/./src/crop.js","webpack://srcissors/./src/srcissors.js"],"sourcesContent":["import $ from 'jquery'\n\nexport default class Preview {\n constructor({onReady, img, opacity, outline}) {\n this.onReady = onReady\n this.img = img\n this.opacity = opacity\n this.outline = outline\n this.x = this.y = 0\n this.width = this.height = 0\n\n this.img.on('load', () => {\n const width = this.img.width()\n const height = this.img.height()\n this.ratio = width / height\n\n this.onReady({width, height})\n this.img.show()\n })\n }\n\n setImage({url}) {\n this.url = url\n this.img.attr('src', this.url)\n if (this.outline) this.setBackgroundImage({url: this.url})\n }\n\n setBackgroundImage({url}) {\n if (this.opacity > 0) {\n const bgImg = $('').css({opacity: this.opacity}).attr('src', url)\n this.outline.append(bgImg)\n }\n }\n\n reset() {\n this.url = undefined\n this.x = this.y = 0\n this.width = this.height = 0\n this.img.attr('src', '')\n this.img.css({width: '', height: '', transform: ''})\n if (this.outline) this.outline.css({transform: ''}).html('')\n }\n\n setWidth(width) {\n this.img.css({width: `${width}px`, height: 'auto'})\n const height = width / this.ratio\n this.updateImageDimensions({width, height})\n }\n\n setHeight(height) {\n this.img.css({width: 'auto', height: `${height}px`})\n const width = height * this.ratio\n this.updateImageDimensions({width, height})\n }\n\n updateImageDimensions({width, height}) {\n this.width = width\n this.height = height\n if (this.outline) this.outline.css({width: `${this.width}px`, height: `${this.height}px`})\n }\n\n pan(x1, y1) {\n // Without rounding some numbers would not be set to css.\n // e.g: '-5.14957320384e-14'\n this.x = x1\n this.y = y1\n const x = Math.round(this.x)\n const y = Math.round(this.y)\n this.img.css({transform: `translate(-${x}px, -${y}px)`})\n if (this.outline) this.outline.css({transform: `translate(-${x}px, -${y}px)`})\n }\n}\n","import $ from 'jquery'\n\nconst getPageCoordinates = function (event) {\n if (event.type.includes('touch')) {\n return {\n pageX: event.originalEvent.changedTouches[0].pageX,\n pageY: event.originalEvent.changedTouches[0].pageY\n }\n }\n return {pageX: event.pageX, pageY: event.pageY}\n}\n\nexport default class Events {\n constructor({parent, view, horizontal, vertical, actions}) {\n this.parent = parent\n this.view = view\n this.doubleClickThreshold = 300\n\n // setup events\n if (actions.pan) {\n this.pan()\n }\n if (actions.zoomOnDoubleClick) {\n this.doubleClick()\n }\n if (actions.resize) {\n this.resizeView({\n horizontal: actions.resizeHorizontal,\n vertical: actions.resizeVertical\n })\n }\n\n this.preventBrowserDragDrop()\n this.responsiveArena()\n }\n\n pan() {\n const $doc = $(document)\n this.view.on('mousedown.srcissors touchstart.srcissors', (e1) => {\n const panData = {\n startX: this.parent.preview.x,\n startY: this.parent.preview.y\n }\n\n e1.preventDefault()\n $doc\n .on('mousemove.srcissors-pan touchmove.srcissors-pan', (e2) => {\n const {pageX, pageY} = getPageCoordinates(e2)\n const {pageX: prevPageX, pageY: prevPageY} = getPageCoordinates(e1)\n panData.dx = pageX - prevPageX\n panData.dy = pageY - prevPageY\n this.parent.onPan(panData)\n })\n .on('mouseup.srcissors-pan touchend.srcissors-pan', () => {\n $doc.off('mouseup.srcissors-pan touchend.srcissors-pan')\n $doc.off('mousemove.srcissors-pan touchmove.srcissors-pan')\n\n // only trigger panEnd if pan has been called\n if (panData.dx != null) this.parent.onPanEnd()\n })\n })\n }\n\n doubleClick() {\n let lastClick\n\n this.view.on('mousedown.srcissors touchstart.srcissors', (event) => {\n const now = new Date().getTime()\n if (lastClick && lastClick > now - this.doubleClickThreshold) {\n this.parent.onDoubleClick(getPageCoordinates(event))\n }\n lastClick = now\n })\n }\n\n preventBrowserDragDrop() {\n this.view.on('dragstart.srcissors', () => false)\n }\n\n // Resize View\n // -----------\n\n resizeView({horizontal, vertical}) {\n const $template = $('
')\n $template.addClass('resize-handler')\n\n let positions = []\n if (horizontal) positions = positions.concat(['right', 'left'])\n if (vertical) positions = positions.concat(['top', 'bottom'])\n\n positions.forEach((position) => {\n const $handler = $template.clone()\n $handler.addClass(`resize-handler-${position}`)\n $handler.on('mousedown.srcissors touchstart.srcissors', this.getResizeMouseDown(position))\n\n this.view.append($handler)\n })\n }\n\n getResizeMouseDown(position) {\n const $doc = $(document)\n\n return (event) => {\n let {pageX: lastX, pageY: lastY} = getPageCoordinates(event)\n event.stopPropagation()\n\n $doc\n .on('mousemove.srcissors-resize touchmove.srcissors-resize', (e2) => {\n let dx, dy\n const {pageX, pageY} = getPageCoordinates(e2)\n switch (position) {\n case 'top':\n case 'bottom':\n dy = pageY - lastY\n if (position === 'top') {\n dy = -dy\n }\n lastY = pageY\n break\n case 'left':\n case 'right':\n dx = pageX - lastX\n if (position === 'left') {\n dx = -dx\n }\n lastX = pageX\n break\n }\n\n this.parent.onResize({position, dx, dy})\n })\n .on('mouseup.srcissors-resize touchend.srcissors-resize', () => {\n $doc.off('mouseup.srcissors-resize touchmove.srcissors-resize')\n $doc.off('mousemove.srcissors-resize touchend.srcissors-resize')\n\n // only trigger panEnd if pan has been called\n this.parent.onResizeEnd({position})\n })\n }\n }\n\n responsiveArena() {}\n}\n","import $ from 'jquery'\nimport Preview from './preview.js'\nimport Events from './events.js'\n\nexport default class Crop {\n constructor({\n arena,\n view,\n img,\n outline,\n url,\n fixedWidth,\n fixedHeight,\n minViewWidth,\n minViewHeight,\n minViewRatio,\n maxViewRatio,\n originalSize,\n crop,\n zoomStep,\n maxArea,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n // CSS classes\n this.onPreviewReady = this.onPreviewReady.bind(this)\n this.arena = arena\n this.view = view\n this.img = img\n this.outline = outline\n this.fixedWidth = fixedWidth\n this.fixedHeight = fixedHeight\n this.minViewWidth = minViewWidth\n this.minViewHeight = minViewHeight\n this.minViewRatio = minViewRatio\n this.maxViewRatio = maxViewRatio\n this.originalSize = originalSize\n this.actions = actions\n this.minResolution = minResolution\n this.surroundingImageOpacity = surroundingImageOpacity\n this.loadingCssClass = 'crop-view--is-loading'\n this.panningCssClass = 'crop-view--is-panning'\n this.outlineCssClass = 'crop-outline--active'\n\n // State\n this.isPanning = false\n this.initialCrop = crop\n\n // Events\n this.loadEvent = $.Callbacks()\n this.changeEvent = $.Callbacks()\n\n // Sets up the ready event and state\n this.initializeReadyState()\n\n // Confguration\n this.zoomInStep = zoomStep\n this.zoomOutStep = 1 / this.zoomInStep\n\n this.arenaWidth = this.arena.width()\n this.arenaHeight = this.arena.height()\n\n // todo: consider to calculate maxArea with regards to the\n // maximum space an image can within the area. That should\n // be more reliable.\n if (maxArea) this.maxArea = this.arenaWidth * this.arenaHeight * maxArea\n\n if (this.outline) this.setSurroundingImageVisibility(showSurroundingImage)\n\n this.preview = new Preview({\n onReady: this.onPreviewReady,\n img: this.img,\n outline: this.outline,\n opacity: this.surroundingImageOpacity\n })\n\n this.setImage(url)\n }\n\n initializeReadyState() {\n this.isReady = false\n if (this.readyEvent != null) {\n this.readyEvent.empty()\n }\n this.readyEvent = $.Callbacks('memory once')\n }\n\n setImage(url) {\n if (url === this.preview.url) return\n\n if (this.isInitialized) this.preview.reset()\n this.initializeReadyState()\n this.view.addClass(this.loadingCssClass)\n this.preview.setImage({url})\n }\n\n setSurroundingImageVisibility(visibility) {\n // visibility: always|panning|never\n // override opacity in crop-outline--active css class\n this.surroundingImageOpacity = parseFloat(this.surroundingImageOpacity || 0.2)\n\n if (visibility === 'always') {\n this.outline.css('opacity', 1.0)\n } else if (visibility === 'panning') {\n this.outline.css('opacity', null)\n } else {\n // 'never' default\n this.outline.css('opacity', 0)\n this.surroundingImageOpacity = 0\n }\n }\n\n reset() {\n if (!this.isReady) return\n\n this.resize({width: this.imageWidth, height: this.imageHeight})\n this.zoomAllOut()\n }\n\n onPreviewReady(previewImageSize) {\n this.checkRatio(previewImageSize)\n const {width, height} = this.originalSize || previewImageSize\n\n // console.log(this.originalSize, previewImageSize, {width, height})\n this.preview.updateImageDimensions({width, height})\n\n let keepDimension\n if (!this.isInitialized) {\n this.events = new Events({\n parent: this,\n view: this.view,\n actions: this.actions\n })\n }\n\n this.imageWidth = width\n this.imageHeight = height\n this.imageRatio = this.imageWidth / this.imageHeight\n const imageResolution = this.imageWidth * this.imageHeight\n\n if (this.minResolution && this.minResolution > imageResolution) {\n // If the minimal required resolution is bigger than the actual image\n // resolution, we ignore the configuration\n delete this.minResolution\n }\n\n if (this.minResolution) {\n // For any given image resolution with a minimal required resolution\n // we can calculate both, a minimal resolution and a maximal resolution\n const minRatioForResolution = this.minResolution / (this.imageHeight * this.imageHeight)\n if (!this.minViewRatio || this.minViewRatio < minRatioForResolution) {\n this.minViewRatio = minRatioForResolution\n }\n const maxRatioForResolution = (this.imageWidth * this.imageWidth) / this.minResolution\n if (!this.maxViewRatio || this.maxViewRatio > maxRatioForResolution) {\n this.maxViewRatio = maxRatioForResolution\n }\n }\n\n this.calcMaxMinDimensions()\n\n if (this.fixedWidth) {\n keepDimension = 'width'\n }\n if (this.fixedHeight) {\n keepDimension = 'height'\n }\n this.setViewDimensions({\n width: this.imageWidth,\n height: this.imageHeight,\n keepDimension\n })\n\n // ready state\n this.isReady = true\n this.view.removeClass(this.loadingCssClass)\n\n if (!this.isInitialized && this.initialCrop != null) {\n this.setCrop(this.initialCrop)\n } else {\n this.zoomAllOut()\n this.center()\n }\n\n this.isInitialized = true\n this.readyEvent.fire()\n this.loadEvent.fire()\n }\n\n setCrop({x, y, width, height}) {\n if (!this.isReady) {\n this.on('ready', () => this.setCrop({x, y, width, height}))\n return\n }\n\n this.resize({width, height})\n\n const factor = this.viewWidth / width\n const previewWidth = this.imageWidth * factor\n\n this.zoom({width: previewWidth})\n this.pan({x: x * factor, y: y * factor})\n }\n\n getCrop() {\n const factor = this.preview.width / this.imageWidth\n const crop = {\n x: this.preview.x / factor,\n y: this.preview.y / factor,\n width: this.viewWidth / factor,\n height: this.viewHeight / factor\n }\n\n this.roundCrop(crop)\n this.validateCrop(crop)\n return crop\n }\n\n roundCrop(crop) {\n for (const name in crop) {\n const value = crop[name]\n crop[name] = Math.round(value)\n }\n }\n\n validateCrop(crop) {\n const {x, y, width, height} = crop\n if (x < 0) crop.x = 0\n if (y < 0) crop.y = 0\n\n if (x + width > this.imageWidth) {\n crop.width = this.imageWidth - x\n }\n\n if (y + height > this.imageHeight) {\n crop.height = this.imageHeight - y\n }\n\n return crop\n }\n\n setRatio(ratio, keepDimension) {\n let height, width\n if (!this.isReady) {\n this.on('ready', () => this.setRatio(ratio, keepDimension))\n return\n }\n\n ratio = this.enforceValidRatio(ratio)\n\n if (keepDimension === 'height') {\n height = this.viewHeight\n width = height * ratio\n } else {\n width = this.viewWidth\n height = width / ratio\n }\n\n this.resizeFocusPoint = this.getFocusPoint()\n return this.resize({width, height})\n }\n\n // Event handling\n // --------------\n\n onPan(data) {\n if (!this.isPanning) {\n this.isPanning = true\n this.arena.addClass(this.panningCssClass)\n this.outline.addClass(this.outlineCssClass)\n }\n\n const newX = data.startX - data.dx\n const newY = data.startY - data.dy\n this.pan({x: newX, y: newY})\n }\n\n onPanEnd() {\n this.isPanning = false\n this.arena.removeClass(this.panningCssClass)\n return this.outline.removeClass(this.outlineCssClass)\n }\n\n onDoubleClick({pageX, pageY}) {\n const {left, top} = this.view[0].getBoundingClientRect()\n const viewX = pageX - left\n const viewY = pageY - top\n this.zoomIn({viewX, viewY})\n }\n\n onResize({position, dx, dy}) {\n if (!this.isResizing) {\n this.isResizing = true\n this.resizeFocusPoint = this.getFocusPoint()\n }\n\n if (['top', 'bottom'].includes(position)) {\n dy = 2 * dy // Because it's centered we need to change width by factor two\n this.resize({width: this.viewWidth, height: this.viewHeight + dy, keepDimension: 'height'})\n } else if (['left', 'right'].includes(position)) {\n dx = 2 * dx\n this.resize({width: this.viewWidth + dx, height: this.viewHeight, keepDimension: 'width'})\n }\n }\n\n onResizeEnd() {\n this.isResizing = false\n this.resizeFocusPoint = undefined\n }\n\n resize({width, height, keepDimension}) {\n this.setViewDimensions({width, height, keepDimension})\n\n // Update view center of focus point\n if (this.resizeFocusPoint) {\n this.resizeFocusPoint.viewX = this.viewWidth / 2\n this.resizeFocusPoint.viewY = this.viewHeight / 2\n }\n\n // Ensure dimensions and focus\n this.zoom({\n width: this.preview.width,\n height: this.preview.height,\n focusPoint: this.resizeFocusPoint\n })\n }\n\n setViewDimensions({width, height, keepDimension}) {\n if (this.maxArea) {\n ;({width, height} = this.enforceMaxArea({width, height, keepDimension}))\n }\n\n ;({width, height} = this.enforceViewDimensions({width, height, keepDimension}))\n\n this.view.css({width, height})\n this.viewWidth = width\n this.viewHeight = height\n this.viewRatio = width / height\n\n if (this.minResolution) {\n const minZoomPixelWidth = Math.sqrt(this.minResolution * this.viewRatio)\n const minZoomPixelHeight = Math.sqrt(this.minResolution / this.viewRatio)\n this.maxImageWidth = (this.viewWidth / minZoomPixelWidth) * this.imageWidth\n this.maxImageHeight = (this.viewHeight / minZoomPixelHeight) * this.imageHeight\n }\n\n this.fireChange()\n }\n\n // Update view\n // -----------\n\n zoomAllOut() {\n if (this.isWidthRestricting()) {\n this.zoom({width: this.viewWidth})\n } else {\n this.zoom({height: this.viewHeight})\n }\n }\n\n zoomIn(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomInStep\n } else {\n params.height = this.preview.height * this.zoomInStep\n }\n\n this.zoom(params)\n }\n\n zoomOut(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomOutStep\n } else {\n params.height = this.preview.height * this.zoomOutStep\n }\n\n this.zoom(params)\n }\n\n zoom({width, height, viewX, viewY, focusPoint}) {\n if (focusPoint == null) {\n focusPoint = this.getFocusPoint({viewX, viewY})\n }\n\n ;({width, height} = this.enforceZoom({width, height}))\n if (width != null) {\n this.preview.setWidth(width)\n this.fireChange()\n } else if (height != null) {\n this.preview.setHeight(height)\n this.fireChange()\n }\n\n this.focus(focusPoint)\n }\n\n // returns {Object} e.g. percentX: 0.2, percentY: 0.5\n getFocusPoint(param) {\n if (param == null) {\n param = {}\n }\n let {viewX, viewY} = param\n if (viewX == null) {\n viewX = this.viewWidth / 2\n }\n if (viewY == null) {\n viewY = this.viewHeight / 2\n }\n const x = this.preview.x + viewX\n const y = this.preview.y + viewY\n const percentX = x / this.preview.width\n const percentY = y / this.preview.height\n return {percentX, percentY, viewX, viewY}\n }\n\n focus({percentX, percentY, viewX, viewY}) {\n let x = this.preview.width * percentX\n let y = this.preview.height * percentY\n x = x - viewX\n y = y - viewY\n\n this.pan({x, y})\n }\n\n center() {\n const newX = (this.preview.width - this.viewWidth) / 2\n const newY = (this.preview.height - this.viewHeight) / 2\n this.pan({x: newX, y: newY})\n }\n\n // @param { Object }\n // - x {Number} pixel to pan to the left\n // - y {Number} pixels to pan to the top\n pan(data) {\n data = this.enforceXy(data)\n this.preview.pan(data.x, data.y)\n this.fireChange()\n }\n\n // Validations\n // -----------\n\n enforceXy({x, y}) {\n if (x > this.preview.width - this.viewWidth) {\n x = this.preview.width - this.viewWidth\n }\n\n if (x < 0) x = 0\n\n if (y > this.preview.height - this.viewHeight) {\n y = this.preview.height - this.viewHeight\n }\n\n if (y < 0) y = 0\n\n return {x, y}\n }\n\n enforceZoom({width, height}) {\n if (width != null && this.maxImageWidth && width > this.maxImageWidth) {\n // prevent zooming in past the required resolution defined by minResolution\n return {width: this.maxImageWidth}\n }\n\n if (width != null && width < this.viewWidth) {\n // prevent zooming out past covering the view completely\n return {width: this.viewWidth}\n }\n\n if (height != null && this.maxImageHeight && height > this.maxImageHeight) {\n // prevent zooming in past the required resolution defined by minResolution\n return {height: this.maxImageHeight}\n }\n\n if (height != null && height < this.viewHeight) {\n // prevent zooming out past covering the view completely\n return {height: this.viewHeight}\n }\n\n return {width, height}\n }\n\n calcMaxMinDimensions() {\n this.maxWidth = this.min([this.arenaWidth, this.imageWidth])\n this.maxHeight = this.min([this.arenaHeight, this.imageHeight])\n this.minWidth = this.minViewWidth || 0\n this.minHeight = this.minViewHeight || 0\n\n if (this.fixedWidth) this.maxWidth = this.minWidth = this.fixedWidth\n if (this.fixedHeight) this.maxHeight = this.minHeight = this.fixedHeight\n }\n\n areDimensionsValid({width, height, keepDimension}) {\n const ratio = width / height\n\n const invalid =\n width < this.minWidth ||\n width > this.maxWidth ||\n height < this.minHeight ||\n height > this.maxHeight ||\n ratio < this.minViewRatio ||\n ratio > this.maxViewRatio\n\n return !invalid\n }\n\n isValidRatio(ratio) {\n return !(ratio < this.minViewRatio || ratio > this.maxViewRatio)\n }\n\n enforceValidRatio(ratio) {\n if (ratio < this.minViewRatio) return this.minViewRatio\n if (ratio > this.maxViewRatio) return this.maxViewRatio\n return ratio\n }\n\n enforceViewDimensions({width, height, keepDimension}) {\n let newHeight, newWidth, ratio\n if (width < this.minWidth) newWidth = this.minWidth\n if (width > this.maxWidth) newWidth = this.maxWidth\n if (height < this.minHeight) newHeight = this.minHeight\n if (height > this.maxHeight) newHeight = this.maxHeight\n\n if (keepDimension) {\n if (newWidth) width = newWidth\n if (newHeight) height = newHeight\n\n // check max/min ratios\n ratio = width / height\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n ;({width, height} = this.getRatioBox({ratio, width, height, keepDimension}))\n if (width > this.arenaWidth || height > this.arenaHeight) {\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n }\n } else if (newWidth || newHeight) {\n ratio = this.enforceValidRatio(width / height)\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n\n return {width, height}\n }\n\n enforceMaxArea({width, height, keepDimension}) {\n let ratio = width / height\n\n if (keepDimension === 'width') {\n height = this.maxArea / width\n ratio = width / height\n } else if (keepDimension === 'height') {\n width = this.maxArea / height\n ratio = width / height\n } else {\n // keep ratio\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n return {width, height}\n }\n\n checkRatio(previewImageSize) {\n if (this.originalSize) {\n const expectedRatio = this.originalSize.width / this.originalSize.height\n const actualRatio = previewImageSize.width / previewImageSize.height\n const percentageChange = ((actualRatio - expectedRatio) / expectedRatio) * 100\n if (Math.abs(percentageChange) > 1) {\n throw new Error(\n `srcissors: Displayed image has a different image ratio than the ` +\n `one configured in 'originalRatio': ${expectedRatio} vs ${actualRatio}`\n )\n }\n }\n }\n\n // Calculations\n // ------------\n //\n // Ratio: width / height\n // Tall < 1 (Square) < Wide\n // (A ratio less than one is a tall image format and\n // a ratio greater than one is a wide image format)\n\n // Check if the width or height is restricting\n isWidthRestricting() {\n return this.viewRatio >= this.imageRatio\n }\n\n getRatioBox({ratio, width, height, keepDimension}) {\n if (keepDimension === 'width' || height == null) {\n height = width / ratio\n } else if (keepDimension === 'height' || width == null) {\n width = height * ratio\n } else {\n height = width / ratio\n }\n\n return {width, height}\n }\n\n centerAlign(areaWidth, areaHeight, ratio) {\n let height, width, x, y\n if (areaWidth / areaHeight > ratio) {\n width = areaHeight * ratio\n x = (areaWidth - width) / 2\n } else {\n height = areaWidth / ratio\n y = (areaHeight - height) / 2\n }\n\n // return\n return {\n x: x || 0,\n y: y || 0,\n width: width || areaWidth,\n height: height || areaHeight\n }\n }\n\n min(array) {\n let min = array[0]\n for (const number of array) {\n if (number < min) min = number\n }\n\n return min\n }\n\n // Events\n // ------\n\n on(name, callback) {\n return this[`${name}Event`].add(callback)\n }\n\n off(name, callback) {\n return this[`${name}Event`].remove(callback)\n }\n\n // Debounce change events so they are not fired more\n // than once per tick.\n fireChange() {\n if (this.changeDispatch != null) return\n\n this.changeDispatch = setTimeout(() => {\n this.changeDispatch = undefined\n this.changeEvent.fire(this.getCrop())\n }, 0)\n }\n\n // Development helpers\n // -------------------\n\n debug() {\n const r = (num) => Math.round(num * 10) / 10\n\n const obj = {\n arena: `${r(this.arenaWidth)}x${r(this.arenaHeight)}`,\n view: `${r(this.viewWidth)}x${r(this.viewHeight)}`,\n image: `${r(this.imageWidth)}x${r(this.imageHeight)}`,\n preview: `${r(this.preview.width)}x${r(this.preview.height)}`,\n previewXy: `${r(this.preview.x)}x${r(this.preview.y)}`\n }\n\n console.log(obj) // eslint-disable-line no-console\n return obj\n }\n}\n","import $ from 'jquery'\nimport Crop from './crop.js'\n\nexport default {\n new({\n arena,\n url,\n fixedWidth,\n fixedHeight,\n minWidth,\n minHeight,\n minRatio,\n maxRatio,\n maxArea,\n originalSize,\n zoomStep,\n crop,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n arena = $(arena)\n const view = arena.find('.crop-view')\n const preview = view.find('.crop-preview')\n const img = $('')\n preview.append(img)\n let outline = view.find('.crop-outline')\n if (!outline.length) {\n outline = undefined\n }\n\n const allowedActions = {\n pan: true,\n zoomOnDoubleClick: true,\n resize: true,\n resizeHorizontal: !fixedWidth,\n resizeVertical: !fixedHeight\n }\n\n $.extend(allowedActions, actions)\n\n if (zoomStep == null) {\n zoomStep = 1.25\n }\n\n if (minWidth == null) {\n minWidth = 50\n }\n if (minHeight == null) {\n minHeight = 50\n }\n\n return new Crop({\n url, // {String}\n crop, // {Object} Set an inital crop. This is the same as calling setCrop()\n arena, // {jQuery Element}\n view, // {jQuery Element}\n img, // {jQuery Element}\n outline, // {jQuery Element or undefined}\n showSurroundingImage, // {String} always|panning|never\n surroundingImageOpacity, // {Number} e.g. in the 0.0 - 1.0 range\n fixedWidth, // {Number} e.g. 300\n fixedHeight, // {Number} e.g. 500\n minViewWidth: minWidth, // {Number} e.g. 100\n minViewHeight: minHeight, // {Number} e.g. 100\n minViewRatio: minRatio, // {Number} e.g. 1.5/2\n maxViewRatio: maxRatio, // {Number} e.g. 2/1\n maxArea, // {Number} 0.8 -> max 80% of arena area are covered by the preview\n originalSize, // {Object} Original image size, can be used to display a downscaled\n // version of the image in the cropping interface, but use the original\n // size for crop attributes; e.g. {width: 4000, height: 3000}\n zoomStep, // {Number} e.g. 1.25 -> 125%\n actions: allowedActions,\n minResolution\n })\n }\n}\n"],"names":["Preview","constructor","onReady","img","opacity","outline","this","x","y","width","height","on","ratio","show","setImage","url","attr","setBackgroundImage","bgImg","css","append","reset","undefined","transform","html","setWidth","updateImageDimensions","setHeight","pan","x1","y1","Math","round","getPageCoordinates","event","type","includes","pageX","originalEvent","changedTouches","pageY","Events","parent","view","horizontal","vertical","actions","doubleClickThreshold","zoomOnDoubleClick","doubleClick","resize","resizeView","resizeHorizontal","resizeVertical","preventBrowserDragDrop","responsiveArena","$doc","document","e1","panData","startX","preview","startY","preventDefault","e2","prevPageX","prevPageY","dx","dy","onPan","off","onPanEnd","lastClick","now","Date","getTime","onDoubleClick","$template","addClass","positions","concat","forEach","position","$handler","clone","getResizeMouseDown","lastX","lastY","stopPropagation","onResize","onResizeEnd","Crop","arena","fixedWidth","fixedHeight","minViewWidth","minViewHeight","minViewRatio","maxViewRatio","originalSize","crop","zoomStep","maxArea","minResolution","surroundingImageOpacity","showSurroundingImage","onPreviewReady","bind","loadingCssClass","panningCssClass","outlineCssClass","isPanning","initialCrop","loadEvent","changeEvent","initializeReadyState","zoomInStep","zoomOutStep","arenaWidth","arenaHeight","setSurroundingImageVisibility","isReady","readyEvent","empty","isInitialized","visibility","parseFloat","imageWidth","imageHeight","zoomAllOut","previewImageSize","checkRatio","keepDimension","events","imageRatio","imageResolution","minRatioForResolution","maxRatioForResolution","calcMaxMinDimensions","setViewDimensions","removeClass","center","setCrop","fire","factor","viewWidth","previewWidth","zoom","getCrop","viewHeight","roundCrop","validateCrop","name","value","setRatio","enforceValidRatio","resizeFocusPoint","getFocusPoint","data","newX","newY","left","top","getBoundingClientRect","viewX","viewY","zoomIn","isResizing","focusPoint","enforceMaxArea","enforceViewDimensions","viewRatio","minZoomPixelWidth","sqrt","minZoomPixelHeight","maxImageWidth","maxImageHeight","fireChange","isWidthRestricting","params","zoomOut","enforceZoom","focus","param","percentX","percentY","enforceXy","maxWidth","min","maxHeight","minWidth","minHeight","areDimensionsValid","isValidRatio","newHeight","newWidth","getRatioBox","centerAlign","expectedRatio","actualRatio","percentageChange","abs","Error","areaWidth","areaHeight","array","number","callback","add","remove","changeDispatch","setTimeout","debug","r","num","obj","image","previewXy","console","log","minRatio","maxRatio","find","length","allowedActions"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"./srcissors.js","mappings":"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","sources":["webpack://srcissors/./src/preview.js","webpack://srcissors/./src/events.js","webpack://srcissors/./src/crop.js","webpack://srcissors/./src/srcissors.js"],"sourcesContent":["import $ from 'jquery'\n\nexport default class Preview {\n constructor({onReady, img, opacity, outline}) {\n this.onReady = onReady\n this.img = img\n this.opacity = opacity\n this.outline = outline\n this.x = this.y = 0\n this.width = this.height = 0\n\n this.img.on('load', () => {\n const width = this.img.width()\n const height = this.img.height()\n this.ratio = width / height\n\n this.onReady({width, height})\n this.img.show()\n })\n }\n\n setImage({url}) {\n this.url = url\n this.img.attr('src', this.url)\n if (this.outline) this.setBackgroundImage({url: this.url})\n }\n\n setBackgroundImage({url}) {\n if (this.opacity > 0) {\n const bgImg = $('').css({opacity: this.opacity}).attr('src', url)\n this.outline.append(bgImg)\n }\n }\n\n reset() {\n this.url = undefined\n this.x = this.y = 0\n this.width = this.height = 0\n this.img.attr('src', '')\n this.img.css({width: '', height: '', transform: ''})\n if (this.outline) this.outline.css({transform: ''}).html('')\n }\n\n setWidth(width) {\n this.img.css({width: `${width}px`, height: 'auto'})\n const height = width / this.ratio\n this.updateImageDimensions({width, height})\n }\n\n setHeight(height) {\n this.img.css({width: 'auto', height: `${height}px`})\n const width = height * this.ratio\n this.updateImageDimensions({width, height})\n }\n\n updateImageDimensions({width, height}) {\n this.width = width\n this.height = height\n if (this.outline) this.outline.css({width: `${this.width}px`, height: `${this.height}px`})\n }\n\n pan(x1, y1) {\n // Without rounding some numbers would not be set to css.\n // e.g: '-5.14957320384e-14'\n this.x = x1\n this.y = y1\n const x = Math.round(this.x)\n const y = Math.round(this.y)\n this.img.css({transform: `translate(-${x}px, -${y}px)`})\n if (this.outline) this.outline.css({transform: `translate(-${x}px, -${y}px)`})\n }\n}\n","import $ from 'jquery'\n\nconst getPageCoordinates = function (event) {\n if (event.type.includes('touch')) {\n return {\n pageX: event.originalEvent.changedTouches[0].pageX,\n pageY: event.originalEvent.changedTouches[0].pageY\n }\n }\n return {pageX: event.pageX, pageY: event.pageY}\n}\n\nexport default class Events {\n constructor({parent, view, horizontal, vertical, actions}) {\n this.parent = parent\n this.view = view\n this.doubleClickThreshold = 300\n\n // setup events\n if (actions.pan) {\n this.pan()\n }\n if (actions.zoomOnDoubleClick) {\n this.doubleClick()\n }\n if (actions.resize) {\n this.resizeView({\n horizontal: actions.resizeHorizontal,\n vertical: actions.resizeVertical\n })\n }\n\n this.preventBrowserDragDrop()\n this.responsiveArena()\n }\n\n pan() {\n const $doc = $(document)\n this.view.on('mousedown.srcissors touchstart.srcissors', (e1) => {\n const panData = {\n startX: this.parent.preview.x,\n startY: this.parent.preview.y\n }\n\n e1.preventDefault()\n $doc\n .on('mousemove.srcissors-pan touchmove.srcissors-pan', (e2) => {\n const {pageX, pageY} = getPageCoordinates(e2)\n const {pageX: prevPageX, pageY: prevPageY} = getPageCoordinates(e1)\n panData.dx = pageX - prevPageX\n panData.dy = pageY - prevPageY\n this.parent.onPan(panData)\n })\n .on('mouseup.srcissors-pan touchend.srcissors-pan', () => {\n $doc.off('mouseup.srcissors-pan touchend.srcissors-pan')\n $doc.off('mousemove.srcissors-pan touchmove.srcissors-pan')\n\n // only trigger panEnd if pan has been called\n if (panData.dx != null) this.parent.onPanEnd()\n })\n })\n }\n\n doubleClick() {\n let lastClick\n\n this.view.on('mousedown.srcissors touchstart.srcissors', (event) => {\n const now = new Date().getTime()\n if (lastClick && lastClick > now - this.doubleClickThreshold) {\n this.parent.onDoubleClick(getPageCoordinates(event))\n }\n lastClick = now\n })\n }\n\n preventBrowserDragDrop() {\n this.view.on('dragstart.srcissors', () => false)\n }\n\n // Resize View\n // -----------\n\n resizeView({horizontal, vertical}) {\n const $template = $('
')\n $template.addClass('resize-handler')\n\n let positions = []\n if (horizontal) positions = positions.concat(['right', 'left'])\n if (vertical) positions = positions.concat(['top', 'bottom'])\n\n positions.forEach((position) => {\n const $handler = $template.clone()\n $handler.addClass(`resize-handler-${position}`)\n $handler.on('mousedown.srcissors touchstart.srcissors', this.getResizeMouseDown(position))\n\n this.view.append($handler)\n })\n }\n\n getResizeMouseDown(position) {\n const $doc = $(document)\n\n return (event) => {\n let {pageX: lastX, pageY: lastY} = getPageCoordinates(event)\n event.stopPropagation()\n\n $doc\n .on('mousemove.srcissors-resize touchmove.srcissors-resize', (e2) => {\n let dx, dy\n const {pageX, pageY} = getPageCoordinates(e2)\n switch (position) {\n case 'top':\n case 'bottom':\n dy = pageY - lastY\n if (position === 'top') {\n dy = -dy\n }\n lastY = pageY\n break\n case 'left':\n case 'right':\n dx = pageX - lastX\n if (position === 'left') {\n dx = -dx\n }\n lastX = pageX\n break\n }\n\n this.parent.onResize({position, dx, dy})\n })\n .on('mouseup.srcissors-resize touchend.srcissors-resize', () => {\n $doc.off('mouseup.srcissors-resize touchmove.srcissors-resize')\n $doc.off('mousemove.srcissors-resize touchend.srcissors-resize')\n\n // only trigger panEnd if pan has been called\n this.parent.onResizeEnd({position})\n })\n }\n }\n\n responsiveArena() {}\n}\n","import $ from 'jquery'\nimport Preview from './preview.js'\nimport Events from './events.js'\n\nexport default class Crop {\n constructor({\n arena,\n view,\n img,\n outline,\n url,\n fixedWidth,\n fixedHeight,\n minViewWidth,\n minViewHeight,\n minViewRatio,\n maxViewRatio,\n originalSize,\n crop,\n zoomStep,\n maxArea,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n // CSS classes\n this.onPreviewReady = this.onPreviewReady.bind(this)\n this.arena = arena\n this.view = view\n this.img = img\n this.outline = outline\n this.fixedWidth = fixedWidth\n this.fixedHeight = fixedHeight\n this.minViewWidth = minViewWidth\n this.minViewHeight = minViewHeight\n this.minViewRatio = minViewRatio\n this.maxViewRatio = maxViewRatio\n this.originalSize = originalSize\n this.actions = actions\n this.minResolution = minResolution\n this.surroundingImageOpacity = surroundingImageOpacity\n this.loadingCssClass = 'crop-view--is-loading'\n this.panningCssClass = 'crop-view--is-panning'\n this.outlineCssClass = 'crop-outline--active'\n\n // State\n this.isPanning = false\n this.initialCrop = crop\n\n // Events\n this.loadEvent = $.Callbacks()\n this.changeEvent = $.Callbacks()\n\n // Sets up the ready event and state\n this.initializeReadyState()\n\n // Confguration\n this.zoomInStep = zoomStep\n this.zoomOutStep = 1 / this.zoomInStep\n\n this.arenaWidth = this.arena.width()\n this.arenaHeight = this.arena.height()\n\n // todo: consider to calculate maxArea with regards to the\n // maximum space an image can within the area. That should\n // be more reliable.\n if (maxArea) this.maxArea = this.arenaWidth * this.arenaHeight * maxArea\n\n if (this.outline) this.setSurroundingImageVisibility(showSurroundingImage)\n\n this.preview = new Preview({\n onReady: this.onPreviewReady,\n img: this.img,\n outline: this.outline,\n opacity: this.surroundingImageOpacity\n })\n\n this.setImage(url)\n }\n\n initializeReadyState() {\n this.isReady = false\n if (this.readyEvent != null) {\n this.readyEvent.empty()\n }\n this.readyEvent = $.Callbacks('memory once')\n }\n\n setImage(url) {\n if (url === this.preview.url) return\n\n if (this.isInitialized) this.preview.reset()\n this.initializeReadyState()\n this.view.addClass(this.loadingCssClass)\n this.preview.setImage({url})\n }\n\n setSurroundingImageVisibility(visibility) {\n // visibility: always|panning|never\n // override opacity in crop-outline--active css class\n this.surroundingImageOpacity = parseFloat(this.surroundingImageOpacity || 0.2)\n\n if (visibility === 'always') {\n this.outline.css('opacity', 1.0)\n } else if (visibility === 'panning') {\n this.outline.css('opacity', null)\n } else {\n // 'never' default\n this.outline.css('opacity', 0)\n this.surroundingImageOpacity = 0\n }\n }\n\n reset() {\n if (!this.isReady) return\n\n this.resize({width: this.imageWidth, height: this.imageHeight})\n this.zoomAllOut()\n }\n\n onPreviewReady(previewImageSize) {\n this.checkRatio(previewImageSize)\n const {width, height} = this.originalSize || previewImageSize\n\n // console.log(this.originalSize, previewImageSize, {width, height})\n this.preview.updateImageDimensions({width, height})\n\n let keepDimension\n if (!this.isInitialized) {\n this.events = new Events({\n parent: this,\n view: this.view,\n actions: this.actions\n })\n }\n\n this.imageWidth = width\n this.imageHeight = height\n this.imageRatio = this.imageWidth / this.imageHeight\n const imageResolution = this.imageWidth * this.imageHeight\n\n if (this.minResolution && this.minResolution > imageResolution) {\n // If the minimal required resolution is bigger than the actual image\n // resolution, we ignore the configuration\n delete this.minResolution\n }\n\n if (this.minResolution) {\n // For any given image resolution with a minimal required resolution\n // we can calculate both, a minimal resolution and a maximal resolution\n const minRatioForResolution = this.minResolution / (this.imageHeight * this.imageHeight)\n if (!this.minViewRatio || this.minViewRatio < minRatioForResolution) {\n this.minViewRatio = minRatioForResolution\n }\n const maxRatioForResolution = (this.imageWidth * this.imageWidth) / this.minResolution\n if (!this.maxViewRatio || this.maxViewRatio > maxRatioForResolution) {\n this.maxViewRatio = maxRatioForResolution\n }\n }\n\n this.calcMaxMinDimensions()\n\n if (this.fixedWidth) {\n keepDimension = 'width'\n }\n if (this.fixedHeight) {\n keepDimension = 'height'\n }\n this.setViewDimensions({\n width: this.imageWidth,\n height: this.imageHeight,\n keepDimension\n })\n\n // ready state\n this.isReady = true\n this.view.removeClass(this.loadingCssClass)\n\n if (!this.isInitialized && this.initialCrop != null) {\n this.setCrop(this.initialCrop)\n } else {\n this.zoomAllOut()\n this.center()\n }\n\n this.isInitialized = true\n this.readyEvent.fire()\n this.loadEvent.fire()\n }\n\n setCrop({x, y, width, height}) {\n if (!this.isReady) {\n this.on('ready', () => this.setCrop({x, y, width, height}))\n return\n }\n\n this.resize({width, height})\n\n const factor = this.viewWidth / width\n const previewWidth = this.imageWidth * factor\n\n this.zoom({width: previewWidth})\n this.pan({x: x * factor, y: y * factor})\n }\n\n getCrop() {\n const factor = this.preview.width / this.imageWidth\n const crop = {\n x: this.preview.x / factor,\n y: this.preview.y / factor,\n width: this.viewWidth / factor,\n height: this.viewHeight / factor\n }\n\n this.roundCrop(crop)\n this.validateCrop(crop)\n return crop\n }\n\n roundCrop(crop) {\n for (const name in crop) {\n const value = crop[name]\n crop[name] = Math.round(value)\n }\n }\n\n validateCrop(crop) {\n const {x, y, width, height} = crop\n if (x < 0) crop.x = 0\n if (y < 0) crop.y = 0\n\n if (x + width > this.imageWidth) {\n crop.width = this.imageWidth - x\n }\n\n if (y + height > this.imageHeight) {\n crop.height = this.imageHeight - y\n }\n\n return crop\n }\n\n setRatio(ratio, keepDimension) {\n let height, width\n if (!this.isReady) {\n this.on('ready', () => this.setRatio(ratio, keepDimension))\n return\n }\n\n ratio = this.enforceValidRatio(ratio)\n\n if (keepDimension === 'height') {\n height = this.viewHeight\n width = height * ratio\n } else {\n width = this.viewWidth\n height = width / ratio\n }\n\n this.resizeFocusPoint = this.getFocusPoint()\n return this.resize({width, height})\n }\n\n // Event handling\n // --------------\n\n onPan(data) {\n if (!this.isPanning) {\n this.isPanning = true\n this.arena.addClass(this.panningCssClass)\n this.outline.addClass(this.outlineCssClass)\n }\n\n const newX = data.startX - data.dx\n const newY = data.startY - data.dy\n this.pan({x: newX, y: newY})\n }\n\n onPanEnd() {\n this.isPanning = false\n this.arena.removeClass(this.panningCssClass)\n return this.outline.removeClass(this.outlineCssClass)\n }\n\n onDoubleClick({pageX, pageY}) {\n const {left, top} = this.view[0].getBoundingClientRect()\n const viewX = pageX - left\n const viewY = pageY - top\n this.zoomIn({viewX, viewY})\n }\n\n onResize({position, dx, dy}) {\n if (!this.isResizing) {\n this.isResizing = true\n this.resizeFocusPoint = this.getFocusPoint()\n }\n\n if (['top', 'bottom'].includes(position)) {\n dy = 2 * dy // Because it's centered we need to change width by factor two\n this.resize({width: this.viewWidth, height: this.viewHeight + dy, keepDimension: 'height'})\n } else if (['left', 'right'].includes(position)) {\n dx = 2 * dx\n this.resize({width: this.viewWidth + dx, height: this.viewHeight, keepDimension: 'width'})\n }\n }\n\n onResizeEnd() {\n this.isResizing = false\n this.resizeFocusPoint = undefined\n }\n\n resize({width, height, keepDimension}) {\n this.setViewDimensions({width, height, keepDimension})\n\n // Update view center of focus point\n if (this.resizeFocusPoint) {\n this.resizeFocusPoint.viewX = this.viewWidth / 2\n this.resizeFocusPoint.viewY = this.viewHeight / 2\n }\n\n // Ensure dimensions and focus\n this.zoom({\n width: this.preview.width,\n height: this.preview.height,\n focusPoint: this.resizeFocusPoint\n })\n }\n\n setViewDimensions({width, height, keepDimension}) {\n if (this.maxArea) {\n ;({width, height} = this.enforceMaxArea({width, height, keepDimension}))\n }\n\n ;({width, height} = this.enforceViewDimensions({width, height, keepDimension}))\n\n this.view.css({width, height})\n this.viewWidth = width\n this.viewHeight = height\n this.viewRatio = width / height\n\n if (this.minResolution) {\n const minZoomPixelWidth = Math.sqrt(this.minResolution * this.viewRatio)\n const minZoomPixelHeight = Math.sqrt(this.minResolution / this.viewRatio)\n const maxImageWidth = (this.viewWidth / minZoomPixelWidth) * this.imageWidth\n const maxImageHeight = (this.viewHeight / minZoomPixelHeight) * this.imageHeight\n\n // Depending on the image size and configured ratio, the required\n // resolution cannot always be reached.\n if (maxImageWidth >= this.viewWidth && maxImageHeight >= this.viewHeight) {\n this.maxImageWidth = maxImageWidth\n this.maxImageHeight = maxImageHeight\n } else {\n // minResolution is unreachable at this ratio. Lock the zoom at the\n // most zoomed-out state, where the crop covers the largest possible\n // image area.\n this.maxImageWidth = Math.max(this.viewWidth, this.viewHeight * this.imageRatio)\n this.maxImageHeight = this.maxImageWidth / this.imageRatio\n }\n }\n\n this.fireChange()\n }\n\n // Update view\n // -----------\n\n zoomAllOut() {\n if (this.isWidthRestricting()) {\n this.zoom({width: this.viewWidth})\n } else {\n this.zoom({height: this.viewHeight})\n }\n }\n\n zoomIn(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomInStep\n } else {\n params.height = this.preview.height * this.zoomInStep\n }\n\n this.zoom(params)\n }\n\n zoomOut(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomOutStep\n } else {\n params.height = this.preview.height * this.zoomOutStep\n }\n\n this.zoom(params)\n }\n\n zoom({width, height, viewX, viewY, focusPoint}) {\n if (focusPoint == null) {\n focusPoint = this.getFocusPoint({viewX, viewY})\n }\n\n ;({width, height} = this.enforceZoom({width, height}))\n if (width != null) {\n this.preview.setWidth(width)\n this.fireChange()\n } else if (height != null) {\n this.preview.setHeight(height)\n this.fireChange()\n }\n\n this.focus(focusPoint)\n }\n\n // returns {Object} e.g. percentX: 0.2, percentY: 0.5\n getFocusPoint(param) {\n if (param == null) {\n param = {}\n }\n let {viewX, viewY} = param\n if (viewX == null) {\n viewX = this.viewWidth / 2\n }\n if (viewY == null) {\n viewY = this.viewHeight / 2\n }\n const x = this.preview.x + viewX\n const y = this.preview.y + viewY\n const percentX = x / this.preview.width\n const percentY = y / this.preview.height\n return {percentX, percentY, viewX, viewY}\n }\n\n focus({percentX, percentY, viewX, viewY}) {\n let x = this.preview.width * percentX\n let y = this.preview.height * percentY\n x = x - viewX\n y = y - viewY\n\n this.pan({x, y})\n }\n\n center() {\n const newX = (this.preview.width - this.viewWidth) / 2\n const newY = (this.preview.height - this.viewHeight) / 2\n this.pan({x: newX, y: newY})\n }\n\n // @param { Object }\n // - x {Number} pixel to pan to the left\n // - y {Number} pixels to pan to the top\n pan(data) {\n data = this.enforceXy(data)\n this.preview.pan(data.x, data.y)\n this.fireChange()\n }\n\n // Validations\n // -----------\n\n enforceXy({x, y}) {\n if (x > this.preview.width - this.viewWidth) {\n x = this.preview.width - this.viewWidth\n }\n\n if (x < 0) x = 0\n\n if (y > this.preview.height - this.viewHeight) {\n y = this.preview.height - this.viewHeight\n }\n\n if (y < 0) y = 0\n\n return {x, y}\n }\n\n enforceZoom({width, height}) {\n if (width != null && this.maxImageWidth && width > this.maxImageWidth) {\n // prevent zooming in past the required resolution defined by minResolution\n return {width: this.maxImageWidth}\n }\n\n if (width != null && width < this.viewWidth) {\n // prevent zooming out past covering the view completely\n return {width: this.viewWidth}\n }\n\n if (height != null && this.maxImageHeight && height > this.maxImageHeight) {\n // prevent zooming in past the required resolution defined by minResolution\n return {height: this.maxImageHeight}\n }\n\n if (height != null && height < this.viewHeight) {\n // prevent zooming out past covering the view completely\n return {height: this.viewHeight}\n }\n\n return {width, height}\n }\n\n calcMaxMinDimensions() {\n this.maxWidth = this.min([this.arenaWidth, this.imageWidth])\n this.maxHeight = this.min([this.arenaHeight, this.imageHeight])\n this.minWidth = this.minViewWidth || 0\n this.minHeight = this.minViewHeight || 0\n\n if (this.fixedWidth) this.maxWidth = this.minWidth = this.fixedWidth\n if (this.fixedHeight) this.maxHeight = this.minHeight = this.fixedHeight\n }\n\n areDimensionsValid({width, height, keepDimension}) {\n const ratio = width / height\n\n const invalid =\n width < this.minWidth ||\n width > this.maxWidth ||\n height < this.minHeight ||\n height > this.maxHeight ||\n ratio < this.minViewRatio ||\n ratio > this.maxViewRatio\n\n return !invalid\n }\n\n isValidRatio(ratio) {\n return !(ratio < this.minViewRatio || ratio > this.maxViewRatio)\n }\n\n enforceValidRatio(ratio) {\n if (ratio < this.minViewRatio) return this.minViewRatio\n if (ratio > this.maxViewRatio) return this.maxViewRatio\n return ratio\n }\n\n enforceViewDimensions({width, height, keepDimension}) {\n let newHeight, newWidth, ratio\n if (width < this.minWidth) newWidth = this.minWidth\n if (width > this.maxWidth) newWidth = this.maxWidth\n if (height < this.minHeight) newHeight = this.minHeight\n if (height > this.maxHeight) newHeight = this.maxHeight\n\n if (keepDimension) {\n if (newWidth) width = newWidth\n if (newHeight) height = newHeight\n\n // check max/min ratios\n ratio = width / height\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n ;({width, height} = this.getRatioBox({ratio, width, height, keepDimension}))\n if (width > this.arenaWidth || height > this.arenaHeight) {\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n }\n } else if (newWidth || newHeight) {\n ratio = this.enforceValidRatio(width / height)\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n\n return {width, height}\n }\n\n enforceMaxArea({width, height, keepDimension}) {\n let ratio = width / height\n\n if (keepDimension === 'width') {\n height = this.maxArea / width\n ratio = width / height\n } else if (keepDimension === 'height') {\n width = this.maxArea / height\n ratio = width / height\n } else {\n // keep ratio\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n return {width, height}\n }\n\n checkRatio(previewImageSize) {\n if (this.originalSize) {\n const expectedRatio = this.originalSize.width / this.originalSize.height\n const actualRatio = previewImageSize.width / previewImageSize.height\n const percentageChange = ((actualRatio - expectedRatio) / expectedRatio) * 100\n if (Math.abs(percentageChange) > 1) {\n throw new Error(\n `srcissors: Displayed image has a different image ratio than the ` +\n `one configured in 'originalRatio': ${expectedRatio} vs ${actualRatio}`\n )\n }\n }\n }\n\n // Calculations\n // ------------\n //\n // Ratio: width / height\n // Tall < 1 (Square) < Wide\n // (A ratio less than one is a tall image format and\n // a ratio greater than one is a wide image format)\n\n // Check if the width or height is restricting\n isWidthRestricting() {\n return this.viewRatio >= this.imageRatio\n }\n\n getRatioBox({ratio, width, height, keepDimension}) {\n if (keepDimension === 'width' || height == null) {\n height = width / ratio\n } else if (keepDimension === 'height' || width == null) {\n width = height * ratio\n } else {\n height = width / ratio\n }\n\n return {width, height}\n }\n\n centerAlign(areaWidth, areaHeight, ratio) {\n let height, width, x, y\n if (areaWidth / areaHeight > ratio) {\n width = areaHeight * ratio\n x = (areaWidth - width) / 2\n } else {\n height = areaWidth / ratio\n y = (areaHeight - height) / 2\n }\n\n // return\n return {\n x: x || 0,\n y: y || 0,\n width: width || areaWidth,\n height: height || areaHeight\n }\n }\n\n min(array) {\n let min = array[0]\n for (const number of array) {\n if (number < min) min = number\n }\n\n return min\n }\n\n // Events\n // ------\n\n on(name, callback) {\n return this[`${name}Event`].add(callback)\n }\n\n off(name, callback) {\n return this[`${name}Event`].remove(callback)\n }\n\n // Debounce change events so they are not fired more\n // than once per tick.\n fireChange() {\n if (this.changeDispatch != null) return\n\n this.changeDispatch = setTimeout(() => {\n this.changeDispatch = undefined\n this.changeEvent.fire(this.getCrop())\n }, 0)\n }\n\n // Development helpers\n // -------------------\n\n debug() {\n const r = (num) => Math.round(num * 10) / 10\n\n const obj = {\n arena: `${r(this.arenaWidth)}x${r(this.arenaHeight)}`,\n view: `${r(this.viewWidth)}x${r(this.viewHeight)}`,\n image: `${r(this.imageWidth)}x${r(this.imageHeight)}`,\n preview: `${r(this.preview.width)}x${r(this.preview.height)}`,\n previewXy: `${r(this.preview.x)}x${r(this.preview.y)}`\n }\n\n console.log(obj) // eslint-disable-line no-console\n return obj\n }\n}\n","import $ from 'jquery'\nimport Crop from './crop.js'\n\nexport default {\n new({\n arena,\n url,\n fixedWidth,\n fixedHeight,\n minWidth,\n minHeight,\n minRatio,\n maxRatio,\n maxArea,\n originalSize,\n zoomStep,\n crop,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n arena = $(arena)\n const view = arena.find('.crop-view')\n const preview = view.find('.crop-preview')\n const img = $('')\n preview.append(img)\n let outline = view.find('.crop-outline')\n if (!outline.length) {\n outline = undefined\n }\n\n const allowedActions = {\n pan: true,\n zoomOnDoubleClick: true,\n resize: true,\n resizeHorizontal: !fixedWidth,\n resizeVertical: !fixedHeight\n }\n\n $.extend(allowedActions, actions)\n\n if (zoomStep == null) {\n zoomStep = 1.25\n }\n\n if (minWidth == null) {\n minWidth = 50\n }\n if (minHeight == null) {\n minHeight = 50\n }\n\n return new Crop({\n url, // {String}\n crop, // {Object} Set an inital crop. This is the same as calling setCrop()\n arena, // {jQuery Element}\n view, // {jQuery Element}\n img, // {jQuery Element}\n outline, // {jQuery Element or undefined}\n showSurroundingImage, // {String} always|panning|never\n surroundingImageOpacity, // {Number} e.g. in the 0.0 - 1.0 range\n fixedWidth, // {Number} e.g. 300\n fixedHeight, // {Number} e.g. 500\n minViewWidth: minWidth, // {Number} e.g. 100\n minViewHeight: minHeight, // {Number} e.g. 100\n minViewRatio: minRatio, // {Number} e.g. 1.5/2\n maxViewRatio: maxRatio, // {Number} e.g. 2/1\n maxArea, // {Number} 0.8 -> max 80% of arena area are covered by the preview\n originalSize, // {Object} Original image size, can be used to display a downscaled\n // version of the image in the cropping interface, but use the original\n // size for crop attributes; e.g. {width: 4000, height: 3000}\n zoomStep, // {Number} e.g. 1.25 -> 125%\n actions: allowedActions,\n minResolution\n })\n }\n}\n"],"names":["Preview","constructor","onReady","img","opacity","outline","this","x","y","width","height","on","ratio","show","setImage","url","attr","setBackgroundImage","bgImg","__WEBPACK_EXTERNAL_MODULE_jquery_default__","css","append","reset","undefined","transform","html","setWidth","updateImageDimensions","setHeight","pan","x1","y1","Math","round","getPageCoordinates","event","type","includes","pageX","originalEvent","changedTouches","pageY","Events","parent","view","horizontal","vertical","actions","doubleClickThreshold","zoomOnDoubleClick","doubleClick","resize","resizeView","resizeHorizontal","resizeVertical","preventBrowserDragDrop","responsiveArena","$doc","document","e1","panData","startX","preview","startY","preventDefault","e2","prevPageX","prevPageY","dx","dy","onPan","off","onPanEnd","lastClick","now","Date","getTime","onDoubleClick","$template","addClass","positions","concat","forEach","position","$handler","clone","getResizeMouseDown","lastX","lastY","stopPropagation","onResize","onResizeEnd","Crop","arena","fixedWidth","fixedHeight","minViewWidth","minViewHeight","minViewRatio","maxViewRatio","originalSize","crop","zoomStep","maxArea","minResolution","surroundingImageOpacity","showSurroundingImage","onPreviewReady","bind","loadingCssClass","panningCssClass","outlineCssClass","isPanning","initialCrop","loadEvent","Callbacks","changeEvent","initializeReadyState","zoomInStep","zoomOutStep","arenaWidth","arenaHeight","setSurroundingImageVisibility","isReady","readyEvent","empty","isInitialized","visibility","parseFloat","imageWidth","imageHeight","zoomAllOut","previewImageSize","checkRatio","keepDimension","events","imageRatio","imageResolution","minRatioForResolution","maxRatioForResolution","calcMaxMinDimensions","setViewDimensions","removeClass","center","setCrop","fire","factor","viewWidth","previewWidth","zoom","getCrop","viewHeight","roundCrop","validateCrop","name","value","setRatio","enforceValidRatio","resizeFocusPoint","getFocusPoint","data","newX","newY","left","top","getBoundingClientRect","viewX","viewY","zoomIn","isResizing","focusPoint","enforceMaxArea","enforceViewDimensions","viewRatio","minZoomPixelWidth","sqrt","minZoomPixelHeight","maxImageWidth","maxImageHeight","max","fireChange","isWidthRestricting","params","zoomOut","enforceZoom","focus","param","percentX","percentY","enforceXy","maxWidth","min","maxHeight","minWidth","minHeight","areDimensionsValid","isValidRatio","newHeight","newWidth","getRatioBox","centerAlign","expectedRatio","actualRatio","percentageChange","abs","Error","areaWidth","areaHeight","array","number","callback","add","remove","changeDispatch","setTimeout","debug","r","num","obj","image","previewXy","console","log","srcissors","minRatio","maxRatio","find","length","allowedActions","extend"],"sourceRoot":""} \ No newline at end of file diff --git a/src/crop.js b/src/crop.js index c3cf010..56bc86c 100644 --- a/src/crop.js +++ b/src/crop.js @@ -342,8 +342,21 @@ export default class Crop { if (this.minResolution) { const minZoomPixelWidth = Math.sqrt(this.minResolution * this.viewRatio) const minZoomPixelHeight = Math.sqrt(this.minResolution / this.viewRatio) - this.maxImageWidth = (this.viewWidth / minZoomPixelWidth) * this.imageWidth - this.maxImageHeight = (this.viewHeight / minZoomPixelHeight) * this.imageHeight + const maxImageWidth = (this.viewWidth / minZoomPixelWidth) * this.imageWidth + const maxImageHeight = (this.viewHeight / minZoomPixelHeight) * this.imageHeight + + // Depending on the image size and configured ratio, the required + // resolution cannot always be reached. + if (maxImageWidth >= this.viewWidth && maxImageHeight >= this.viewHeight) { + this.maxImageWidth = maxImageWidth + this.maxImageHeight = maxImageHeight + } else { + // minResolution is unreachable at this ratio. Lock the zoom at the + // most zoomed-out state, where the crop covers the largest possible + // image area. + this.maxImageWidth = Math.max(this.viewWidth, this.viewHeight * this.imageRatio) + this.maxImageHeight = this.maxImageWidth / this.imageRatio + } } this.fireChange() diff --git a/srcissors.js b/srcissors.js index 903213a..b653cb3 100644 --- a/srcissors.js +++ b/srcissors.js @@ -1,2 +1,2 @@ -import{default as i}from"jquery";class t{constructor({onReady:i,img:t,opacity:e,outline:s}){this.onReady=i,this.img=t,this.opacity=e,this.outline=s,this.x=this.y=0,this.width=this.height=0,this.img.on("load",()=>{const i=this.img.width(),t=this.img.height();this.ratio=i/t,this.onReady({width:i,height:t}),this.img.show()})}setImage({url:i}){this.url=i,this.img.attr("src",this.url),this.outline&&this.setBackgroundImage({url:this.url})}setBackgroundImage({url:t}){if(this.opacity>0){const e=i("").css({opacity:this.opacity}).attr("src",t);this.outline.append(e)}}reset(){this.url=void 0,this.x=this.y=0,this.width=this.height=0,this.img.attr("src",""),this.img.css({width:"",height:"",transform:""}),this.outline&&this.outline.css({transform:""}).html("")}setWidth(i){this.img.css({width:`${i}px`,height:"auto"});const t=i/this.ratio;this.updateImageDimensions({width:i,height:t})}setHeight(i){this.img.css({width:"auto",height:`${i}px`});const t=i*this.ratio;this.updateImageDimensions({width:t,height:i})}updateImageDimensions({width:i,height:t}){this.width=i,this.height=t,this.outline&&this.outline.css({width:`${this.width}px`,height:`${this.height}px`})}pan(i,t){this.x=i,this.y=t;const e=Math.round(this.x),s=Math.round(this.y);this.img.css({transform:`translate(-${e}px, -${s}px)`}),this.outline&&this.outline.css({transform:`translate(-${e}px, -${s}px)`})}}const e=function(i){return i.type.includes("touch")?{pageX:i.originalEvent.changedTouches[0].pageX,pageY:i.originalEvent.changedTouches[0].pageY}:{pageX:i.pageX,pageY:i.pageY}};class s{constructor({parent:i,view:t,horizontal:e,vertical:s,actions:h}){this.parent=i,this.view=t,this.doubleClickThreshold=300,h.pan&&this.pan(),h.zoomOnDoubleClick&&this.doubleClick(),h.resize&&this.resizeView({horizontal:h.resizeHorizontal,vertical:h.resizeVertical}),this.preventBrowserDragDrop(),this.responsiveArena()}pan(){const t=i(document);this.view.on("mousedown.srcissors touchstart.srcissors",i=>{const s={startX:this.parent.preview.x,startY:this.parent.preview.y};i.preventDefault(),t.on("mousemove.srcissors-pan touchmove.srcissors-pan",t=>{const{pageX:h,pageY:n}=e(t),{pageX:o,pageY:a}=e(i);s.dx=h-o,s.dy=n-a,this.parent.onPan(s)}).on("mouseup.srcissors-pan touchend.srcissors-pan",()=>{t.off("mouseup.srcissors-pan touchend.srcissors-pan"),t.off("mousemove.srcissors-pan touchmove.srcissors-pan"),null!=s.dx&&this.parent.onPanEnd()})})}doubleClick(){let i;this.view.on("mousedown.srcissors touchstart.srcissors",t=>{const s=(new Date).getTime();i&&i>s-this.doubleClickThreshold&&this.parent.onDoubleClick(e(t)),i=s})}preventBrowserDragDrop(){this.view.on("dragstart.srcissors",()=>!1)}resizeView({horizontal:t,vertical:e}){const s=i("
");s.addClass("resize-handler");let h=[];t&&(h=h.concat(["right","left"])),e&&(h=h.concat(["top","bottom"])),h.forEach(i=>{const t=s.clone();t.addClass(`resize-handler-${i}`),t.on("mousedown.srcissors touchstart.srcissors",this.getResizeMouseDown(i)),this.view.append(t)})}getResizeMouseDown(t){const s=i(document);return i=>{let{pageX:h,pageY:n}=e(i);i.stopPropagation(),s.on("mousemove.srcissors-resize touchmove.srcissors-resize",i=>{let s,o;const{pageX:a,pageY:r}=e(i);switch(t){case"top":case"bottom":o=r-n,"top"===t&&(o=-o),n=r;break;case"left":case"right":s=a-h,"left"===t&&(s=-s),h=a}this.parent.onResize({position:t,dx:s,dy:o})}).on("mouseup.srcissors-resize touchend.srcissors-resize",()=>{s.off("mouseup.srcissors-resize touchmove.srcissors-resize"),s.off("mousemove.srcissors-resize touchend.srcissors-resize"),this.parent.onResizeEnd({position:t})})}}responsiveArena(){}}class h{constructor({arena:e,view:s,img:h,outline:n,url:o,fixedWidth:a,fixedHeight:r,minViewWidth:g,minViewHeight:d,minViewRatio:m,maxViewRatio:w,originalSize:l,crop:c,zoomStep:u,maxArea:p,actions:v,minResolution:x,surroundingImageOpacity:R,showSurroundingImage:z}){this.onPreviewReady=this.onPreviewReady.bind(this),this.arena=e,this.view=s,this.img=h,this.outline=n,this.fixedWidth=a,this.fixedHeight=r,this.minViewWidth=g,this.minViewHeight=d,this.minViewRatio=m,this.maxViewRatio=w,this.originalSize=l,this.actions=v,this.minResolution=x,this.surroundingImageOpacity=R,this.loadingCssClass="crop-view--is-loading",this.panningCssClass="crop-view--is-panning",this.outlineCssClass="crop-outline--active",this.isPanning=!1,this.initialCrop=c,this.loadEvent=i.Callbacks(),this.changeEvent=i.Callbacks(),this.initializeReadyState(),this.zoomInStep=u,this.zoomOutStep=1/this.zoomInStep,this.arenaWidth=this.arena.width(),this.arenaHeight=this.arena.height(),p&&(this.maxArea=this.arenaWidth*this.arenaHeight*p),this.outline&&this.setSurroundingImageVisibility(z),this.preview=new t({onReady:this.onPreviewReady,img:this.img,outline:this.outline,opacity:this.surroundingImageOpacity}),this.setImage(o)}initializeReadyState(){this.isReady=!1,null!=this.readyEvent&&this.readyEvent.empty(),this.readyEvent=i.Callbacks("memory once")}setImage(i){i!==this.preview.url&&(this.isInitialized&&this.preview.reset(),this.initializeReadyState(),this.view.addClass(this.loadingCssClass),this.preview.setImage({url:i}))}setSurroundingImageVisibility(i){this.surroundingImageOpacity=parseFloat(this.surroundingImageOpacity||.2),"always"===i?this.outline.css("opacity",1):"panning"===i?this.outline.css("opacity",null):(this.outline.css("opacity",0),this.surroundingImageOpacity=0)}reset(){this.isReady&&(this.resize({width:this.imageWidth,height:this.imageHeight}),this.zoomAllOut())}onPreviewReady(i){this.checkRatio(i);const{width:t,height:e}=this.originalSize||i;let h;this.preview.updateImageDimensions({width:t,height:e}),this.isInitialized||(this.events=new s({parent:this,view:this.view,actions:this.actions})),this.imageWidth=t,this.imageHeight=e,this.imageRatio=this.imageWidth/this.imageHeight;const n=this.imageWidth*this.imageHeight;if(this.minResolution&&this.minResolution>n&&delete this.minResolution,this.minResolution){const i=this.minResolution/(this.imageHeight*this.imageHeight);(!this.minViewRatio||this.minViewRatiot)&&(this.maxViewRatio=t)}this.calcMaxMinDimensions(),this.fixedWidth&&(h="width"),this.fixedHeight&&(h="height"),this.setViewDimensions({width:this.imageWidth,height:this.imageHeight,keepDimension:h}),this.isReady=!0,this.view.removeClass(this.loadingCssClass),this.isInitialized||null==this.initialCrop?(this.zoomAllOut(),this.center()):this.setCrop(this.initialCrop),this.isInitialized=!0,this.readyEvent.fire(),this.loadEvent.fire()}setCrop({x:i,y:t,width:e,height:s}){if(!this.isReady)return void this.on("ready",()=>this.setCrop({x:i,y:t,width:e,height:s}));this.resize({width:e,height:s});const h=this.viewWidth/e,n=this.imageWidth*h;this.zoom({width:n}),this.pan({x:i*h,y:t*h})}getCrop(){const i=this.preview.width/this.imageWidth,t={x:this.preview.x/i,y:this.preview.y/i,width:this.viewWidth/i,height:this.viewHeight/i};return this.roundCrop(t),this.validateCrop(t),t}roundCrop(i){for(const t in i){const e=i[t];i[t]=Math.round(e)}}validateCrop(i){const{x:t,y:e,width:s,height:h}=i;return t<0&&(i.x=0),e<0&&(i.y=0),t+s>this.imageWidth&&(i.width=this.imageWidth-t),e+h>this.imageHeight&&(i.height=this.imageHeight-e),i}setRatio(i,t){let e,s;if(this.isReady)return i=this.enforceValidRatio(i),"height"===t?(e=this.viewHeight,s=e*i):(s=this.viewWidth,e=s/i),this.resizeFocusPoint=this.getFocusPoint(),this.resize({width:s,height:e});this.on("ready",()=>this.setRatio(i,t))}onPan(i){this.isPanning||(this.isPanning=!0,this.arena.addClass(this.panningCssClass),this.outline.addClass(this.outlineCssClass));const t=i.startX-i.dx,e=i.startY-i.dy;this.pan({x:t,y:e})}onPanEnd(){return this.isPanning=!1,this.arena.removeClass(this.panningCssClass),this.outline.removeClass(this.outlineCssClass)}onDoubleClick({pageX:i,pageY:t}){const{left:e,top:s}=this.view[0].getBoundingClientRect(),h=i-e,n=t-s;this.zoomIn({viewX:h,viewY:n})}onResize({position:i,dx:t,dy:e}){this.isResizing||(this.isResizing=!0,this.resizeFocusPoint=this.getFocusPoint()),["top","bottom"].includes(i)?(e*=2,this.resize({width:this.viewWidth,height:this.viewHeight+e,keepDimension:"height"})):["left","right"].includes(i)&&(t*=2,this.resize({width:this.viewWidth+t,height:this.viewHeight,keepDimension:"width"}))}onResizeEnd(){this.isResizing=!1,this.resizeFocusPoint=void 0}resize({width:i,height:t,keepDimension:e}){this.setViewDimensions({width:i,height:t,keepDimension:e}),this.resizeFocusPoint&&(this.resizeFocusPoint.viewX=this.viewWidth/2,this.resizeFocusPoint.viewY=this.viewHeight/2),this.zoom({width:this.preview.width,height:this.preview.height,focusPoint:this.resizeFocusPoint})}setViewDimensions({width:i,height:t,keepDimension:e}){if(this.maxArea&&({width:i,height:t}=this.enforceMaxArea({width:i,height:t,keepDimension:e})),({width:i,height:t}=this.enforceViewDimensions({width:i,height:t,keepDimension:e})),this.view.css({width:i,height:t}),this.viewWidth=i,this.viewHeight=t,this.viewRatio=i/t,this.minResolution){const i=Math.sqrt(this.minResolution*this.viewRatio),t=Math.sqrt(this.minResolution/this.viewRatio);this.maxImageWidth=this.viewWidth/i*this.imageWidth,this.maxImageHeight=this.viewHeight/t*this.imageHeight}this.fireChange()}zoomAllOut(){this.isWidthRestricting()?this.zoom({width:this.viewWidth}):this.zoom({height:this.viewHeight})}zoomIn(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomInStep:i.height=this.preview.height*this.zoomInStep,this.zoom(i)}zoomOut(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomOutStep:i.height=this.preview.height*this.zoomOutStep,this.zoom(i)}zoom({width:i,height:t,viewX:e,viewY:s,focusPoint:h}){null==h&&(h=this.getFocusPoint({viewX:e,viewY:s})),({width:i,height:t}=this.enforceZoom({width:i,height:t})),null!=i?(this.preview.setWidth(i),this.fireChange()):null!=t&&(this.preview.setHeight(t),this.fireChange()),this.focus(h)}getFocusPoint(i){null==i&&(i={});let{viewX:t,viewY:e}=i;null==t&&(t=this.viewWidth/2),null==e&&(e=this.viewHeight/2);const s=this.preview.x+t,h=this.preview.y+e;return{percentX:s/this.preview.width,percentY:h/this.preview.height,viewX:t,viewY:e}}focus({percentX:i,percentY:t,viewX:e,viewY:s}){let h=this.preview.width*i,n=this.preview.height*t;h-=e,n-=s,this.pan({x:h,y:n})}center(){const i=(this.preview.width-this.viewWidth)/2,t=(this.preview.height-this.viewHeight)/2;this.pan({x:i,y:t})}pan(i){i=this.enforceXy(i),this.preview.pan(i.x,i.y),this.fireChange()}enforceXy({x:i,y:t}){return i>this.preview.width-this.viewWidth&&(i=this.preview.width-this.viewWidth),i<0&&(i=0),t>this.preview.height-this.viewHeight&&(t=this.preview.height-this.viewHeight),t<0&&(t=0),{x:i,y:t}}enforceZoom({width:i,height:t}){return null!=i&&this.maxImageWidth&&i>this.maxImageWidth?{width:this.maxImageWidth}:null!=i&&ithis.maxImageHeight?{height:this.maxImageHeight}:null!=t&&tthis.maxWidth||tthis.maxHeight||sthis.maxViewRatio)}isValidRatio(i){return!(ithis.maxViewRatio)}enforceValidRatio(i){return ithis.maxViewRatio?this.maxViewRatio:i}enforceViewDimensions({width:i,height:t,keepDimension:e}){let s,h,n;return ithis.maxWidth&&(h=this.maxWidth),tthis.maxHeight&&(s=this.maxHeight),e?(h&&(i=h),s&&(t=s),n=i/t,this.isValidRatio(n)||(n=this.enforceValidRatio(n),({width:i,height:t}=this.getRatioBox({ratio:n,width:i,height:t,keepDimension:e})),(i>this.arenaWidth||t>this.arenaHeight)&&({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n)))):(h||s)&&(n=this.enforceValidRatio(i/t),({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n))),{width:i,height:t}}enforceMaxArea({width:i,height:t,keepDimension:e}){let s=i/t;return"width"===e?s=i/(t=this.maxArea/i):"height"===e?s=(i=this.maxArea/t)/t:t=(i=Math.sqrt(this.maxArea*s))/s,this.isValidRatio(s)||(s=this.enforceValidRatio(s),t=(i=Math.sqrt(this.maxArea*s))/s),{width:i,height:t}}checkRatio(i){if(this.originalSize){const t=this.originalSize.width/this.originalSize.height,e=i.width/i.height,s=(e-t)/t*100;if(Math.abs(s)>1)throw new Error(`srcissors: Displayed image has a different image ratio than the one configured in 'originalRatio': ${t} vs ${e}`)}}isWidthRestricting(){return this.viewRatio>=this.imageRatio}getRatioBox({ratio:i,width:t,height:e,keepDimension:s}){return"width"===s||null==e?e=t/i:"height"===s||null==t?t=e*i:e=t/i,{width:t,height:e}}centerAlign(i,t,e){let s,h,n,o;return i/t>e?(h=t*e,n=(i-h)/2):(s=i/e,o=(t-s)/2),{x:n||0,y:o||0,width:h||i,height:s||t}}min(i){let t=i[0];for(const e of i)e{this.changeDispatch=void 0,this.changeEvent.fire(this.getCrop())},0))}debug(){const i=i=>Math.round(10*i)/10,t={arena:`${i(this.arenaWidth)}x${i(this.arenaHeight)}`,view:`${i(this.viewWidth)}x${i(this.viewHeight)}`,image:`${i(this.imageWidth)}x${i(this.imageHeight)}`,preview:`${i(this.preview.width)}x${i(this.preview.height)}`,previewXy:`${i(this.preview.x)}x${i(this.preview.y)}`};return console.log(t),t}}const n={new({arena:t,url:e,fixedWidth:s,fixedHeight:n,minWidth:o,minHeight:a,minRatio:r,maxRatio:g,maxArea:d,originalSize:m,zoomStep:w,crop:l,actions:c,minResolution:u,surroundingImageOpacity:p,showSurroundingImage:v}){const x=(t=i(t)).find(".crop-view"),R=x.find(".crop-preview"),z=i("");R.append(z);let f=x.find(".crop-outline");f.length||(f=void 0);const y={pan:!0,zoomOnDoubleClick:!0,resize:!0,resizeHorizontal:!s,resizeVertical:!n};return i.extend(y,c),null==w&&(w=1.25),null==o&&(o=50),null==a&&(a=50),new h({url:e,crop:l,arena:t,view:x,img:z,outline:f,showSurroundingImage:v,surroundingImageOpacity:p,fixedWidth:s,fixedHeight:n,minViewWidth:o,minViewHeight:a,minViewRatio:r,maxViewRatio:g,maxArea:d,originalSize:m,zoomStep:w,actions:y,minResolution:u})}};export{n as default}; +import{default as i}from"jquery";class t{constructor({onReady:i,img:t,opacity:e,outline:s}){this.onReady=i,this.img=t,this.opacity=e,this.outline=s,this.x=this.y=0,this.width=this.height=0,this.img.on("load",()=>{const i=this.img.width(),t=this.img.height();this.ratio=i/t,this.onReady({width:i,height:t}),this.img.show()})}setImage({url:i}){this.url=i,this.img.attr("src",this.url),this.outline&&this.setBackgroundImage({url:this.url})}setBackgroundImage({url:t}){if(this.opacity>0){const e=i("").css({opacity:this.opacity}).attr("src",t);this.outline.append(e)}}reset(){this.url=void 0,this.x=this.y=0,this.width=this.height=0,this.img.attr("src",""),this.img.css({width:"",height:"",transform:""}),this.outline&&this.outline.css({transform:""}).html("")}setWidth(i){this.img.css({width:`${i}px`,height:"auto"});const t=i/this.ratio;this.updateImageDimensions({width:i,height:t})}setHeight(i){this.img.css({width:"auto",height:`${i}px`});const t=i*this.ratio;this.updateImageDimensions({width:t,height:i})}updateImageDimensions({width:i,height:t}){this.width=i,this.height=t,this.outline&&this.outline.css({width:`${this.width}px`,height:`${this.height}px`})}pan(i,t){this.x=i,this.y=t;const e=Math.round(this.x),s=Math.round(this.y);this.img.css({transform:`translate(-${e}px, -${s}px)`}),this.outline&&this.outline.css({transform:`translate(-${e}px, -${s}px)`})}}const e=function(i){return i.type.includes("touch")?{pageX:i.originalEvent.changedTouches[0].pageX,pageY:i.originalEvent.changedTouches[0].pageY}:{pageX:i.pageX,pageY:i.pageY}};class s{constructor({parent:i,view:t,horizontal:e,vertical:s,actions:h}){this.parent=i,this.view=t,this.doubleClickThreshold=300,h.pan&&this.pan(),h.zoomOnDoubleClick&&this.doubleClick(),h.resize&&this.resizeView({horizontal:h.resizeHorizontal,vertical:h.resizeVertical}),this.preventBrowserDragDrop(),this.responsiveArena()}pan(){const t=i(document);this.view.on("mousedown.srcissors touchstart.srcissors",i=>{const s={startX:this.parent.preview.x,startY:this.parent.preview.y};i.preventDefault(),t.on("mousemove.srcissors-pan touchmove.srcissors-pan",t=>{const{pageX:h,pageY:n}=e(t),{pageX:o,pageY:a}=e(i);s.dx=h-o,s.dy=n-a,this.parent.onPan(s)}).on("mouseup.srcissors-pan touchend.srcissors-pan",()=>{t.off("mouseup.srcissors-pan touchend.srcissors-pan"),t.off("mousemove.srcissors-pan touchmove.srcissors-pan"),null!=s.dx&&this.parent.onPanEnd()})})}doubleClick(){let i;this.view.on("mousedown.srcissors touchstart.srcissors",t=>{const s=(new Date).getTime();i&&i>s-this.doubleClickThreshold&&this.parent.onDoubleClick(e(t)),i=s})}preventBrowserDragDrop(){this.view.on("dragstart.srcissors",()=>!1)}resizeView({horizontal:t,vertical:e}){const s=i("
");s.addClass("resize-handler");let h=[];t&&(h=h.concat(["right","left"])),e&&(h=h.concat(["top","bottom"])),h.forEach(i=>{const t=s.clone();t.addClass(`resize-handler-${i}`),t.on("mousedown.srcissors touchstart.srcissors",this.getResizeMouseDown(i)),this.view.append(t)})}getResizeMouseDown(t){const s=i(document);return i=>{let{pageX:h,pageY:n}=e(i);i.stopPropagation(),s.on("mousemove.srcissors-resize touchmove.srcissors-resize",i=>{let s,o;const{pageX:a,pageY:r}=e(i);switch(t){case"top":case"bottom":o=r-n,"top"===t&&(o=-o),n=r;break;case"left":case"right":s=a-h,"left"===t&&(s=-s),h=a}this.parent.onResize({position:t,dx:s,dy:o})}).on("mouseup.srcissors-resize touchend.srcissors-resize",()=>{s.off("mouseup.srcissors-resize touchmove.srcissors-resize"),s.off("mousemove.srcissors-resize touchend.srcissors-resize"),this.parent.onResizeEnd({position:t})})}}responsiveArena(){}}class h{constructor({arena:e,view:s,img:h,outline:n,url:o,fixedWidth:a,fixedHeight:r,minViewWidth:g,minViewHeight:d,minViewRatio:m,maxViewRatio:w,originalSize:l,crop:c,zoomStep:u,maxArea:p,actions:v,minResolution:x,surroundingImageOpacity:R,showSurroundingImage:z}){this.onPreviewReady=this.onPreviewReady.bind(this),this.arena=e,this.view=s,this.img=h,this.outline=n,this.fixedWidth=a,this.fixedHeight=r,this.minViewWidth=g,this.minViewHeight=d,this.minViewRatio=m,this.maxViewRatio=w,this.originalSize=l,this.actions=v,this.minResolution=x,this.surroundingImageOpacity=R,this.loadingCssClass="crop-view--is-loading",this.panningCssClass="crop-view--is-panning",this.outlineCssClass="crop-outline--active",this.isPanning=!1,this.initialCrop=c,this.loadEvent=i.Callbacks(),this.changeEvent=i.Callbacks(),this.initializeReadyState(),this.zoomInStep=u,this.zoomOutStep=1/this.zoomInStep,this.arenaWidth=this.arena.width(),this.arenaHeight=this.arena.height(),p&&(this.maxArea=this.arenaWidth*this.arenaHeight*p),this.outline&&this.setSurroundingImageVisibility(z),this.preview=new t({onReady:this.onPreviewReady,img:this.img,outline:this.outline,opacity:this.surroundingImageOpacity}),this.setImage(o)}initializeReadyState(){this.isReady=!1,null!=this.readyEvent&&this.readyEvent.empty(),this.readyEvent=i.Callbacks("memory once")}setImage(i){i!==this.preview.url&&(this.isInitialized&&this.preview.reset(),this.initializeReadyState(),this.view.addClass(this.loadingCssClass),this.preview.setImage({url:i}))}setSurroundingImageVisibility(i){this.surroundingImageOpacity=parseFloat(this.surroundingImageOpacity||.2),"always"===i?this.outline.css("opacity",1):"panning"===i?this.outline.css("opacity",null):(this.outline.css("opacity",0),this.surroundingImageOpacity=0)}reset(){this.isReady&&(this.resize({width:this.imageWidth,height:this.imageHeight}),this.zoomAllOut())}onPreviewReady(i){this.checkRatio(i);const{width:t,height:e}=this.originalSize||i;let h;this.preview.updateImageDimensions({width:t,height:e}),this.isInitialized||(this.events=new s({parent:this,view:this.view,actions:this.actions})),this.imageWidth=t,this.imageHeight=e,this.imageRatio=this.imageWidth/this.imageHeight;const n=this.imageWidth*this.imageHeight;if(this.minResolution&&this.minResolution>n&&delete this.minResolution,this.minResolution){const i=this.minResolution/(this.imageHeight*this.imageHeight);(!this.minViewRatio||this.minViewRatiot)&&(this.maxViewRatio=t)}this.calcMaxMinDimensions(),this.fixedWidth&&(h="width"),this.fixedHeight&&(h="height"),this.setViewDimensions({width:this.imageWidth,height:this.imageHeight,keepDimension:h}),this.isReady=!0,this.view.removeClass(this.loadingCssClass),this.isInitialized||null==this.initialCrop?(this.zoomAllOut(),this.center()):this.setCrop(this.initialCrop),this.isInitialized=!0,this.readyEvent.fire(),this.loadEvent.fire()}setCrop({x:i,y:t,width:e,height:s}){if(!this.isReady)return void this.on("ready",()=>this.setCrop({x:i,y:t,width:e,height:s}));this.resize({width:e,height:s});const h=this.viewWidth/e,n=this.imageWidth*h;this.zoom({width:n}),this.pan({x:i*h,y:t*h})}getCrop(){const i=this.preview.width/this.imageWidth,t={x:this.preview.x/i,y:this.preview.y/i,width:this.viewWidth/i,height:this.viewHeight/i};return this.roundCrop(t),this.validateCrop(t),t}roundCrop(i){for(const t in i){const e=i[t];i[t]=Math.round(e)}}validateCrop(i){const{x:t,y:e,width:s,height:h}=i;return t<0&&(i.x=0),e<0&&(i.y=0),t+s>this.imageWidth&&(i.width=this.imageWidth-t),e+h>this.imageHeight&&(i.height=this.imageHeight-e),i}setRatio(i,t){let e,s;if(this.isReady)return i=this.enforceValidRatio(i),"height"===t?(e=this.viewHeight,s=e*i):(s=this.viewWidth,e=s/i),this.resizeFocusPoint=this.getFocusPoint(),this.resize({width:s,height:e});this.on("ready",()=>this.setRatio(i,t))}onPan(i){this.isPanning||(this.isPanning=!0,this.arena.addClass(this.panningCssClass),this.outline.addClass(this.outlineCssClass));const t=i.startX-i.dx,e=i.startY-i.dy;this.pan({x:t,y:e})}onPanEnd(){return this.isPanning=!1,this.arena.removeClass(this.panningCssClass),this.outline.removeClass(this.outlineCssClass)}onDoubleClick({pageX:i,pageY:t}){const{left:e,top:s}=this.view[0].getBoundingClientRect(),h=i-e,n=t-s;this.zoomIn({viewX:h,viewY:n})}onResize({position:i,dx:t,dy:e}){this.isResizing||(this.isResizing=!0,this.resizeFocusPoint=this.getFocusPoint()),["top","bottom"].includes(i)?(e*=2,this.resize({width:this.viewWidth,height:this.viewHeight+e,keepDimension:"height"})):["left","right"].includes(i)&&(t*=2,this.resize({width:this.viewWidth+t,height:this.viewHeight,keepDimension:"width"}))}onResizeEnd(){this.isResizing=!1,this.resizeFocusPoint=void 0}resize({width:i,height:t,keepDimension:e}){this.setViewDimensions({width:i,height:t,keepDimension:e}),this.resizeFocusPoint&&(this.resizeFocusPoint.viewX=this.viewWidth/2,this.resizeFocusPoint.viewY=this.viewHeight/2),this.zoom({width:this.preview.width,height:this.preview.height,focusPoint:this.resizeFocusPoint})}setViewDimensions({width:i,height:t,keepDimension:e}){if(this.maxArea&&({width:i,height:t}=this.enforceMaxArea({width:i,height:t,keepDimension:e})),({width:i,height:t}=this.enforceViewDimensions({width:i,height:t,keepDimension:e})),this.view.css({width:i,height:t}),this.viewWidth=i,this.viewHeight=t,this.viewRatio=i/t,this.minResolution){const i=Math.sqrt(this.minResolution*this.viewRatio),t=Math.sqrt(this.minResolution/this.viewRatio),e=this.viewWidth/i*this.imageWidth,s=this.viewHeight/t*this.imageHeight;e>=this.viewWidth&&s>=this.viewHeight?(this.maxImageWidth=e,this.maxImageHeight=s):(this.maxImageWidth=Math.max(this.viewWidth,this.viewHeight*this.imageRatio),this.maxImageHeight=this.maxImageWidth/this.imageRatio)}this.fireChange()}zoomAllOut(){this.isWidthRestricting()?this.zoom({width:this.viewWidth}):this.zoom({height:this.viewHeight})}zoomIn(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomInStep:i.height=this.preview.height*this.zoomInStep,this.zoom(i)}zoomOut(i){null==i&&(i={}),this.isWidthRestricting()?i.width=this.preview.width*this.zoomOutStep:i.height=this.preview.height*this.zoomOutStep,this.zoom(i)}zoom({width:i,height:t,viewX:e,viewY:s,focusPoint:h}){null==h&&(h=this.getFocusPoint({viewX:e,viewY:s})),({width:i,height:t}=this.enforceZoom({width:i,height:t})),null!=i?(this.preview.setWidth(i),this.fireChange()):null!=t&&(this.preview.setHeight(t),this.fireChange()),this.focus(h)}getFocusPoint(i){null==i&&(i={});let{viewX:t,viewY:e}=i;null==t&&(t=this.viewWidth/2),null==e&&(e=this.viewHeight/2);const s=this.preview.x+t,h=this.preview.y+e;return{percentX:s/this.preview.width,percentY:h/this.preview.height,viewX:t,viewY:e}}focus({percentX:i,percentY:t,viewX:e,viewY:s}){let h=this.preview.width*i,n=this.preview.height*t;h-=e,n-=s,this.pan({x:h,y:n})}center(){const i=(this.preview.width-this.viewWidth)/2,t=(this.preview.height-this.viewHeight)/2;this.pan({x:i,y:t})}pan(i){i=this.enforceXy(i),this.preview.pan(i.x,i.y),this.fireChange()}enforceXy({x:i,y:t}){return i>this.preview.width-this.viewWidth&&(i=this.preview.width-this.viewWidth),i<0&&(i=0),t>this.preview.height-this.viewHeight&&(t=this.preview.height-this.viewHeight),t<0&&(t=0),{x:i,y:t}}enforceZoom({width:i,height:t}){return null!=i&&this.maxImageWidth&&i>this.maxImageWidth?{width:this.maxImageWidth}:null!=i&&ithis.maxImageHeight?{height:this.maxImageHeight}:null!=t&&tthis.maxWidth||tthis.maxHeight||sthis.maxViewRatio)}isValidRatio(i){return!(ithis.maxViewRatio)}enforceValidRatio(i){return ithis.maxViewRatio?this.maxViewRatio:i}enforceViewDimensions({width:i,height:t,keepDimension:e}){let s,h,n;return ithis.maxWidth&&(h=this.maxWidth),tthis.maxHeight&&(s=this.maxHeight),e?(h&&(i=h),s&&(t=s),n=i/t,this.isValidRatio(n)||(n=this.enforceValidRatio(n),({width:i,height:t}=this.getRatioBox({ratio:n,width:i,height:t,keepDimension:e})),(i>this.arenaWidth||t>this.arenaHeight)&&({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n)))):(h||s)&&(n=this.enforceValidRatio(i/t),({width:i,height:t}=this.centerAlign(this.maxWidth,this.maxHeight,n))),{width:i,height:t}}enforceMaxArea({width:i,height:t,keepDimension:e}){let s=i/t;return"width"===e?s=i/(t=this.maxArea/i):"height"===e?s=(i=this.maxArea/t)/t:t=(i=Math.sqrt(this.maxArea*s))/s,this.isValidRatio(s)||(s=this.enforceValidRatio(s),t=(i=Math.sqrt(this.maxArea*s))/s),{width:i,height:t}}checkRatio(i){if(this.originalSize){const t=this.originalSize.width/this.originalSize.height,e=i.width/i.height,s=(e-t)/t*100;if(Math.abs(s)>1)throw new Error(`srcissors: Displayed image has a different image ratio than the one configured in 'originalRatio': ${t} vs ${e}`)}}isWidthRestricting(){return this.viewRatio>=this.imageRatio}getRatioBox({ratio:i,width:t,height:e,keepDimension:s}){return"width"===s||null==e?e=t/i:"height"===s||null==t?t=e*i:e=t/i,{width:t,height:e}}centerAlign(i,t,e){let s,h,n,o;return i/t>e?(h=t*e,n=(i-h)/2):(s=i/e,o=(t-s)/2),{x:n||0,y:o||0,width:h||i,height:s||t}}min(i){let t=i[0];for(const e of i)e{this.changeDispatch=void 0,this.changeEvent.fire(this.getCrop())},0))}debug(){const i=i=>Math.round(10*i)/10,t={arena:`${i(this.arenaWidth)}x${i(this.arenaHeight)}`,view:`${i(this.viewWidth)}x${i(this.viewHeight)}`,image:`${i(this.imageWidth)}x${i(this.imageHeight)}`,preview:`${i(this.preview.width)}x${i(this.preview.height)}`,previewXy:`${i(this.preview.x)}x${i(this.preview.y)}`};return console.log(t),t}}const n={new({arena:t,url:e,fixedWidth:s,fixedHeight:n,minWidth:o,minHeight:a,minRatio:r,maxRatio:g,maxArea:d,originalSize:m,zoomStep:w,crop:l,actions:c,minResolution:u,surroundingImageOpacity:p,showSurroundingImage:v}){const x=(t=i(t)).find(".crop-view"),R=x.find(".crop-preview"),z=i("");R.append(z);let f=x.find(".crop-outline");f.length||(f=void 0);const y={pan:!0,zoomOnDoubleClick:!0,resize:!0,resizeHorizontal:!s,resizeVertical:!n};return i.extend(y,c),null==w&&(w=1.25),null==o&&(o=50),null==a&&(a=50),new h({url:e,crop:l,arena:t,view:x,img:z,outline:f,showSurroundingImage:v,surroundingImageOpacity:p,fixedWidth:s,fixedHeight:n,minViewWidth:o,minViewHeight:a,minViewRatio:r,maxViewRatio:g,maxArea:d,originalSize:m,zoomStep:w,actions:y,minResolution:u})}};export{n as default}; //# sourceMappingURL=srcissors.js.map \ No newline at end of file diff --git a/srcissors.js.map b/srcissors.js.map index 6df6d40..ff99106 100644 --- a/srcissors.js.map +++ b/srcissors.js.map @@ -1 +1 @@ -{"version":3,"file":"./srcissors.js","mappings":"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","sources":["webpack://srcissors/./src/preview.js","webpack://srcissors/./src/events.js","webpack://srcissors/./src/crop.js","webpack://srcissors/./src/srcissors.js"],"sourcesContent":["import $ from 'jquery'\n\nexport default class Preview {\n constructor({onReady, img, opacity, outline}) {\n this.onReady = onReady\n this.img = img\n this.opacity = opacity\n this.outline = outline\n this.x = this.y = 0\n this.width = this.height = 0\n\n this.img.on('load', () => {\n const width = this.img.width()\n const height = this.img.height()\n this.ratio = width / height\n\n this.onReady({width, height})\n this.img.show()\n })\n }\n\n setImage({url}) {\n this.url = url\n this.img.attr('src', this.url)\n if (this.outline) this.setBackgroundImage({url: this.url})\n }\n\n setBackgroundImage({url}) {\n if (this.opacity > 0) {\n const bgImg = $('').css({opacity: this.opacity}).attr('src', url)\n this.outline.append(bgImg)\n }\n }\n\n reset() {\n this.url = undefined\n this.x = this.y = 0\n this.width = this.height = 0\n this.img.attr('src', '')\n this.img.css({width: '', height: '', transform: ''})\n if (this.outline) this.outline.css({transform: ''}).html('')\n }\n\n setWidth(width) {\n this.img.css({width: `${width}px`, height: 'auto'})\n const height = width / this.ratio\n this.updateImageDimensions({width, height})\n }\n\n setHeight(height) {\n this.img.css({width: 'auto', height: `${height}px`})\n const width = height * this.ratio\n this.updateImageDimensions({width, height})\n }\n\n updateImageDimensions({width, height}) {\n this.width = width\n this.height = height\n if (this.outline) this.outline.css({width: `${this.width}px`, height: `${this.height}px`})\n }\n\n pan(x1, y1) {\n // Without rounding some numbers would not be set to css.\n // e.g: '-5.14957320384e-14'\n this.x = x1\n this.y = y1\n const x = Math.round(this.x)\n const y = Math.round(this.y)\n this.img.css({transform: `translate(-${x}px, -${y}px)`})\n if (this.outline) this.outline.css({transform: `translate(-${x}px, -${y}px)`})\n }\n}\n","import $ from 'jquery'\n\nconst getPageCoordinates = function (event) {\n if (event.type.includes('touch')) {\n return {\n pageX: event.originalEvent.changedTouches[0].pageX,\n pageY: event.originalEvent.changedTouches[0].pageY\n }\n }\n return {pageX: event.pageX, pageY: event.pageY}\n}\n\nexport default class Events {\n constructor({parent, view, horizontal, vertical, actions}) {\n this.parent = parent\n this.view = view\n this.doubleClickThreshold = 300\n\n // setup events\n if (actions.pan) {\n this.pan()\n }\n if (actions.zoomOnDoubleClick) {\n this.doubleClick()\n }\n if (actions.resize) {\n this.resizeView({\n horizontal: actions.resizeHorizontal,\n vertical: actions.resizeVertical\n })\n }\n\n this.preventBrowserDragDrop()\n this.responsiveArena()\n }\n\n pan() {\n const $doc = $(document)\n this.view.on('mousedown.srcissors touchstart.srcissors', (e1) => {\n const panData = {\n startX: this.parent.preview.x,\n startY: this.parent.preview.y\n }\n\n e1.preventDefault()\n $doc\n .on('mousemove.srcissors-pan touchmove.srcissors-pan', (e2) => {\n const {pageX, pageY} = getPageCoordinates(e2)\n const {pageX: prevPageX, pageY: prevPageY} = getPageCoordinates(e1)\n panData.dx = pageX - prevPageX\n panData.dy = pageY - prevPageY\n this.parent.onPan(panData)\n })\n .on('mouseup.srcissors-pan touchend.srcissors-pan', () => {\n $doc.off('mouseup.srcissors-pan touchend.srcissors-pan')\n $doc.off('mousemove.srcissors-pan touchmove.srcissors-pan')\n\n // only trigger panEnd if pan has been called\n if (panData.dx != null) this.parent.onPanEnd()\n })\n })\n }\n\n doubleClick() {\n let lastClick\n\n this.view.on('mousedown.srcissors touchstart.srcissors', (event) => {\n const now = new Date().getTime()\n if (lastClick && lastClick > now - this.doubleClickThreshold) {\n this.parent.onDoubleClick(getPageCoordinates(event))\n }\n lastClick = now\n })\n }\n\n preventBrowserDragDrop() {\n this.view.on('dragstart.srcissors', () => false)\n }\n\n // Resize View\n // -----------\n\n resizeView({horizontal, vertical}) {\n const $template = $('
')\n $template.addClass('resize-handler')\n\n let positions = []\n if (horizontal) positions = positions.concat(['right', 'left'])\n if (vertical) positions = positions.concat(['top', 'bottom'])\n\n positions.forEach((position) => {\n const $handler = $template.clone()\n $handler.addClass(`resize-handler-${position}`)\n $handler.on('mousedown.srcissors touchstart.srcissors', this.getResizeMouseDown(position))\n\n this.view.append($handler)\n })\n }\n\n getResizeMouseDown(position) {\n const $doc = $(document)\n\n return (event) => {\n let {pageX: lastX, pageY: lastY} = getPageCoordinates(event)\n event.stopPropagation()\n\n $doc\n .on('mousemove.srcissors-resize touchmove.srcissors-resize', (e2) => {\n let dx, dy\n const {pageX, pageY} = getPageCoordinates(e2)\n switch (position) {\n case 'top':\n case 'bottom':\n dy = pageY - lastY\n if (position === 'top') {\n dy = -dy\n }\n lastY = pageY\n break\n case 'left':\n case 'right':\n dx = pageX - lastX\n if (position === 'left') {\n dx = -dx\n }\n lastX = pageX\n break\n }\n\n this.parent.onResize({position, dx, dy})\n })\n .on('mouseup.srcissors-resize touchend.srcissors-resize', () => {\n $doc.off('mouseup.srcissors-resize touchmove.srcissors-resize')\n $doc.off('mousemove.srcissors-resize touchend.srcissors-resize')\n\n // only trigger panEnd if pan has been called\n this.parent.onResizeEnd({position})\n })\n }\n }\n\n responsiveArena() {}\n}\n","import $ from 'jquery'\nimport Preview from './preview.js'\nimport Events from './events.js'\n\nexport default class Crop {\n constructor({\n arena,\n view,\n img,\n outline,\n url,\n fixedWidth,\n fixedHeight,\n minViewWidth,\n minViewHeight,\n minViewRatio,\n maxViewRatio,\n originalSize,\n crop,\n zoomStep,\n maxArea,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n // CSS classes\n this.onPreviewReady = this.onPreviewReady.bind(this)\n this.arena = arena\n this.view = view\n this.img = img\n this.outline = outline\n this.fixedWidth = fixedWidth\n this.fixedHeight = fixedHeight\n this.minViewWidth = minViewWidth\n this.minViewHeight = minViewHeight\n this.minViewRatio = minViewRatio\n this.maxViewRatio = maxViewRatio\n this.originalSize = originalSize\n this.actions = actions\n this.minResolution = minResolution\n this.surroundingImageOpacity = surroundingImageOpacity\n this.loadingCssClass = 'crop-view--is-loading'\n this.panningCssClass = 'crop-view--is-panning'\n this.outlineCssClass = 'crop-outline--active'\n\n // State\n this.isPanning = false\n this.initialCrop = crop\n\n // Events\n this.loadEvent = $.Callbacks()\n this.changeEvent = $.Callbacks()\n\n // Sets up the ready event and state\n this.initializeReadyState()\n\n // Confguration\n this.zoomInStep = zoomStep\n this.zoomOutStep = 1 / this.zoomInStep\n\n this.arenaWidth = this.arena.width()\n this.arenaHeight = this.arena.height()\n\n // todo: consider to calculate maxArea with regards to the\n // maximum space an image can within the area. That should\n // be more reliable.\n if (maxArea) this.maxArea = this.arenaWidth * this.arenaHeight * maxArea\n\n if (this.outline) this.setSurroundingImageVisibility(showSurroundingImage)\n\n this.preview = new Preview({\n onReady: this.onPreviewReady,\n img: this.img,\n outline: this.outline,\n opacity: this.surroundingImageOpacity\n })\n\n this.setImage(url)\n }\n\n initializeReadyState() {\n this.isReady = false\n if (this.readyEvent != null) {\n this.readyEvent.empty()\n }\n this.readyEvent = $.Callbacks('memory once')\n }\n\n setImage(url) {\n if (url === this.preview.url) return\n\n if (this.isInitialized) this.preview.reset()\n this.initializeReadyState()\n this.view.addClass(this.loadingCssClass)\n this.preview.setImage({url})\n }\n\n setSurroundingImageVisibility(visibility) {\n // visibility: always|panning|never\n // override opacity in crop-outline--active css class\n this.surroundingImageOpacity = parseFloat(this.surroundingImageOpacity || 0.2)\n\n if (visibility === 'always') {\n this.outline.css('opacity', 1.0)\n } else if (visibility === 'panning') {\n this.outline.css('opacity', null)\n } else {\n // 'never' default\n this.outline.css('opacity', 0)\n this.surroundingImageOpacity = 0\n }\n }\n\n reset() {\n if (!this.isReady) return\n\n this.resize({width: this.imageWidth, height: this.imageHeight})\n this.zoomAllOut()\n }\n\n onPreviewReady(previewImageSize) {\n this.checkRatio(previewImageSize)\n const {width, height} = this.originalSize || previewImageSize\n\n // console.log(this.originalSize, previewImageSize, {width, height})\n this.preview.updateImageDimensions({width, height})\n\n let keepDimension\n if (!this.isInitialized) {\n this.events = new Events({\n parent: this,\n view: this.view,\n actions: this.actions\n })\n }\n\n this.imageWidth = width\n this.imageHeight = height\n this.imageRatio = this.imageWidth / this.imageHeight\n const imageResolution = this.imageWidth * this.imageHeight\n\n if (this.minResolution && this.minResolution > imageResolution) {\n // If the minimal required resolution is bigger than the actual image\n // resolution, we ignore the configuration\n delete this.minResolution\n }\n\n if (this.minResolution) {\n // For any given image resolution with a minimal required resolution\n // we can calculate both, a minimal resolution and a maximal resolution\n const minRatioForResolution = this.minResolution / (this.imageHeight * this.imageHeight)\n if (!this.minViewRatio || this.minViewRatio < minRatioForResolution) {\n this.minViewRatio = minRatioForResolution\n }\n const maxRatioForResolution = (this.imageWidth * this.imageWidth) / this.minResolution\n if (!this.maxViewRatio || this.maxViewRatio > maxRatioForResolution) {\n this.maxViewRatio = maxRatioForResolution\n }\n }\n\n this.calcMaxMinDimensions()\n\n if (this.fixedWidth) {\n keepDimension = 'width'\n }\n if (this.fixedHeight) {\n keepDimension = 'height'\n }\n this.setViewDimensions({\n width: this.imageWidth,\n height: this.imageHeight,\n keepDimension\n })\n\n // ready state\n this.isReady = true\n this.view.removeClass(this.loadingCssClass)\n\n if (!this.isInitialized && this.initialCrop != null) {\n this.setCrop(this.initialCrop)\n } else {\n this.zoomAllOut()\n this.center()\n }\n\n this.isInitialized = true\n this.readyEvent.fire()\n this.loadEvent.fire()\n }\n\n setCrop({x, y, width, height}) {\n if (!this.isReady) {\n this.on('ready', () => this.setCrop({x, y, width, height}))\n return\n }\n\n this.resize({width, height})\n\n const factor = this.viewWidth / width\n const previewWidth = this.imageWidth * factor\n\n this.zoom({width: previewWidth})\n this.pan({x: x * factor, y: y * factor})\n }\n\n getCrop() {\n const factor = this.preview.width / this.imageWidth\n const crop = {\n x: this.preview.x / factor,\n y: this.preview.y / factor,\n width: this.viewWidth / factor,\n height: this.viewHeight / factor\n }\n\n this.roundCrop(crop)\n this.validateCrop(crop)\n return crop\n }\n\n roundCrop(crop) {\n for (const name in crop) {\n const value = crop[name]\n crop[name] = Math.round(value)\n }\n }\n\n validateCrop(crop) {\n const {x, y, width, height} = crop\n if (x < 0) crop.x = 0\n if (y < 0) crop.y = 0\n\n if (x + width > this.imageWidth) {\n crop.width = this.imageWidth - x\n }\n\n if (y + height > this.imageHeight) {\n crop.height = this.imageHeight - y\n }\n\n return crop\n }\n\n setRatio(ratio, keepDimension) {\n let height, width\n if (!this.isReady) {\n this.on('ready', () => this.setRatio(ratio, keepDimension))\n return\n }\n\n ratio = this.enforceValidRatio(ratio)\n\n if (keepDimension === 'height') {\n height = this.viewHeight\n width = height * ratio\n } else {\n width = this.viewWidth\n height = width / ratio\n }\n\n this.resizeFocusPoint = this.getFocusPoint()\n return this.resize({width, height})\n }\n\n // Event handling\n // --------------\n\n onPan(data) {\n if (!this.isPanning) {\n this.isPanning = true\n this.arena.addClass(this.panningCssClass)\n this.outline.addClass(this.outlineCssClass)\n }\n\n const newX = data.startX - data.dx\n const newY = data.startY - data.dy\n this.pan({x: newX, y: newY})\n }\n\n onPanEnd() {\n this.isPanning = false\n this.arena.removeClass(this.panningCssClass)\n return this.outline.removeClass(this.outlineCssClass)\n }\n\n onDoubleClick({pageX, pageY}) {\n const {left, top} = this.view[0].getBoundingClientRect()\n const viewX = pageX - left\n const viewY = pageY - top\n this.zoomIn({viewX, viewY})\n }\n\n onResize({position, dx, dy}) {\n if (!this.isResizing) {\n this.isResizing = true\n this.resizeFocusPoint = this.getFocusPoint()\n }\n\n if (['top', 'bottom'].includes(position)) {\n dy = 2 * dy // Because it's centered we need to change width by factor two\n this.resize({width: this.viewWidth, height: this.viewHeight + dy, keepDimension: 'height'})\n } else if (['left', 'right'].includes(position)) {\n dx = 2 * dx\n this.resize({width: this.viewWidth + dx, height: this.viewHeight, keepDimension: 'width'})\n }\n }\n\n onResizeEnd() {\n this.isResizing = false\n this.resizeFocusPoint = undefined\n }\n\n resize({width, height, keepDimension}) {\n this.setViewDimensions({width, height, keepDimension})\n\n // Update view center of focus point\n if (this.resizeFocusPoint) {\n this.resizeFocusPoint.viewX = this.viewWidth / 2\n this.resizeFocusPoint.viewY = this.viewHeight / 2\n }\n\n // Ensure dimensions and focus\n this.zoom({\n width: this.preview.width,\n height: this.preview.height,\n focusPoint: this.resizeFocusPoint\n })\n }\n\n setViewDimensions({width, height, keepDimension}) {\n if (this.maxArea) {\n ;({width, height} = this.enforceMaxArea({width, height, keepDimension}))\n }\n\n ;({width, height} = this.enforceViewDimensions({width, height, keepDimension}))\n\n this.view.css({width, height})\n this.viewWidth = width\n this.viewHeight = height\n this.viewRatio = width / height\n\n if (this.minResolution) {\n const minZoomPixelWidth = Math.sqrt(this.minResolution * this.viewRatio)\n const minZoomPixelHeight = Math.sqrt(this.minResolution / this.viewRatio)\n this.maxImageWidth = (this.viewWidth / minZoomPixelWidth) * this.imageWidth\n this.maxImageHeight = (this.viewHeight / minZoomPixelHeight) * this.imageHeight\n }\n\n this.fireChange()\n }\n\n // Update view\n // -----------\n\n zoomAllOut() {\n if (this.isWidthRestricting()) {\n this.zoom({width: this.viewWidth})\n } else {\n this.zoom({height: this.viewHeight})\n }\n }\n\n zoomIn(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomInStep\n } else {\n params.height = this.preview.height * this.zoomInStep\n }\n\n this.zoom(params)\n }\n\n zoomOut(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomOutStep\n } else {\n params.height = this.preview.height * this.zoomOutStep\n }\n\n this.zoom(params)\n }\n\n zoom({width, height, viewX, viewY, focusPoint}) {\n if (focusPoint == null) {\n focusPoint = this.getFocusPoint({viewX, viewY})\n }\n\n ;({width, height} = this.enforceZoom({width, height}))\n if (width != null) {\n this.preview.setWidth(width)\n this.fireChange()\n } else if (height != null) {\n this.preview.setHeight(height)\n this.fireChange()\n }\n\n this.focus(focusPoint)\n }\n\n // returns {Object} e.g. percentX: 0.2, percentY: 0.5\n getFocusPoint(param) {\n if (param == null) {\n param = {}\n }\n let {viewX, viewY} = param\n if (viewX == null) {\n viewX = this.viewWidth / 2\n }\n if (viewY == null) {\n viewY = this.viewHeight / 2\n }\n const x = this.preview.x + viewX\n const y = this.preview.y + viewY\n const percentX = x / this.preview.width\n const percentY = y / this.preview.height\n return {percentX, percentY, viewX, viewY}\n }\n\n focus({percentX, percentY, viewX, viewY}) {\n let x = this.preview.width * percentX\n let y = this.preview.height * percentY\n x = x - viewX\n y = y - viewY\n\n this.pan({x, y})\n }\n\n center() {\n const newX = (this.preview.width - this.viewWidth) / 2\n const newY = (this.preview.height - this.viewHeight) / 2\n this.pan({x: newX, y: newY})\n }\n\n // @param { Object }\n // - x {Number} pixel to pan to the left\n // - y {Number} pixels to pan to the top\n pan(data) {\n data = this.enforceXy(data)\n this.preview.pan(data.x, data.y)\n this.fireChange()\n }\n\n // Validations\n // -----------\n\n enforceXy({x, y}) {\n if (x > this.preview.width - this.viewWidth) {\n x = this.preview.width - this.viewWidth\n }\n\n if (x < 0) x = 0\n\n if (y > this.preview.height - this.viewHeight) {\n y = this.preview.height - this.viewHeight\n }\n\n if (y < 0) y = 0\n\n return {x, y}\n }\n\n enforceZoom({width, height}) {\n if (width != null && this.maxImageWidth && width > this.maxImageWidth) {\n // prevent zooming in past the required resolution defined by minResolution\n return {width: this.maxImageWidth}\n }\n\n if (width != null && width < this.viewWidth) {\n // prevent zooming out past covering the view completely\n return {width: this.viewWidth}\n }\n\n if (height != null && this.maxImageHeight && height > this.maxImageHeight) {\n // prevent zooming in past the required resolution defined by minResolution\n return {height: this.maxImageHeight}\n }\n\n if (height != null && height < this.viewHeight) {\n // prevent zooming out past covering the view completely\n return {height: this.viewHeight}\n }\n\n return {width, height}\n }\n\n calcMaxMinDimensions() {\n this.maxWidth = this.min([this.arenaWidth, this.imageWidth])\n this.maxHeight = this.min([this.arenaHeight, this.imageHeight])\n this.minWidth = this.minViewWidth || 0\n this.minHeight = this.minViewHeight || 0\n\n if (this.fixedWidth) this.maxWidth = this.minWidth = this.fixedWidth\n if (this.fixedHeight) this.maxHeight = this.minHeight = this.fixedHeight\n }\n\n areDimensionsValid({width, height, keepDimension}) {\n const ratio = width / height\n\n const invalid =\n width < this.minWidth ||\n width > this.maxWidth ||\n height < this.minHeight ||\n height > this.maxHeight ||\n ratio < this.minViewRatio ||\n ratio > this.maxViewRatio\n\n return !invalid\n }\n\n isValidRatio(ratio) {\n return !(ratio < this.minViewRatio || ratio > this.maxViewRatio)\n }\n\n enforceValidRatio(ratio) {\n if (ratio < this.minViewRatio) return this.minViewRatio\n if (ratio > this.maxViewRatio) return this.maxViewRatio\n return ratio\n }\n\n enforceViewDimensions({width, height, keepDimension}) {\n let newHeight, newWidth, ratio\n if (width < this.minWidth) newWidth = this.minWidth\n if (width > this.maxWidth) newWidth = this.maxWidth\n if (height < this.minHeight) newHeight = this.minHeight\n if (height > this.maxHeight) newHeight = this.maxHeight\n\n if (keepDimension) {\n if (newWidth) width = newWidth\n if (newHeight) height = newHeight\n\n // check max/min ratios\n ratio = width / height\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n ;({width, height} = this.getRatioBox({ratio, width, height, keepDimension}))\n if (width > this.arenaWidth || height > this.arenaHeight) {\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n }\n } else if (newWidth || newHeight) {\n ratio = this.enforceValidRatio(width / height)\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n\n return {width, height}\n }\n\n enforceMaxArea({width, height, keepDimension}) {\n let ratio = width / height\n\n if (keepDimension === 'width') {\n height = this.maxArea / width\n ratio = width / height\n } else if (keepDimension === 'height') {\n width = this.maxArea / height\n ratio = width / height\n } else {\n // keep ratio\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n return {width, height}\n }\n\n checkRatio(previewImageSize) {\n if (this.originalSize) {\n const expectedRatio = this.originalSize.width / this.originalSize.height\n const actualRatio = previewImageSize.width / previewImageSize.height\n const percentageChange = ((actualRatio - expectedRatio) / expectedRatio) * 100\n if (Math.abs(percentageChange) > 1) {\n throw new Error(\n `srcissors: Displayed image has a different image ratio than the ` +\n `one configured in 'originalRatio': ${expectedRatio} vs ${actualRatio}`\n )\n }\n }\n }\n\n // Calculations\n // ------------\n //\n // Ratio: width / height\n // Tall < 1 (Square) < Wide\n // (A ratio less than one is a tall image format and\n // a ratio greater than one is a wide image format)\n\n // Check if the width or height is restricting\n isWidthRestricting() {\n return this.viewRatio >= this.imageRatio\n }\n\n getRatioBox({ratio, width, height, keepDimension}) {\n if (keepDimension === 'width' || height == null) {\n height = width / ratio\n } else if (keepDimension === 'height' || width == null) {\n width = height * ratio\n } else {\n height = width / ratio\n }\n\n return {width, height}\n }\n\n centerAlign(areaWidth, areaHeight, ratio) {\n let height, width, x, y\n if (areaWidth / areaHeight > ratio) {\n width = areaHeight * ratio\n x = (areaWidth - width) / 2\n } else {\n height = areaWidth / ratio\n y = (areaHeight - height) / 2\n }\n\n // return\n return {\n x: x || 0,\n y: y || 0,\n width: width || areaWidth,\n height: height || areaHeight\n }\n }\n\n min(array) {\n let min = array[0]\n for (const number of array) {\n if (number < min) min = number\n }\n\n return min\n }\n\n // Events\n // ------\n\n on(name, callback) {\n return this[`${name}Event`].add(callback)\n }\n\n off(name, callback) {\n return this[`${name}Event`].remove(callback)\n }\n\n // Debounce change events so they are not fired more\n // than once per tick.\n fireChange() {\n if (this.changeDispatch != null) return\n\n this.changeDispatch = setTimeout(() => {\n this.changeDispatch = undefined\n this.changeEvent.fire(this.getCrop())\n }, 0)\n }\n\n // Development helpers\n // -------------------\n\n debug() {\n const r = (num) => Math.round(num * 10) / 10\n\n const obj = {\n arena: `${r(this.arenaWidth)}x${r(this.arenaHeight)}`,\n view: `${r(this.viewWidth)}x${r(this.viewHeight)}`,\n image: `${r(this.imageWidth)}x${r(this.imageHeight)}`,\n preview: `${r(this.preview.width)}x${r(this.preview.height)}`,\n previewXy: `${r(this.preview.x)}x${r(this.preview.y)}`\n }\n\n console.log(obj) // eslint-disable-line no-console\n return obj\n }\n}\n","import $ from 'jquery'\nimport Crop from './crop.js'\n\nexport default {\n new({\n arena,\n url,\n fixedWidth,\n fixedHeight,\n minWidth,\n minHeight,\n minRatio,\n maxRatio,\n maxArea,\n originalSize,\n zoomStep,\n crop,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n arena = $(arena)\n const view = arena.find('.crop-view')\n const preview = view.find('.crop-preview')\n const img = $('')\n preview.append(img)\n let outline = view.find('.crop-outline')\n if (!outline.length) {\n outline = undefined\n }\n\n const allowedActions = {\n pan: true,\n zoomOnDoubleClick: true,\n resize: true,\n resizeHorizontal: !fixedWidth,\n resizeVertical: !fixedHeight\n }\n\n $.extend(allowedActions, actions)\n\n if (zoomStep == null) {\n zoomStep = 1.25\n }\n\n if (minWidth == null) {\n minWidth = 50\n }\n if (minHeight == null) {\n minHeight = 50\n }\n\n return new Crop({\n url, // {String}\n crop, // {Object} Set an inital crop. This is the same as calling setCrop()\n arena, // {jQuery Element}\n view, // {jQuery Element}\n img, // {jQuery Element}\n outline, // {jQuery Element or undefined}\n showSurroundingImage, // {String} always|panning|never\n surroundingImageOpacity, // {Number} e.g. in the 0.0 - 1.0 range\n fixedWidth, // {Number} e.g. 300\n fixedHeight, // {Number} e.g. 500\n minViewWidth: minWidth, // {Number} e.g. 100\n minViewHeight: minHeight, // {Number} e.g. 100\n minViewRatio: minRatio, // {Number} e.g. 1.5/2\n maxViewRatio: maxRatio, // {Number} e.g. 2/1\n maxArea, // {Number} 0.8 -> max 80% of arena area are covered by the preview\n originalSize, // {Object} Original image size, can be used to display a downscaled\n // version of the image in the cropping interface, but use the original\n // size for crop attributes; e.g. {width: 4000, height: 3000}\n zoomStep, // {Number} e.g. 1.25 -> 125%\n actions: allowedActions,\n minResolution\n })\n }\n}\n"],"names":["Preview","constructor","onReady","img","opacity","outline","this","x","y","width","height","on","ratio","show","setImage","url","attr","setBackgroundImage","bgImg","css","append","reset","undefined","transform","html","setWidth","updateImageDimensions","setHeight","pan","x1","y1","Math","round","getPageCoordinates","event","type","includes","pageX","originalEvent","changedTouches","pageY","Events","parent","view","horizontal","vertical","actions","doubleClickThreshold","zoomOnDoubleClick","doubleClick","resize","resizeView","resizeHorizontal","resizeVertical","preventBrowserDragDrop","responsiveArena","$doc","document","e1","panData","startX","preview","startY","preventDefault","e2","prevPageX","prevPageY","dx","dy","onPan","off","onPanEnd","lastClick","now","Date","getTime","onDoubleClick","$template","addClass","positions","concat","forEach","position","$handler","clone","getResizeMouseDown","lastX","lastY","stopPropagation","onResize","onResizeEnd","Crop","arena","fixedWidth","fixedHeight","minViewWidth","minViewHeight","minViewRatio","maxViewRatio","originalSize","crop","zoomStep","maxArea","minResolution","surroundingImageOpacity","showSurroundingImage","onPreviewReady","bind","loadingCssClass","panningCssClass","outlineCssClass","isPanning","initialCrop","loadEvent","changeEvent","initializeReadyState","zoomInStep","zoomOutStep","arenaWidth","arenaHeight","setSurroundingImageVisibility","isReady","readyEvent","empty","isInitialized","visibility","parseFloat","imageWidth","imageHeight","zoomAllOut","previewImageSize","checkRatio","keepDimension","events","imageRatio","imageResolution","minRatioForResolution","maxRatioForResolution","calcMaxMinDimensions","setViewDimensions","removeClass","center","setCrop","fire","factor","viewWidth","previewWidth","zoom","getCrop","viewHeight","roundCrop","validateCrop","name","value","setRatio","enforceValidRatio","resizeFocusPoint","getFocusPoint","data","newX","newY","left","top","getBoundingClientRect","viewX","viewY","zoomIn","isResizing","focusPoint","enforceMaxArea","enforceViewDimensions","viewRatio","minZoomPixelWidth","sqrt","minZoomPixelHeight","maxImageWidth","maxImageHeight","fireChange","isWidthRestricting","params","zoomOut","enforceZoom","focus","param","percentX","percentY","enforceXy","maxWidth","min","maxHeight","minWidth","minHeight","areDimensionsValid","isValidRatio","newHeight","newWidth","getRatioBox","centerAlign","expectedRatio","actualRatio","percentageChange","abs","Error","areaWidth","areaHeight","array","number","callback","add","remove","changeDispatch","setTimeout","debug","r","num","obj","image","previewXy","console","log","minRatio","maxRatio","find","length","allowedActions"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"./srcissors.js","mappings":"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","sources":["webpack://srcissors/./src/preview.js","webpack://srcissors/./src/events.js","webpack://srcissors/./src/crop.js","webpack://srcissors/./src/srcissors.js"],"sourcesContent":["import $ from 'jquery'\n\nexport default class Preview {\n constructor({onReady, img, opacity, outline}) {\n this.onReady = onReady\n this.img = img\n this.opacity = opacity\n this.outline = outline\n this.x = this.y = 0\n this.width = this.height = 0\n\n this.img.on('load', () => {\n const width = this.img.width()\n const height = this.img.height()\n this.ratio = width / height\n\n this.onReady({width, height})\n this.img.show()\n })\n }\n\n setImage({url}) {\n this.url = url\n this.img.attr('src', this.url)\n if (this.outline) this.setBackgroundImage({url: this.url})\n }\n\n setBackgroundImage({url}) {\n if (this.opacity > 0) {\n const bgImg = $('').css({opacity: this.opacity}).attr('src', url)\n this.outline.append(bgImg)\n }\n }\n\n reset() {\n this.url = undefined\n this.x = this.y = 0\n this.width = this.height = 0\n this.img.attr('src', '')\n this.img.css({width: '', height: '', transform: ''})\n if (this.outline) this.outline.css({transform: ''}).html('')\n }\n\n setWidth(width) {\n this.img.css({width: `${width}px`, height: 'auto'})\n const height = width / this.ratio\n this.updateImageDimensions({width, height})\n }\n\n setHeight(height) {\n this.img.css({width: 'auto', height: `${height}px`})\n const width = height * this.ratio\n this.updateImageDimensions({width, height})\n }\n\n updateImageDimensions({width, height}) {\n this.width = width\n this.height = height\n if (this.outline) this.outline.css({width: `${this.width}px`, height: `${this.height}px`})\n }\n\n pan(x1, y1) {\n // Without rounding some numbers would not be set to css.\n // e.g: '-5.14957320384e-14'\n this.x = x1\n this.y = y1\n const x = Math.round(this.x)\n const y = Math.round(this.y)\n this.img.css({transform: `translate(-${x}px, -${y}px)`})\n if (this.outline) this.outline.css({transform: `translate(-${x}px, -${y}px)`})\n }\n}\n","import $ from 'jquery'\n\nconst getPageCoordinates = function (event) {\n if (event.type.includes('touch')) {\n return {\n pageX: event.originalEvent.changedTouches[0].pageX,\n pageY: event.originalEvent.changedTouches[0].pageY\n }\n }\n return {pageX: event.pageX, pageY: event.pageY}\n}\n\nexport default class Events {\n constructor({parent, view, horizontal, vertical, actions}) {\n this.parent = parent\n this.view = view\n this.doubleClickThreshold = 300\n\n // setup events\n if (actions.pan) {\n this.pan()\n }\n if (actions.zoomOnDoubleClick) {\n this.doubleClick()\n }\n if (actions.resize) {\n this.resizeView({\n horizontal: actions.resizeHorizontal,\n vertical: actions.resizeVertical\n })\n }\n\n this.preventBrowserDragDrop()\n this.responsiveArena()\n }\n\n pan() {\n const $doc = $(document)\n this.view.on('mousedown.srcissors touchstart.srcissors', (e1) => {\n const panData = {\n startX: this.parent.preview.x,\n startY: this.parent.preview.y\n }\n\n e1.preventDefault()\n $doc\n .on('mousemove.srcissors-pan touchmove.srcissors-pan', (e2) => {\n const {pageX, pageY} = getPageCoordinates(e2)\n const {pageX: prevPageX, pageY: prevPageY} = getPageCoordinates(e1)\n panData.dx = pageX - prevPageX\n panData.dy = pageY - prevPageY\n this.parent.onPan(panData)\n })\n .on('mouseup.srcissors-pan touchend.srcissors-pan', () => {\n $doc.off('mouseup.srcissors-pan touchend.srcissors-pan')\n $doc.off('mousemove.srcissors-pan touchmove.srcissors-pan')\n\n // only trigger panEnd if pan has been called\n if (panData.dx != null) this.parent.onPanEnd()\n })\n })\n }\n\n doubleClick() {\n let lastClick\n\n this.view.on('mousedown.srcissors touchstart.srcissors', (event) => {\n const now = new Date().getTime()\n if (lastClick && lastClick > now - this.doubleClickThreshold) {\n this.parent.onDoubleClick(getPageCoordinates(event))\n }\n lastClick = now\n })\n }\n\n preventBrowserDragDrop() {\n this.view.on('dragstart.srcissors', () => false)\n }\n\n // Resize View\n // -----------\n\n resizeView({horizontal, vertical}) {\n const $template = $('
')\n $template.addClass('resize-handler')\n\n let positions = []\n if (horizontal) positions = positions.concat(['right', 'left'])\n if (vertical) positions = positions.concat(['top', 'bottom'])\n\n positions.forEach((position) => {\n const $handler = $template.clone()\n $handler.addClass(`resize-handler-${position}`)\n $handler.on('mousedown.srcissors touchstart.srcissors', this.getResizeMouseDown(position))\n\n this.view.append($handler)\n })\n }\n\n getResizeMouseDown(position) {\n const $doc = $(document)\n\n return (event) => {\n let {pageX: lastX, pageY: lastY} = getPageCoordinates(event)\n event.stopPropagation()\n\n $doc\n .on('mousemove.srcissors-resize touchmove.srcissors-resize', (e2) => {\n let dx, dy\n const {pageX, pageY} = getPageCoordinates(e2)\n switch (position) {\n case 'top':\n case 'bottom':\n dy = pageY - lastY\n if (position === 'top') {\n dy = -dy\n }\n lastY = pageY\n break\n case 'left':\n case 'right':\n dx = pageX - lastX\n if (position === 'left') {\n dx = -dx\n }\n lastX = pageX\n break\n }\n\n this.parent.onResize({position, dx, dy})\n })\n .on('mouseup.srcissors-resize touchend.srcissors-resize', () => {\n $doc.off('mouseup.srcissors-resize touchmove.srcissors-resize')\n $doc.off('mousemove.srcissors-resize touchend.srcissors-resize')\n\n // only trigger panEnd if pan has been called\n this.parent.onResizeEnd({position})\n })\n }\n }\n\n responsiveArena() {}\n}\n","import $ from 'jquery'\nimport Preview from './preview.js'\nimport Events from './events.js'\n\nexport default class Crop {\n constructor({\n arena,\n view,\n img,\n outline,\n url,\n fixedWidth,\n fixedHeight,\n minViewWidth,\n minViewHeight,\n minViewRatio,\n maxViewRatio,\n originalSize,\n crop,\n zoomStep,\n maxArea,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n // CSS classes\n this.onPreviewReady = this.onPreviewReady.bind(this)\n this.arena = arena\n this.view = view\n this.img = img\n this.outline = outline\n this.fixedWidth = fixedWidth\n this.fixedHeight = fixedHeight\n this.minViewWidth = minViewWidth\n this.minViewHeight = minViewHeight\n this.minViewRatio = minViewRatio\n this.maxViewRatio = maxViewRatio\n this.originalSize = originalSize\n this.actions = actions\n this.minResolution = minResolution\n this.surroundingImageOpacity = surroundingImageOpacity\n this.loadingCssClass = 'crop-view--is-loading'\n this.panningCssClass = 'crop-view--is-panning'\n this.outlineCssClass = 'crop-outline--active'\n\n // State\n this.isPanning = false\n this.initialCrop = crop\n\n // Events\n this.loadEvent = $.Callbacks()\n this.changeEvent = $.Callbacks()\n\n // Sets up the ready event and state\n this.initializeReadyState()\n\n // Confguration\n this.zoomInStep = zoomStep\n this.zoomOutStep = 1 / this.zoomInStep\n\n this.arenaWidth = this.arena.width()\n this.arenaHeight = this.arena.height()\n\n // todo: consider to calculate maxArea with regards to the\n // maximum space an image can within the area. That should\n // be more reliable.\n if (maxArea) this.maxArea = this.arenaWidth * this.arenaHeight * maxArea\n\n if (this.outline) this.setSurroundingImageVisibility(showSurroundingImage)\n\n this.preview = new Preview({\n onReady: this.onPreviewReady,\n img: this.img,\n outline: this.outline,\n opacity: this.surroundingImageOpacity\n })\n\n this.setImage(url)\n }\n\n initializeReadyState() {\n this.isReady = false\n if (this.readyEvent != null) {\n this.readyEvent.empty()\n }\n this.readyEvent = $.Callbacks('memory once')\n }\n\n setImage(url) {\n if (url === this.preview.url) return\n\n if (this.isInitialized) this.preview.reset()\n this.initializeReadyState()\n this.view.addClass(this.loadingCssClass)\n this.preview.setImage({url})\n }\n\n setSurroundingImageVisibility(visibility) {\n // visibility: always|panning|never\n // override opacity in crop-outline--active css class\n this.surroundingImageOpacity = parseFloat(this.surroundingImageOpacity || 0.2)\n\n if (visibility === 'always') {\n this.outline.css('opacity', 1.0)\n } else if (visibility === 'panning') {\n this.outline.css('opacity', null)\n } else {\n // 'never' default\n this.outline.css('opacity', 0)\n this.surroundingImageOpacity = 0\n }\n }\n\n reset() {\n if (!this.isReady) return\n\n this.resize({width: this.imageWidth, height: this.imageHeight})\n this.zoomAllOut()\n }\n\n onPreviewReady(previewImageSize) {\n this.checkRatio(previewImageSize)\n const {width, height} = this.originalSize || previewImageSize\n\n // console.log(this.originalSize, previewImageSize, {width, height})\n this.preview.updateImageDimensions({width, height})\n\n let keepDimension\n if (!this.isInitialized) {\n this.events = new Events({\n parent: this,\n view: this.view,\n actions: this.actions\n })\n }\n\n this.imageWidth = width\n this.imageHeight = height\n this.imageRatio = this.imageWidth / this.imageHeight\n const imageResolution = this.imageWidth * this.imageHeight\n\n if (this.minResolution && this.minResolution > imageResolution) {\n // If the minimal required resolution is bigger than the actual image\n // resolution, we ignore the configuration\n delete this.minResolution\n }\n\n if (this.minResolution) {\n // For any given image resolution with a minimal required resolution\n // we can calculate both, a minimal resolution and a maximal resolution\n const minRatioForResolution = this.minResolution / (this.imageHeight * this.imageHeight)\n if (!this.minViewRatio || this.minViewRatio < minRatioForResolution) {\n this.minViewRatio = minRatioForResolution\n }\n const maxRatioForResolution = (this.imageWidth * this.imageWidth) / this.minResolution\n if (!this.maxViewRatio || this.maxViewRatio > maxRatioForResolution) {\n this.maxViewRatio = maxRatioForResolution\n }\n }\n\n this.calcMaxMinDimensions()\n\n if (this.fixedWidth) {\n keepDimension = 'width'\n }\n if (this.fixedHeight) {\n keepDimension = 'height'\n }\n this.setViewDimensions({\n width: this.imageWidth,\n height: this.imageHeight,\n keepDimension\n })\n\n // ready state\n this.isReady = true\n this.view.removeClass(this.loadingCssClass)\n\n if (!this.isInitialized && this.initialCrop != null) {\n this.setCrop(this.initialCrop)\n } else {\n this.zoomAllOut()\n this.center()\n }\n\n this.isInitialized = true\n this.readyEvent.fire()\n this.loadEvent.fire()\n }\n\n setCrop({x, y, width, height}) {\n if (!this.isReady) {\n this.on('ready', () => this.setCrop({x, y, width, height}))\n return\n }\n\n this.resize({width, height})\n\n const factor = this.viewWidth / width\n const previewWidth = this.imageWidth * factor\n\n this.zoom({width: previewWidth})\n this.pan({x: x * factor, y: y * factor})\n }\n\n getCrop() {\n const factor = this.preview.width / this.imageWidth\n const crop = {\n x: this.preview.x / factor,\n y: this.preview.y / factor,\n width: this.viewWidth / factor,\n height: this.viewHeight / factor\n }\n\n this.roundCrop(crop)\n this.validateCrop(crop)\n return crop\n }\n\n roundCrop(crop) {\n for (const name in crop) {\n const value = crop[name]\n crop[name] = Math.round(value)\n }\n }\n\n validateCrop(crop) {\n const {x, y, width, height} = crop\n if (x < 0) crop.x = 0\n if (y < 0) crop.y = 0\n\n if (x + width > this.imageWidth) {\n crop.width = this.imageWidth - x\n }\n\n if (y + height > this.imageHeight) {\n crop.height = this.imageHeight - y\n }\n\n return crop\n }\n\n setRatio(ratio, keepDimension) {\n let height, width\n if (!this.isReady) {\n this.on('ready', () => this.setRatio(ratio, keepDimension))\n return\n }\n\n ratio = this.enforceValidRatio(ratio)\n\n if (keepDimension === 'height') {\n height = this.viewHeight\n width = height * ratio\n } else {\n width = this.viewWidth\n height = width / ratio\n }\n\n this.resizeFocusPoint = this.getFocusPoint()\n return this.resize({width, height})\n }\n\n // Event handling\n // --------------\n\n onPan(data) {\n if (!this.isPanning) {\n this.isPanning = true\n this.arena.addClass(this.panningCssClass)\n this.outline.addClass(this.outlineCssClass)\n }\n\n const newX = data.startX - data.dx\n const newY = data.startY - data.dy\n this.pan({x: newX, y: newY})\n }\n\n onPanEnd() {\n this.isPanning = false\n this.arena.removeClass(this.panningCssClass)\n return this.outline.removeClass(this.outlineCssClass)\n }\n\n onDoubleClick({pageX, pageY}) {\n const {left, top} = this.view[0].getBoundingClientRect()\n const viewX = pageX - left\n const viewY = pageY - top\n this.zoomIn({viewX, viewY})\n }\n\n onResize({position, dx, dy}) {\n if (!this.isResizing) {\n this.isResizing = true\n this.resizeFocusPoint = this.getFocusPoint()\n }\n\n if (['top', 'bottom'].includes(position)) {\n dy = 2 * dy // Because it's centered we need to change width by factor two\n this.resize({width: this.viewWidth, height: this.viewHeight + dy, keepDimension: 'height'})\n } else if (['left', 'right'].includes(position)) {\n dx = 2 * dx\n this.resize({width: this.viewWidth + dx, height: this.viewHeight, keepDimension: 'width'})\n }\n }\n\n onResizeEnd() {\n this.isResizing = false\n this.resizeFocusPoint = undefined\n }\n\n resize({width, height, keepDimension}) {\n this.setViewDimensions({width, height, keepDimension})\n\n // Update view center of focus point\n if (this.resizeFocusPoint) {\n this.resizeFocusPoint.viewX = this.viewWidth / 2\n this.resizeFocusPoint.viewY = this.viewHeight / 2\n }\n\n // Ensure dimensions and focus\n this.zoom({\n width: this.preview.width,\n height: this.preview.height,\n focusPoint: this.resizeFocusPoint\n })\n }\n\n setViewDimensions({width, height, keepDimension}) {\n if (this.maxArea) {\n ;({width, height} = this.enforceMaxArea({width, height, keepDimension}))\n }\n\n ;({width, height} = this.enforceViewDimensions({width, height, keepDimension}))\n\n this.view.css({width, height})\n this.viewWidth = width\n this.viewHeight = height\n this.viewRatio = width / height\n\n if (this.minResolution) {\n const minZoomPixelWidth = Math.sqrt(this.minResolution * this.viewRatio)\n const minZoomPixelHeight = Math.sqrt(this.minResolution / this.viewRatio)\n const maxImageWidth = (this.viewWidth / minZoomPixelWidth) * this.imageWidth\n const maxImageHeight = (this.viewHeight / minZoomPixelHeight) * this.imageHeight\n\n // Depending on the image size and configured ratio, the required\n // resolution cannot always be reached.\n if (maxImageWidth >= this.viewWidth && maxImageHeight >= this.viewHeight) {\n this.maxImageWidth = maxImageWidth\n this.maxImageHeight = maxImageHeight\n } else {\n // minResolution is unreachable at this ratio. Lock the zoom at the\n // most zoomed-out state, where the crop covers the largest possible\n // image area.\n this.maxImageWidth = Math.max(this.viewWidth, this.viewHeight * this.imageRatio)\n this.maxImageHeight = this.maxImageWidth / this.imageRatio\n }\n }\n\n this.fireChange()\n }\n\n // Update view\n // -----------\n\n zoomAllOut() {\n if (this.isWidthRestricting()) {\n this.zoom({width: this.viewWidth})\n } else {\n this.zoom({height: this.viewHeight})\n }\n }\n\n zoomIn(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomInStep\n } else {\n params.height = this.preview.height * this.zoomInStep\n }\n\n this.zoom(params)\n }\n\n zoomOut(params) {\n if (params == null) {\n params = {}\n }\n if (this.isWidthRestricting()) {\n params.width = this.preview.width * this.zoomOutStep\n } else {\n params.height = this.preview.height * this.zoomOutStep\n }\n\n this.zoom(params)\n }\n\n zoom({width, height, viewX, viewY, focusPoint}) {\n if (focusPoint == null) {\n focusPoint = this.getFocusPoint({viewX, viewY})\n }\n\n ;({width, height} = this.enforceZoom({width, height}))\n if (width != null) {\n this.preview.setWidth(width)\n this.fireChange()\n } else if (height != null) {\n this.preview.setHeight(height)\n this.fireChange()\n }\n\n this.focus(focusPoint)\n }\n\n // returns {Object} e.g. percentX: 0.2, percentY: 0.5\n getFocusPoint(param) {\n if (param == null) {\n param = {}\n }\n let {viewX, viewY} = param\n if (viewX == null) {\n viewX = this.viewWidth / 2\n }\n if (viewY == null) {\n viewY = this.viewHeight / 2\n }\n const x = this.preview.x + viewX\n const y = this.preview.y + viewY\n const percentX = x / this.preview.width\n const percentY = y / this.preview.height\n return {percentX, percentY, viewX, viewY}\n }\n\n focus({percentX, percentY, viewX, viewY}) {\n let x = this.preview.width * percentX\n let y = this.preview.height * percentY\n x = x - viewX\n y = y - viewY\n\n this.pan({x, y})\n }\n\n center() {\n const newX = (this.preview.width - this.viewWidth) / 2\n const newY = (this.preview.height - this.viewHeight) / 2\n this.pan({x: newX, y: newY})\n }\n\n // @param { Object }\n // - x {Number} pixel to pan to the left\n // - y {Number} pixels to pan to the top\n pan(data) {\n data = this.enforceXy(data)\n this.preview.pan(data.x, data.y)\n this.fireChange()\n }\n\n // Validations\n // -----------\n\n enforceXy({x, y}) {\n if (x > this.preview.width - this.viewWidth) {\n x = this.preview.width - this.viewWidth\n }\n\n if (x < 0) x = 0\n\n if (y > this.preview.height - this.viewHeight) {\n y = this.preview.height - this.viewHeight\n }\n\n if (y < 0) y = 0\n\n return {x, y}\n }\n\n enforceZoom({width, height}) {\n if (width != null && this.maxImageWidth && width > this.maxImageWidth) {\n // prevent zooming in past the required resolution defined by minResolution\n return {width: this.maxImageWidth}\n }\n\n if (width != null && width < this.viewWidth) {\n // prevent zooming out past covering the view completely\n return {width: this.viewWidth}\n }\n\n if (height != null && this.maxImageHeight && height > this.maxImageHeight) {\n // prevent zooming in past the required resolution defined by minResolution\n return {height: this.maxImageHeight}\n }\n\n if (height != null && height < this.viewHeight) {\n // prevent zooming out past covering the view completely\n return {height: this.viewHeight}\n }\n\n return {width, height}\n }\n\n calcMaxMinDimensions() {\n this.maxWidth = this.min([this.arenaWidth, this.imageWidth])\n this.maxHeight = this.min([this.arenaHeight, this.imageHeight])\n this.minWidth = this.minViewWidth || 0\n this.minHeight = this.minViewHeight || 0\n\n if (this.fixedWidth) this.maxWidth = this.minWidth = this.fixedWidth\n if (this.fixedHeight) this.maxHeight = this.minHeight = this.fixedHeight\n }\n\n areDimensionsValid({width, height, keepDimension}) {\n const ratio = width / height\n\n const invalid =\n width < this.minWidth ||\n width > this.maxWidth ||\n height < this.minHeight ||\n height > this.maxHeight ||\n ratio < this.minViewRatio ||\n ratio > this.maxViewRatio\n\n return !invalid\n }\n\n isValidRatio(ratio) {\n return !(ratio < this.minViewRatio || ratio > this.maxViewRatio)\n }\n\n enforceValidRatio(ratio) {\n if (ratio < this.minViewRatio) return this.minViewRatio\n if (ratio > this.maxViewRatio) return this.maxViewRatio\n return ratio\n }\n\n enforceViewDimensions({width, height, keepDimension}) {\n let newHeight, newWidth, ratio\n if (width < this.minWidth) newWidth = this.minWidth\n if (width > this.maxWidth) newWidth = this.maxWidth\n if (height < this.minHeight) newHeight = this.minHeight\n if (height > this.maxHeight) newHeight = this.maxHeight\n\n if (keepDimension) {\n if (newWidth) width = newWidth\n if (newHeight) height = newHeight\n\n // check max/min ratios\n ratio = width / height\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n ;({width, height} = this.getRatioBox({ratio, width, height, keepDimension}))\n if (width > this.arenaWidth || height > this.arenaHeight) {\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n }\n } else if (newWidth || newHeight) {\n ratio = this.enforceValidRatio(width / height)\n ;({width, height} = this.centerAlign(this.maxWidth, this.maxHeight, ratio))\n }\n\n return {width, height}\n }\n\n enforceMaxArea({width, height, keepDimension}) {\n let ratio = width / height\n\n if (keepDimension === 'width') {\n height = this.maxArea / width\n ratio = width / height\n } else if (keepDimension === 'height') {\n width = this.maxArea / height\n ratio = width / height\n } else {\n // keep ratio\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n if (!this.isValidRatio(ratio)) {\n ratio = this.enforceValidRatio(ratio)\n width = Math.sqrt(this.maxArea * ratio)\n height = width / ratio\n }\n\n return {width, height}\n }\n\n checkRatio(previewImageSize) {\n if (this.originalSize) {\n const expectedRatio = this.originalSize.width / this.originalSize.height\n const actualRatio = previewImageSize.width / previewImageSize.height\n const percentageChange = ((actualRatio - expectedRatio) / expectedRatio) * 100\n if (Math.abs(percentageChange) > 1) {\n throw new Error(\n `srcissors: Displayed image has a different image ratio than the ` +\n `one configured in 'originalRatio': ${expectedRatio} vs ${actualRatio}`\n )\n }\n }\n }\n\n // Calculations\n // ------------\n //\n // Ratio: width / height\n // Tall < 1 (Square) < Wide\n // (A ratio less than one is a tall image format and\n // a ratio greater than one is a wide image format)\n\n // Check if the width or height is restricting\n isWidthRestricting() {\n return this.viewRatio >= this.imageRatio\n }\n\n getRatioBox({ratio, width, height, keepDimension}) {\n if (keepDimension === 'width' || height == null) {\n height = width / ratio\n } else if (keepDimension === 'height' || width == null) {\n width = height * ratio\n } else {\n height = width / ratio\n }\n\n return {width, height}\n }\n\n centerAlign(areaWidth, areaHeight, ratio) {\n let height, width, x, y\n if (areaWidth / areaHeight > ratio) {\n width = areaHeight * ratio\n x = (areaWidth - width) / 2\n } else {\n height = areaWidth / ratio\n y = (areaHeight - height) / 2\n }\n\n // return\n return {\n x: x || 0,\n y: y || 0,\n width: width || areaWidth,\n height: height || areaHeight\n }\n }\n\n min(array) {\n let min = array[0]\n for (const number of array) {\n if (number < min) min = number\n }\n\n return min\n }\n\n // Events\n // ------\n\n on(name, callback) {\n return this[`${name}Event`].add(callback)\n }\n\n off(name, callback) {\n return this[`${name}Event`].remove(callback)\n }\n\n // Debounce change events so they are not fired more\n // than once per tick.\n fireChange() {\n if (this.changeDispatch != null) return\n\n this.changeDispatch = setTimeout(() => {\n this.changeDispatch = undefined\n this.changeEvent.fire(this.getCrop())\n }, 0)\n }\n\n // Development helpers\n // -------------------\n\n debug() {\n const r = (num) => Math.round(num * 10) / 10\n\n const obj = {\n arena: `${r(this.arenaWidth)}x${r(this.arenaHeight)}`,\n view: `${r(this.viewWidth)}x${r(this.viewHeight)}`,\n image: `${r(this.imageWidth)}x${r(this.imageHeight)}`,\n preview: `${r(this.preview.width)}x${r(this.preview.height)}`,\n previewXy: `${r(this.preview.x)}x${r(this.preview.y)}`\n }\n\n console.log(obj) // eslint-disable-line no-console\n return obj\n }\n}\n","import $ from 'jquery'\nimport Crop from './crop.js'\n\nexport default {\n new({\n arena,\n url,\n fixedWidth,\n fixedHeight,\n minWidth,\n minHeight,\n minRatio,\n maxRatio,\n maxArea,\n originalSize,\n zoomStep,\n crop,\n actions,\n minResolution,\n surroundingImageOpacity,\n showSurroundingImage\n }) {\n arena = $(arena)\n const view = arena.find('.crop-view')\n const preview = view.find('.crop-preview')\n const img = $('')\n preview.append(img)\n let outline = view.find('.crop-outline')\n if (!outline.length) {\n outline = undefined\n }\n\n const allowedActions = {\n pan: true,\n zoomOnDoubleClick: true,\n resize: true,\n resizeHorizontal: !fixedWidth,\n resizeVertical: !fixedHeight\n }\n\n $.extend(allowedActions, actions)\n\n if (zoomStep == null) {\n zoomStep = 1.25\n }\n\n if (minWidth == null) {\n minWidth = 50\n }\n if (minHeight == null) {\n minHeight = 50\n }\n\n return new Crop({\n url, // {String}\n crop, // {Object} Set an inital crop. This is the same as calling setCrop()\n arena, // {jQuery Element}\n view, // {jQuery Element}\n img, // {jQuery Element}\n outline, // {jQuery Element or undefined}\n showSurroundingImage, // {String} always|panning|never\n surroundingImageOpacity, // {Number} e.g. in the 0.0 - 1.0 range\n fixedWidth, // {Number} e.g. 300\n fixedHeight, // {Number} e.g. 500\n minViewWidth: minWidth, // {Number} e.g. 100\n minViewHeight: minHeight, // {Number} e.g. 100\n minViewRatio: minRatio, // {Number} e.g. 1.5/2\n maxViewRatio: maxRatio, // {Number} e.g. 2/1\n maxArea, // {Number} 0.8 -> max 80% of arena area are covered by the preview\n originalSize, // {Object} Original image size, can be used to display a downscaled\n // version of the image in the cropping interface, but use the original\n // size for crop attributes; e.g. {width: 4000, height: 3000}\n zoomStep, // {Number} e.g. 1.25 -> 125%\n actions: allowedActions,\n minResolution\n })\n }\n}\n"],"names":["Preview","constructor","onReady","img","opacity","outline","this","x","y","width","height","on","ratio","show","setImage","url","attr","setBackgroundImage","bgImg","__WEBPACK_EXTERNAL_MODULE_jquery_default__","css","append","reset","undefined","transform","html","setWidth","updateImageDimensions","setHeight","pan","x1","y1","Math","round","getPageCoordinates","event","type","includes","pageX","originalEvent","changedTouches","pageY","Events","parent","view","horizontal","vertical","actions","doubleClickThreshold","zoomOnDoubleClick","doubleClick","resize","resizeView","resizeHorizontal","resizeVertical","preventBrowserDragDrop","responsiveArena","$doc","document","e1","panData","startX","preview","startY","preventDefault","e2","prevPageX","prevPageY","dx","dy","onPan","off","onPanEnd","lastClick","now","Date","getTime","onDoubleClick","$template","addClass","positions","concat","forEach","position","$handler","clone","getResizeMouseDown","lastX","lastY","stopPropagation","onResize","onResizeEnd","Crop","arena","fixedWidth","fixedHeight","minViewWidth","minViewHeight","minViewRatio","maxViewRatio","originalSize","crop","zoomStep","maxArea","minResolution","surroundingImageOpacity","showSurroundingImage","onPreviewReady","bind","loadingCssClass","panningCssClass","outlineCssClass","isPanning","initialCrop","loadEvent","Callbacks","changeEvent","initializeReadyState","zoomInStep","zoomOutStep","arenaWidth","arenaHeight","setSurroundingImageVisibility","isReady","readyEvent","empty","isInitialized","visibility","parseFloat","imageWidth","imageHeight","zoomAllOut","previewImageSize","checkRatio","keepDimension","events","imageRatio","imageResolution","minRatioForResolution","maxRatioForResolution","calcMaxMinDimensions","setViewDimensions","removeClass","center","setCrop","fire","factor","viewWidth","previewWidth","zoom","getCrop","viewHeight","roundCrop","validateCrop","name","value","setRatio","enforceValidRatio","resizeFocusPoint","getFocusPoint","data","newX","newY","left","top","getBoundingClientRect","viewX","viewY","zoomIn","isResizing","focusPoint","enforceMaxArea","enforceViewDimensions","viewRatio","minZoomPixelWidth","sqrt","minZoomPixelHeight","maxImageWidth","maxImageHeight","max","fireChange","isWidthRestricting","params","zoomOut","enforceZoom","focus","param","percentX","percentY","enforceXy","maxWidth","min","maxHeight","minWidth","minHeight","areDimensionsValid","isValidRatio","newHeight","newWidth","getRatioBox","centerAlign","expectedRatio","actualRatio","percentageChange","abs","Error","areaWidth","areaHeight","array","number","callback","add","remove","changeDispatch","setTimeout","debug","r","num","obj","image","previewXy","console","log","srcissors","minRatio","maxRatio","find","length","allowedActions","extend"],"sourceRoot":""} \ No newline at end of file diff --git a/test/specs/srcissors_spec.js b/test/specs/srcissors_spec.js index 6584bd5..d6ca486 100644 --- a/test/specs/srcissors_spec.js +++ b/test/specs/srcissors_spec.js @@ -362,4 +362,34 @@ describe('srcissors', function () { }) }) }) + + describe('with a minResolution that cannot be met at the crop ratio', function () { + beforeEach(function (done) { + this.arena = $(template) + this.arena.css({width: 400, height: 300}) + $(document.body).append(this.arena) + + this.crop = srcissors.new({ + arena: this.arena, + url: '/test/images/diagonal.jpg', + minResolution: 90000 + }) + this.crop.on('ready', done) + }) + + afterEach(function () { + this.arena.remove() + }) + + it('locks the crop at the largest possible area instead of rendering a broken crop', function () { + this.crop.setCrop({x: 100, y: 50, width: 150, height: 200}) + + expect(this.crop.getCrop()).to.deep.equal({ + x: 150, + y: 0, + width: 225, + height: 300 + }) + }) + }) })