[Glitch] Add limitation of image's max zoom rate (max to the original size of image)
Port 7f3497bd7f to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
			
			
This commit is contained in:
		
							parent
							
								
									10fd2099b7
								
							
						
					
					
						commit
						f563531019
					
				
					 1 changed files with 51 additions and 18 deletions
				
			
		|  | @ -113,7 +113,8 @@ class ZoomableImage extends React.PureComponent { | ||||||
|   state = { |   state = { | ||||||
|     scale: MIN_SCALE, |     scale: MIN_SCALE, | ||||||
|     zoomMatrix: { |     zoomMatrix: { | ||||||
|       type: null, // 'full-width' 'full-height'
 |       type: null, // 'width' 'height'
 | ||||||
|  |       fullScreen: null, // bool
 | ||||||
|       rate: null, // full screen scale rate
 |       rate: null, // full screen scale rate
 | ||||||
|       clientWidth: null, |       clientWidth: null, | ||||||
|       clientHeight: null, |       clientHeight: null, | ||||||
|  | @ -122,12 +123,15 @@ class ZoomableImage extends React.PureComponent { | ||||||
|       clientHeightFixed: null, |       clientHeightFixed: null, | ||||||
|       scrollTop: null, |       scrollTop: null, | ||||||
|       scrollLeft: null, |       scrollLeft: null, | ||||||
|  |       translateX: null, | ||||||
|  |       translateY: null, | ||||||
|     }, |     }, | ||||||
|     zoomState: 'expand', // 'expand' 'compress'
 |     zoomState: 'expand', // 'expand' 'compress'
 | ||||||
|     navigationHidden: false, |     navigationHidden: false, | ||||||
|     dragPosition: { top: 0, left: 0, x: 0, y: 0 }, |     dragPosition: { top: 0, left: 0, x: 0, y: 0 }, | ||||||
|     dragged: false, |     dragged: false, | ||||||
|     lockScroll: { x: 0, y: 0 }, |     lockScroll: { x: 0, y: 0 }, | ||||||
|  |     lockTranslate: { x: 0, y: 0 }, | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   removers = []; |   removers = []; | ||||||
|  | @ -168,18 +172,24 @@ class ZoomableImage extends React.PureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentDidUpdate () { |   componentDidUpdate () { | ||||||
|  |     this.setState({ zoomState: this.state.scale >= this.state.zoomMatrix.rate ? 'compress' : 'expand' }); | ||||||
|  | 
 | ||||||
|  |     if (this.state.scale === MIN_SCALE) { | ||||||
|  |       this.container.style.removeProperty('cursor'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   UNSAFE_componentWillReceiveProps () { | ||||||
|  |     // reset when slide to next image
 | ||||||
|     if (this.props.zoomButtonHidden) { |     if (this.props.zoomButtonHidden) { | ||||||
|       this.setState({ scale: MIN_SCALE }, () => { |       this.setState({ | ||||||
|  |         scale: MIN_SCALE, | ||||||
|  |         lockTranslate: { x: 0, y: 0 }, | ||||||
|  |       }, () => { | ||||||
|         this.container.scrollLeft = 0; |         this.container.scrollLeft = 0; | ||||||
|         this.container.scrollTop = 0; |         this.container.scrollTop = 0; | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     this.setState({ zoomState: this.state.scale >= this.state.zoomMatrix.rate ? 'compress' : 'expand' }); |  | ||||||
| 
 |  | ||||||
|     if (this.state.scale === 1) { |  | ||||||
|       this.container.style.removeProperty('cursor'); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   removeEventListeners () { |   removeEventListeners () { | ||||||
|  | @ -192,7 +202,7 @@ class ZoomableImage extends React.PureComponent { | ||||||
| 
 | 
 | ||||||
|     const event = normalizeWheel(e); |     const event = normalizeWheel(e); | ||||||
| 
 | 
 | ||||||
|     if (this.state.zoomMatrix.type === 'full-width') { |     if (this.state.zoomMatrix.type === 'width') { | ||||||
|       // full width, scroll vertical
 |       // full width, scroll vertical
 | ||||||
|       this.container.scrollTop = Math.max(this.container.scrollTop + event.pixelY, this.state.lockScroll.y); |       this.container.scrollTop = Math.max(this.container.scrollTop + event.pixelY, this.state.lockScroll.y); | ||||||
|     } else { |     } else { | ||||||
|  | @ -268,7 +278,7 @@ class ZoomableImage extends React.PureComponent { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   zoom(nextScale, midpoint) { |   zoom(nextScale, midpoint) { | ||||||
|     const { scale } = this.state; |     const { scale, zoomMatrix } = this.state; | ||||||
|     const { scrollLeft, scrollTop } = this.container; |     const { scrollLeft, scrollTop } = this.container; | ||||||
| 
 | 
 | ||||||
|     // math memo:
 |     // math memo:
 | ||||||
|  | @ -283,6 +293,15 @@ class ZoomableImage extends React.PureComponent { | ||||||
|     this.setState({ scale: nextScale }, () => { |     this.setState({ scale: nextScale }, () => { | ||||||
|       this.container.scrollLeft = nextScrollLeft; |       this.container.scrollLeft = nextScrollLeft; | ||||||
|       this.container.scrollTop = nextScrollTop; |       this.container.scrollTop = nextScrollTop; | ||||||
|  |       // reset the translateX/Y constantly
 | ||||||
|  |       if (nextScale < zoomMatrix.rate) { | ||||||
|  |         this.setState({ | ||||||
|  |           lockTranslate: { | ||||||
|  |             x: zoomMatrix.fullScreen ? 0 : zoomMatrix.translateX * ((nextScale - MIN_SCALE) / (zoomMatrix.rate - MIN_SCALE)), | ||||||
|  |             y: zoomMatrix.fullScreen ? 0 : zoomMatrix.translateY * ((nextScale - MIN_SCALE) / (zoomMatrix.rate - MIN_SCALE)), | ||||||
|  |           }, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -307,14 +326,18 @@ class ZoomableImage extends React.PureComponent { | ||||||
|     const { offsetWidth, offsetHeight } = this.image; |     const { offsetWidth, offsetHeight } = this.image; | ||||||
|     const clientHeightFixed = clientHeight - NAV_BAR_HEIGHT; |     const clientHeightFixed = clientHeight - NAV_BAR_HEIGHT; | ||||||
| 
 | 
 | ||||||
|     const type = width/height < clientWidth / clientHeightFixed ? 'full-width' : 'full-height'; |     const type = width / height < clientWidth / clientHeightFixed ? 'width' : 'height'; | ||||||
|     const rate = type === 'full-width' ? clientWidth / offsetWidth : clientHeightFixed / offsetHeight; |     const fullScreen = type === 'width' ?  width > clientWidth : height > clientHeightFixed; | ||||||
|     const scrollTop = type === 'full-width' ?  (clientHeight - offsetHeight) / 2 - NAV_BAR_HEIGHT : (clientHeightFixed - offsetHeight) / 2; |     const rate = type === 'width' ? Math.min(clientWidth, width) / offsetWidth : Math.min(clientHeightFixed, height) / offsetHeight; | ||||||
|  |     const scrollTop = type === 'width' ?  (clientHeight - offsetHeight) / 2 - NAV_BAR_HEIGHT : (clientHeightFixed - offsetHeight) / 2; | ||||||
|     const scrollLeft = (clientWidth - offsetWidth) / 2; |     const scrollLeft = (clientWidth - offsetWidth) / 2; | ||||||
|  |     const translateX = type === 'width' ? (width - offsetWidth) / (2 * rate) : 0; | ||||||
|  |     const translateY = type === 'height' ? (height - offsetHeight) / (2 * rate) : 0; | ||||||
| 
 | 
 | ||||||
|     this.setState({ |     this.setState({ | ||||||
|       zoomMatrix: { |       zoomMatrix: { | ||||||
|         type: type, |         type: type, | ||||||
|  |         fullScreen: fullScreen, | ||||||
|         rate: rate, |         rate: rate, | ||||||
|         clientWidth: clientWidth, |         clientWidth: clientWidth, | ||||||
|         clientHeight: clientHeight, |         clientHeight: clientHeight, | ||||||
|  | @ -323,6 +346,8 @@ class ZoomableImage extends React.PureComponent { | ||||||
|         clientHeightFixed: clientHeightFixed, |         clientHeightFixed: clientHeightFixed, | ||||||
|         scrollTop: scrollTop, |         scrollTop: scrollTop, | ||||||
|         scrollLeft: scrollLeft, |         scrollLeft: scrollLeft, | ||||||
|  |         translateX: translateX, | ||||||
|  |         translateY: translateY, | ||||||
|       }, |       }, | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | @ -340,6 +365,10 @@ class ZoomableImage extends React.PureComponent { | ||||||
|           x: 0, |           x: 0, | ||||||
|           y: 0, |           y: 0, | ||||||
|         }, |         }, | ||||||
|  |         lockTranslate: { | ||||||
|  |           x: 0, | ||||||
|  |           y: 0, | ||||||
|  |         }, | ||||||
|       }, () => { |       }, () => { | ||||||
|         this.container.scrollLeft = 0; |         this.container.scrollLeft = 0; | ||||||
|         this.container.scrollTop = 0; |         this.container.scrollTop = 0; | ||||||
|  | @ -351,6 +380,10 @@ class ZoomableImage extends React.PureComponent { | ||||||
|           x: zoomMatrix.scrollLeft, |           x: zoomMatrix.scrollLeft, | ||||||
|           y: zoomMatrix.scrollTop, |           y: zoomMatrix.scrollTop, | ||||||
|         }, |         }, | ||||||
|  |         lockTranslate: { | ||||||
|  |           x: zoomMatrix.fullScreen ? 0 : zoomMatrix.translateX, | ||||||
|  |           y: zoomMatrix.fullScreen ? 0 : zoomMatrix.translateY, | ||||||
|  |         }, | ||||||
|       }, () => { |       }, () => { | ||||||
|         this.container.scrollLeft = zoomMatrix.scrollLeft; |         this.container.scrollLeft = zoomMatrix.scrollLeft; | ||||||
|         this.container.scrollTop = zoomMatrix.scrollTop; |         this.container.scrollTop = zoomMatrix.scrollTop; | ||||||
|  | @ -371,15 +404,15 @@ class ZoomableImage extends React.PureComponent { | ||||||
| 
 | 
 | ||||||
|   render () { |   render () { | ||||||
|     const { alt, src, width, height, intl } = this.props; |     const { alt, src, width, height, intl } = this.props; | ||||||
|     const { scale } = this.state; |     const { scale, lockTranslate } = this.state; | ||||||
|     const overflow = scale === 1 ? 'hidden' : 'scroll'; |     const overflow = scale === MIN_SCALE ? 'hidden' : 'scroll'; | ||||||
|     const zoomButtonSshouldHide = !this.state.navigationHidden && !this.props.zoomButtonHidden ? '' : 'media-modal__zoom-button--hidden'; |     const zoomButtonShouldHide = this.state.navigationHidden || this.props.zoomButtonHidden || this.state.zoomMatrix.rate <= MIN_SCALE ? 'media-modal__zoom-button--hidden' : ''; | ||||||
|     const zoomButtonTitle = this.state.zoomState === 'compress' ? intl.formatMessage(messages.compress) : intl.formatMessage(messages.expand); |     const zoomButtonTitle = this.state.zoomState === 'compress' ? intl.formatMessage(messages.compress) : intl.formatMessage(messages.expand); | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|       <React.Fragment> |       <React.Fragment> | ||||||
|         <IconButton |         <IconButton | ||||||
|           className={`media-modal__zoom-button ${zoomButtonSshouldHide}`} |           className={`media-modal__zoom-button ${zoomButtonShouldHide}`} | ||||||
|           title={zoomButtonTitle} |           title={zoomButtonTitle} | ||||||
|           icon={this.state.zoomState} |           icon={this.state.zoomState} | ||||||
|           onClick={this.handleZoomClick} |           onClick={this.handleZoomClick} | ||||||
|  | @ -402,7 +435,7 @@ class ZoomableImage extends React.PureComponent { | ||||||
|             width={width} |             width={width} | ||||||
|             height={height} |             height={height} | ||||||
|             style={{ |             style={{ | ||||||
|               transform: `scale(${scale})`, |               transform: `scale(${scale}) translate(-${lockTranslate.x}px, -${lockTranslate.y}px)`, | ||||||
|               transformOrigin: '0 0', |               transformOrigin: '0 0', | ||||||
|             }} |             }} | ||||||
|             draggable={false} |             draggable={false} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue