diff options
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx')
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx new file mode 100644 index 000000000..5e5a60edd --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx @@ -0,0 +1,183 @@ +import { TextField, InputAdornment } from "@mui/material"; +import { Doc } from '../../../../fields/Doc'; +import React = require('react'); +import TaskAltIcon from "@mui/icons-material/TaskAlt"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +export interface IInputProps { + label?: JSX.Element; + lowerBound: number; + dataDoc: Doc; + prop: string; + step: number; + unit: string; + upperBound: number; + value: number | string | Array<number | string>; + correctValue?: number; + showIcon?: boolean; + effect?: (val: number) => any; + radianEquivalent?: boolean; + small?: boolean; + mode?: string; + update?: boolean; + labelWidth?: string; +} + +interface IState { + tempValue: string | number | (string|number)[], + tempRadianValue: number, + width: string; + margin: string; +} + +export default class InputField extends React.Component<IInputProps, IState> { + constructor(props: any) { + super(props) + this.state = { + tempValue: this.props.mode != "Freeform" && !this.props.showIcon ? 0 : this.props.value, + tempRadianValue: this.props.mode != "Freeform" && !this.props.showIcon ? 0 : (Number(this.props.value) * Math.PI) / 180, + width: this.props.small ? "6em" : "7em", + margin: this.props.small ? "0px" : "10px" + } + } + + epsilon: number = 0.01; + + componentDidMount(): void { + this.setState({tempValue: Number(this.props.value)}) + } + + componentDidUpdate(prevProps: Readonly<IInputProps>, prevState: Readonly<IState>, snapshot?: any): void { + if (prevProps.value != this.props.value && !isNaN(this.props.value)) { + if (this.props.mode == "Freeform") { + if (Math.abs(this.state.tempValue - Number(this.props.value)) > 1) { + this.setState({tempValue: Number(this.props.value)}) + } + } + } + if (prevProps.update != this.props.update) { + this.externalUpdate(); + } + } + + externalUpdate = () => { + this.setState({tempValue: Number(this.props.value)}) + this.setState({tempRadianValue: Number(this.props.value) * Math.PI / 180}) + }; + + onChange = (event: React.ChangeEvent<HTMLInputElement>) => { + let value = event.target.value == "" ? 0 : Number(event.target.value); + if (value > this.props.upperBound) { + value = this.props.upperBound; + } else if (value < this.props.lowerBound) { + value = this.props.lowerBound; + } + if (this.props.prop != "") { + this.props.dataDoc[this.props.prop] = value + } + this.setState({tempValue: event.target.value == "" ? event.target.value : value}) + this.setState({tempRadianValue: (value * Math.PI) / 180}) + if (this.props.effect) { + this.props.effect(value); + } + }; + + onChangeRadianValue = (event: React.ChangeEvent<HTMLInputElement>) => { + let value = event.target.value === "" ? 0 : Number(event.target.value); + if (value > 2 * Math.PI) { + value = 2 * Math.PI; + } else if (value < 0) { + value = 0; + }if (this.props.prop != "") { + this.props.dataDoc[this.props.prop] = (value * 180) / Math.PI + } + this.setState({tempValue: (value * 180) / Math.PI}) + this.setState({tempRadianValue: value}) + if (this.props.effect) { + this.props.effect((value * 180) / Math.PI); + } + }; + + render () { + return ( + <div + style={{ + display: "flex", + lineHeight: "1.5", + textAlign: "right", + alignItems: "center", + }} + > + {this.props.label && ( + <div + style={{ + marginTop: "0.3em", + marginBottom: "-0.5em", + width: this.props.labelWidth ?? "2em", + }} + > + {this.props.label} + </div> + )} + <TextField + type="number" + variant="standard" + value={this.state.tempValue} + onChange={this.onChange} + sx={{ + height: "1em", + width: this.state.width, + marginLeft: this.state.margin, + zIndex: "modal", + }} + inputProps={{ + step: this.props.step, + min: this.props.lowerBound, + max: this.props.upperBound, + type: "number", + }} + InputProps={{ + startAdornment: ( + <InputAdornment position="start"> + {Math.abs(Number(this.props.value) - (this.props.correctValue ?? 0)) < this.epsilon && + this.props.showIcon && <TaskAltIcon color={"success"} />} + {Math.abs(Number(this.props.value) - (this.props.correctValue ?? 0)) >= this.epsilon && + this.props.showIcon && <ErrorOutlineIcon color={"error"} />} + </InputAdornment> + ), + endAdornment: <InputAdornment position="end">{this.props.unit}</InputAdornment>, + }} + /> + {this.props.radianEquivalent && ( + <div + style={{ marginTop: "0.3em", marginBottom: "-0.5em", width: "1em" }} + > + <p>≈</p> + </div> + )} + {this.props.radianEquivalent && ( + <TextField + type="number" + variant="standard" + value={this.state.tempRadianValue} + onChange={this.onChangeRadianValue} + sx={{ + height: "1em", + width: this.state.width, + marginLeft: this.state.margin, + zIndex: "modal", + }} + inputProps={{ + step: Math.PI / 8, + min: 0, + max: 2 * Math.PI, + type: "number", + }} + InputProps={{ + endAdornment: <InputAdornment position="end">rad</InputAdornment>, + }} + /> + )} + </div> + ) + } +}; |