react-simple-image-zoom
Version:
Simple image zoom/magnification component for react, using react portals
1 lines • 7.72 kB
JavaScript
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("react"),require("react-dom"));else if("function"==typeof define&&define.amd)define(["react","react-dom"],e);else{var s="object"==typeof exports?e(require("react"),require("react-dom")):e(t.React,t.ReactDOM);for(var i in s)("object"==typeof exports?exports:t)[i]=s[i]}}(window,function(t,e){return function(t){var e={};function s(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,s),o.l=!0,o.exports}return s.m=t,s.c=e,s.d=function(t,e,i){s.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:i})},s.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=5)}([function(e,s){e.exports=t},function(t,e,s){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const i=s(0);e.default=(t=>i.createElement("div",{className:"glass",style:{pointerEvents:"none",position:"absolute",top:`${t.y}px`,left:`${t.x}px`,background:"#eee",width:`${t.width}px`,height:`${t.height}px`,backgroundColor:"rgba(0,0,0,.2)",zIndex:2}}))},function(t,e,s){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const i=s(0);e.default=(t=>i.createElement("div",{className:"zoom-container",style:{width:`${t.zoomContainerWidth}px`,height:`${t.zoomContainerHeight}px`,backgroundImage:`url("${t.imgSrc}")`,backgroundTop:`${t.offsetX}`,backgroundLeft:`${t.offsetY}`,backgroundPosition:`-${t.zoomX}px -${t.zoomY}px`,backgroundSize:`${t.zoomImageWidth}px`,backgroundRepeat:"no-repeat"}}))},function(t,s){t.exports=e},function(t,e,s){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const i=s(0),o=s(3),a=s(2),h=s(1);class n extends i.Component{constructor(t){super(t),this.state={isActive:!1,portalEl:null,zoomX:0,zoomY:0,glassX:0,glassY:0,glassWidth:40,glassHeight:40,scaleX:1,scaleY:1,offsetX:0,offsetY:0,zoomScale:this.props.zoomScale||1,imageWidth:this.props.imageWidth,imageHeight:this.props.imageHeight,zoomContainerWidth:this.props.zoomContainerWidth},this.portalStyle=this.props.portalStyle?this.props.portalStyle:n.defaultPortalStyle,this.onResize=this.onWindowResize.bind(this),this.toggle=this.toggleActive.bind(this),this.deactivate=this.setInactive.bind(this),this.zoom=this.zoom.bind(this)}getOffset(t){if(t){const e=t.getBoundingClientRect();return{left:e.left,top:e.top}}return{left:0,top:0}}calcScaleX(t,e=this.state.zoomScale){return this.zoomImage.naturalWidth*e/t}calcScaleY(t,e=this.state.zoomScale){return this.zoomImage.naturalHeight*e/(t||this.zoomImage.height)}calcZoomImageWidth(t=this.state.zoomScale){return this.zoomImage.naturalWidth*t}calcZoomImageHeight(t=this.state.zoomScale){return this.zoomImage.naturalHeight*t}getPortalStyle(){return this.props.responsive?Object.assign(Object.assign({},this.portalStyle),{width:`${this.state.zoomContainerWidth}px`}):this.portalStyle}onWindowResize(){const t=this.image.offsetWidth,e=this.image.offsetHeight,s=this.calcScaleX(t),i=this.calcScaleY(e),o=this.getOffset(this.image);this.setState({offset:o,scaleX:s,scaleY:i,zoomContainerWidth:t,glassWidth:t/s,glassHeight:e/i,imageWidth:t,imageHeight:e})}componentWillUnmount(){this.props.responsive&&window.removeEventListener("resize",this.onResize)}componentDidMount(){this.props.responsive&&window.addEventListener("resize",this.onResize);const t=new Image;t.src=this.props.children.props.src,t.onload=(()=>{let e,s;this.zoomImage=t,this.props.responsive&&(e=this.image.offsetWidth),s=this.image.offsetHeight;const i=this.calcScaleX(e||this.state.imageWidth),o=this.calcScaleY(s||this.state.imageHeight),a={offset:this.getOffset(this.image),scaleX:i,scaleY:o,zoomImageWidth:this.calcZoomImageWidth(),zoomImageHeight:this.calcZoomImageHeight(),glassWidth:this.props.zoomContainerWidth/i,glassHeight:(s||this.state.imageHeight)/o};e&&(a.imageWidth=e),s&&(a.imageHeight=s),this.setState(a)}),this.props.largeImgSrc?this.imgSrc=this.props.largeImgSrc:this.imgSrc=this.props.children&&this.props.children.props.src;const e=document.getElementById(this.props.portalId);this.setState({portalEl:e})}componentWillReceiveProps(t){if(!this.zoomImage)return null;const e=this.image.offsetWidth/this.zoomImage.naturalWidth;if(t.zoomScale<e)return null;const s=this.calcScaleX(this.state.imageWidth,t.zoomScale),i=this.calcScaleY(this.state.imageHeight,t.zoomScale);let o,a;a=this.calcZoomImageWidth(t.zoomScale),(o=t.zoomContainerWidth/s)>this.image.offsetWidth&&(o=this.image.offsetWidth),a<o&&(a=o),t.responsive&&!this.props.responsive&&window.addEventListener("resize",this.onResize),0==t.responsive&&this.props.responsive&&window.removeEventListener("resize",this.onResize),this.setState({glassWidth:o,glassHeight:this.state.imageHeight/i,scaleX:s,scaleY:i,zoomImageWidth:a,zoomContainerWidth:t.zoomContainerWidth,zoomImageHeight:this.calcZoomImageHeight(t.zoomScale),zoomScale:t.zoomScale})}getGlassPos(t){var e=0,s=0;const i=this.getOffset(this.image);let o,a;return e=t.pageX-i.left,s=t.pageY-i.top,e-=window.pageXOffset,s-=window.pageYOffset,o=e-this.state.glassWidth/2,a=s-this.state.glassHeight/2,o>this.image.offsetWidth-this.state.glassWidth&&(o=this.image.offsetWidth-this.state.glassWidth),o<0&&(o=0),a>this.image.offsetHeight-this.state.glassHeight&&(a=this.image.offsetHeight-this.state.glassHeight),a<0&&(a=0),{glassX:o,glassY:a}}zoom(t){if(!this.imgSrc||!this.state.isActive)return null;const e=this.getStateFromEvent(t);this.setState(e)}getPosition(t,e,s){let i;return t<e&&(i=e),t>s&&(i=s),i||(i=t),i-e}getZoomStateFromEvent(t){let e,s,i=t.clientX-this.state.offset.left;i+=window.pageXOffset;const o=this.state.glassWidth/2,a=this.state.imageWidth-o,h=this.getPosition(i,o,a);let n=t.clientY-this.state.offset.top;n+=window.pageYOffset;const r=this.state.glassHeight/2,l=this.state.imageHeight-r,c=this.getPosition(n,r,l);return e=h*this.state.scaleX,(s=c*this.state.scaleY)<0&&(s=0),e<0&&(e=0),{x:e,y:s}}getStateFromEvent(t){const e=t.nativeEvent,s=this.getGlassPos(e),i=this.getZoomStateFromEvent(e);return Object.assign({zoomX:i.x,zoomY:i.y},s)}toggleActive(t){if(this.state.isActive)this.setState({isActive:!1});else{t.nativeEvent;const e=this.getStateFromEvent(t);this.setState(Object.assign({},e,{isActive:!0}))}}setInactive(){this.setState({isActive:!1})}render(){if(!this.state.portalEl)return console.log("no portalEl"),null;const t="image-zoom-container"+(this.state.isActive?" "+(this.props.activeClass||"active"):"");return i.createElement(i.Fragment,null,this.state.isActive&&this.state.zoomImageWidth&&o.createPortal(i.createElement("div",{ref:t=>this.zoomContainer=t,style:this.portalStyle,className:this.props.portalClassName},i.createElement(a.default,{imgSrc:this.imgSrc,offsetX:this.state.offsetX,offsetY:this.state.offsetY,zoomX:this.state.zoomX,zoomY:this.state.zoomY,zoomImageWidth:this.state.zoomImageWidth,zoomContainerWidth:this.state.zoomContainerWidth,zoomContainerHeight:this.props.zoomContainerHeight||this.state.imageHeight})),this.state.portalEl),i.createElement("div",{ref:t=>this.image=t,onClick:this.toggle,onMouseLeave:this.deactivate,onMouseMove:this.zoom,className:t},this.state.isActive&&this.state.offset&&i.createElement(h.default,{x:this.state.glassX+this.state.offset.left,y:this.state.glassY+this.state.offset.top,width:this.state.glassWidth,height:this.state.glassHeight}),this.props.children))}}n.defaultPortalStyle={position:"absolute",width:"540px",zIndex:1},e.default=n},function(t,e,s){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=s(4);e.ImageZoom=i.default}])});