From 0aec56f8ab6da5b60d5592fcd24b31a9b7dd5672 Mon Sep 17 00:00:00 2001 From: Aries Date: Thu, 26 Jun 2025 17:20:15 +0800 Subject: [PATCH] support changing the image view position by dragging after zooming in (#7964) Co-authored-by: zhouwenxuan --- .../src/components/file-content-view/image.js | 28 +++++--- frontend/src/file-view.js | 64 +++++++++++++++++-- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/file-content-view/image.js b/frontend/src/components/file-content-view/image.js index 076c52195b..ca9ae41026 100644 --- a/frontend/src/components/file-content-view/image.js +++ b/frontend/src/components/file-content-view/image.js @@ -61,16 +61,25 @@ class FileContent extends React.Component { thumbnailURL = `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${Utils.encodePath(filePath)}?mtime=${lastModificationTime}`; } - const { scale, angle } = this.props; - let style = {}; - if (scale && angle != undefined) { - style = { transform: `scale(${scale}) rotate(${angle}deg)` }; - } else if (scale) { - style = { transform: `scale(${scale})` }; - } else if (angle != undefined) { - style = { transform: `rotate(${angle}deg)` }; + const { scale, angle, offset } = this.props; + let transforms = []; + + if (scale) { + transforms.push(`scale(${scale})`); + } + if (angle !== undefined) { + transforms.push(`rotate(${angle}deg)`); } + let style = {}; + if (transforms.length > 0) { + style.transform = transforms.join(' '); + } + if (scale > 1 && offset && typeof offset === 'object') { + if (offset.x !== undefined) style.left = offset.x; + if (offset.y !== undefined) style.top = offset.y; + style.position = 'relative'; + } return (
@@ -89,7 +98,8 @@ class FileContent extends React.Component { FileContent.propTypes = { tip: PropTypes.object.isRequired, scale: PropTypes.number, - angle: PropTypes.number + angle: PropTypes.number, + offset: PropTypes.object, }; export default FileContent; diff --git a/frontend/src/file-view.js b/frontend/src/file-view.js index b9c3e8c8bf..c903dc0803 100644 --- a/frontend/src/file-view.js +++ b/frontend/src/file-view.js @@ -22,14 +22,20 @@ class InnerFileView extends React.Component { super(); this.state = { imageScale: 1, - imageAngle: 0 + imageAngle: 0, + imageOffset: { x: 0, y: 0 }, + isDragging: false, + dragStart: null, + dragOrigin: null, }; + this.imageContainerRef = React.createRef(); } setImageScale = (scale) => { - this.setState({ - imageScale: scale - }); + this.setState(prevState => ({ + imageScale: scale, + imageOffset: scale === 1 ? { x: 0, y: 0 } : prevState.imageOffset, + })); }; rotateImage = () => { @@ -46,6 +52,36 @@ class InnerFileView extends React.Component { }); }; + handleImageMouseDown = (e) => { + if (this.state.imageScale <= 1) return; + e.preventDefault(); + this.setState({ + isDragging: true, + dragStart: { x: e.clientX, y: e.clientY }, + dragOrigin: { ...this.state.imageOffset } + }); + document.addEventListener('mousedown', this.handleImageMouseDown); + document.addEventListener('mouseup', this.handleImageMouseUp); + }; + + handleImageMouseMove = (e) => { + if (!this.state.isDragging) return; + const dx = e.clientX - this.state.dragStart.x; + const dy = e.clientY - this.state.dragStart.y; + this.setState({ + imageOffset: { + x: this.state.dragOrigin.x + dx, + y: this.state.dragOrigin.y + dy + } + }); + }; + + handleImageMouseUp = (e) => { + this.setState({ isDragging: false }); + document.removeEventListener('mousedown', this.handleImageMouseDown); + document.removeEventListener('mouseup', this.handleImageMouseUp); + }; + render() { if (err) { return ( @@ -53,11 +89,27 @@ class InnerFileView extends React.Component { ); } - const { imageScale, imageAngle } = this.state; + const { imageScale, imageAngle, imageOffset } = this.state; let content; switch (fileType) { case 'Image': - content = } scale={imageScale} angle={imageAngle} />; + content = ( +
1 ? 'move' : 'default' }} + onMouseDown={this.handleImageMouseDown} + onMouseMove={this.handleImageMouseMove} + onMouseUp={this.handleImageMouseUp} + > + } + scale={imageScale} + angle={imageAngle} + offset={imageOffset} + /> +
+ ); break; case 'SVG': content = ;