Files
CHOMPStation2/tgui/packages/tgui/components/InfinitePlane.jsx
CHOMPStation2 85ca379bb2 [MIRROR] [TGUI 5.0 Prep] JS to JSX (#7414)
Co-authored-by: Selis <sirlionfur@hotmail.de>
Co-authored-by: Selis <selis@xynolabs.com>
2023-12-13 23:23:03 +01:00

189 lines
4.8 KiB
JavaScript

import { computeBoxProps } from './Box';
import { Stack } from './Stack';
import { ProgressBar } from './ProgressBar';
import { Button } from './Button';
import { Component } from 'inferno';
const ZOOM_MIN_VAL = 0.5;
const ZOOM_MAX_VAL = 1.5;
const ZOOM_INCREMENT = 0.1;
export class InfinitePlane extends Component {
constructor() {
super();
this.state = {
mouseDown: false,
left: 0,
top: 0,
lastLeft: 0,
lastTop: 0,
zoom: 1,
};
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleZoomIncrease = this.handleZoomIncrease.bind(this);
this.handleZoomDecrease = this.handleZoomDecrease.bind(this);
this.onMouseUp = this.onMouseUp.bind(this);
this.doOffsetMouse = this.doOffsetMouse.bind(this);
}
componentDidMount() {
window.addEventListener('mouseup', this.onMouseUp);
window.addEventListener('mousedown', this.doOffsetMouse);
window.addEventListener('mousemove', this.doOffsetMouse);
window.addEventListener('mouseup', this.doOffsetMouse);
}
componentWillUnmount() {
window.removeEventListener('mouseup', this.onMouseUp);
window.removeEventListener('mousedown', this.doOffsetMouse);
window.removeEventListener('mousemove', this.doOffsetMouse);
window.removeEventListener('mouseup', this.doOffsetMouse);
}
doOffsetMouse(event) {
const { zoom } = this.state;
event.screenZoomX = event.screenX * Math.pow(zoom, -1);
event.screenZoomY = event.screenY * Math.pow(zoom, -1);
}
handleMouseDown(event) {
this.setState((state) => {
return {
mouseDown: true,
lastLeft: event.clientX - state.left,
lastTop: event.clientY - state.top,
};
});
}
onMouseUp() {
this.setState({
mouseDown: false,
});
}
handleZoomIncrease(event) {
const { onZoomChange } = this.props;
const { zoom } = this.state;
const newZoomValue = Math.min(zoom + ZOOM_INCREMENT, ZOOM_MAX_VAL);
this.setState({
zoom: newZoomValue,
});
if (onZoomChange) {
onZoomChange(newZoomValue);
}
}
handleZoomDecrease(event) {
const { onZoomChange } = this.props;
const { zoom } = this.state;
const newZoomValue = Math.max(zoom - ZOOM_INCREMENT, ZOOM_MIN_VAL);
this.setState({
zoom: newZoomValue,
});
if (onZoomChange) {
onZoomChange(newZoomValue);
}
}
handleMouseMove(event) {
const { onBackgroundMoved, initialLeft = 0, initialTop = 0 } = this.props;
if (this.state.mouseDown) {
let newX, newY;
this.setState((state) => {
newX = event.clientX - state.lastLeft;
newY = event.clientY - state.lastTop;
return {
left: newX,
top: newY,
};
});
if (onBackgroundMoved) {
onBackgroundMoved(newX + initialLeft, newY + initialTop);
}
}
}
render() {
const {
children,
backgroundImage,
imageWidth,
initialLeft = 0,
initialTop = 0,
...rest
} = this.props;
const { left, top, zoom } = this.state;
const finalLeft = initialLeft + left;
const finalTop = initialTop + top;
return (
<div
ref={this.ref}
{...computeBoxProps({
...rest,
style: {
...rest.style,
overflow: 'hidden',
position: 'relative',
},
})}>
<div
onMouseDown={this.handleMouseDown}
onMouseMove={this.handleMouseMove}
style={{
'position': 'fixed',
'height': '100%',
'width': '100%',
'background-image': `url("${backgroundImage}")`,
'background-position': `${finalLeft}px ${finalTop}px`,
'background-repeat': 'repeat',
'background-size': `${zoom * imageWidth}px`,
}}
/>
<div
onMouseDown={this.handleMouseDown}
onMouseMove={this.handleMouseMove}
style={{
'position': 'fixed',
'transform': `translate(${finalLeft}px, ${finalTop}px) scale(${zoom})`,
'transform-origin': 'top left',
'height': '100%',
'width': '100%',
}}>
{children}
</div>
<Stack position="absolute" width="100%">
<Stack.Item>
<Button icon="minus" onClick={this.handleZoomDecrease} />
</Stack.Item>
<Stack.Item grow={1}>
<ProgressBar
minValue={ZOOM_MIN_VAL}
value={zoom}
maxValue={ZOOM_MAX_VAL}>
{zoom}x
</ProgressBar>
</Stack.Item>
<Stack.Item>
<Button icon="plus" onClick={this.handleZoomIncrease} />
</Stack.Item>
</Stack>
</div>
);
}
}