diff --git a/res/css/views/elements/_ImageView.scss b/res/css/views/elements/_ImageView.scss index ec651fcc6a..10553a1c54 100644 --- a/res/css/views/elements/_ImageView.scss +++ b/res/css/views/elements/_ImageView.scss @@ -33,7 +33,7 @@ limitations under the License. } .mx_ImageView_imageBox { - overflow: scroll; + overflow: hidden; display: flex; padding: 0 50px 50px 50px; flex-grow: 1; @@ -41,6 +41,10 @@ limitations under the License. .mainImage { margin: auto; + + &:hover { + cursor: grab; + } } .mx_ImageView_content img { diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index 2feff97fef..8cc55e40bf 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -47,11 +47,19 @@ export default class ImageView extends React.Component { constructor(props) { super(props); this.state = { - rotationDegrees: 0, + rotation: 0, zoom: 100, + translationX: 0, + translationY: 0, + moving: false, }; } + initX = 0; + initY = 0; + lastX = 0; + lastY = 0; + componentDidMount() { // We have to use addEventListener() because the listener // needs to be passive in order to work with Chromium @@ -74,8 +82,18 @@ export default class ImageView extends React.Component { if (ev.ctrlKey) { ev.stopPropagation(); ev.preventDefault(); + const newZoom =this.state.zoom - ev.deltaY; + + if (newZoom <= 100) { + this.setState({ + zoom: 100, + translationX: 0, + translationY: 0, + }); + return; + } this.setState({ - zoom: this.state.zoom - ev.deltaY, + zoom: newZoom, }); } } @@ -109,65 +127,72 @@ export default class ImageView extends React.Component { return name; } - rotateCounterClockwise = () => { - const cur = this.state.rotationDegrees; + onRotateCounterClockwiseClick = () => { + const cur = this.state.rotation; const rotationDegrees = (cur - 90) % 360; - this.setState({ rotationDegrees }); + this.setState({ rotation: rotationDegrees }); }; - rotateClockwise = () => { - const cur = this.state.rotationDegrees; + onRotateClockwiseClick = () => { + const cur = this.state.rotation; const rotationDegrees = (cur + 90) % 360; - this.setState({ rotationDegrees }); + this.setState({ rotation: rotationDegrees }); }; - zoomIn = () => { + onZoomInClick = () => { this.setState({ zoom: this.state.zoom + 10, }); }; - zoomOut = () => { + onZoomOutClick = () => { + if (this.state.zoom <= 100) { + this.setState({ + zoom: 100, + translationX: 0, + translationY: 0, + }); + return; + } this.setState({ zoom: this.state.zoom - 10, }); } + onStartMoving = ev => { + ev.stopPropagation(); + ev.preventDefault(); + + if (this.state.zoom <= 100) return false; + + this.setState({moving: true}); + this.initX = ev.pageX - this.lastX; + this.initY = ev.pageY - this.lastY; + } + + onMoving = ev => { + ev.stopPropagation(); + ev.preventDefault(); + + if (!this.state.moving) return false; + + this.lastX = ev.pageX - this.initX; + this.lastY = ev.pageY - this.initY; + this.setState({ + translationX: this.lastX, + translationY: this.lastY, + }); + } + + onEndMoving = ev => { + this.setState({moving: false}); + } + render() { -/* - // In theory max-width: 80%, max-height: 80% on the CSS should work - // but in practice, it doesn't, so do it manually: + let mayRedact = false; + const showEventMeta = !!this.props.mxEvent; - var width = this.props.width || 500; - var height = this.props.height || 500; - - var maxWidth = document.documentElement.clientWidth * 0.8; - var maxHeight = document.documentElement.clientHeight * 0.8; - - var widthFrac = width / maxWidth; - var heightFrac = height / maxHeight; - - var displayWidth; - var displayHeight; - if (widthFrac > heightFrac) { - displayWidth = Math.min(width, maxWidth); - displayHeight = (displayWidth / width) * height; - } else { - displayHeight = Math.min(height, maxHeight); - displayWidth = (displayHeight / height) * width; - } - - var style = { - width: displayWidth, - height: displayHeight - }; -*/ let res; - const style = { - height: this.state.zoom + "%", - width: this.state.zoom + "%", - }; - if (this.props.width && this.props.height) { res = this.props.width + "x" + this.props.height + "px"; } @@ -184,9 +209,6 @@ export default class ImageView extends React.Component { sizeRes = size || res; } - let mayRedact = false; - const showEventMeta = !!this.props.mxEvent; - let metadata; if (showEventMeta) { // Figure out the sender, defaulting to mxid @@ -216,8 +238,16 @@ export default class ImageView extends React.Component { ); } - const rotationDegrees = this.state.rotationDegrees; - const effectiveStyle = {transform: `rotate(${rotationDegrees}deg)`, ...style}; + const rotationDegrees = this.state.rotation + "deg"; + const zoomPercentage = this.state.zoom/100; + const translatePixelsX = this.state.translationX + "px"; + const translatePixelsY = this.state.translationY + "px"; + const style = { + transform: `rotate(${rotationDegrees}) + scale(${zoomPercentage}) + translateX(${translatePixelsX}) + translateY(${translatePixelsY})`, + }; return ( { sizeRes }
- + { - + { - + { - + { @@ -261,7 +291,17 @@ export default class ImageView extends React.Component {
- +