floatLineComponent.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { PropertyChangedEvent } from "../../propertyChangedEvent";
  4. import { LockObject } from "../tabs/propertyGrids/lockObject";
  5. import { SliderLineComponent } from './sliderLineComponent';
  6. import { Tools } from 'babylonjs/Misc/tools';
  7. interface IFloatLineComponentProps {
  8. label: string;
  9. target: any;
  10. propertyName: string;
  11. lockObject?: LockObject;
  12. onChange?: (newValue: number) => void;
  13. isInteger?: boolean;
  14. replaySourceReplacement?: string;
  15. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  16. additionalClass?: string;
  17. step?: string,
  18. digits?: number;
  19. useEuler?: boolean;
  20. min?: number
  21. }
  22. export class FloatLineComponent extends React.Component<IFloatLineComponentProps, { value: string }> {
  23. private _localChange = false;
  24. private _store: number;
  25. constructor(props: IFloatLineComponentProps) {
  26. super(props);
  27. let currentValue = this.props.target[this.props.propertyName];
  28. this.state = { value: currentValue ? (this.props.isInteger ? currentValue.toFixed(0) : currentValue.toFixed(this.props.digits || 3)) : "0" };
  29. this._store = currentValue;
  30. }
  31. componentWillUnmount() {
  32. this.unlock();
  33. }
  34. shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: { value: string }) {
  35. if (this._localChange) {
  36. this._localChange = false;
  37. return true;
  38. }
  39. const newValue = nextProps.target[nextProps.propertyName];
  40. const newValueString = newValue ? this.props.isInteger ? newValue.toFixed(0) : newValue.toFixed(this.props.digits || 3) : "0";
  41. if (newValueString !== nextState.value) {
  42. nextState.value = newValueString;
  43. return true;
  44. }
  45. return false;
  46. }
  47. raiseOnPropertyChanged(newValue: number, previousValue: number) {
  48. if (this.props.onChange) {
  49. this.props.onChange(newValue);
  50. }
  51. if (!this.props.onPropertyChangedObservable) {
  52. return;
  53. }
  54. this.props.onPropertyChangedObservable.notifyObservers({
  55. object: this.props.replaySourceReplacement ?? this.props.target,
  56. property: this.props.propertyName,
  57. value: newValue,
  58. initialValue: previousValue
  59. });
  60. }
  61. updateValue(valueString: string) {
  62. if (/[^0-9\.\-]/g.test(valueString)) {
  63. return;
  64. }
  65. let valueAsNumber: number;
  66. if (this.props.isInteger) {
  67. valueAsNumber = parseInt(valueString);
  68. } else {
  69. valueAsNumber = parseFloat(valueString);
  70. }
  71. if (!isNaN(valueAsNumber) && this.props.min !== undefined) {
  72. if (valueAsNumber < this.props.min) {
  73. valueAsNumber = this.props.min;
  74. valueString = valueAsNumber.toString();
  75. }
  76. }
  77. this._localChange = true;
  78. this.setState({ value: valueString });
  79. if (isNaN(valueAsNumber)) {
  80. return;
  81. }
  82. this.props.target[this.props.propertyName] = valueAsNumber;
  83. this.raiseOnPropertyChanged(valueAsNumber, this._store);
  84. this._store = valueAsNumber;
  85. }
  86. lock() {
  87. if (this.props.lockObject) {
  88. this.props.lockObject.lock = true;
  89. }
  90. }
  91. unlock() {
  92. if (this.props.lockObject) {
  93. this.props.lockObject.lock = false;
  94. }
  95. }
  96. render() {
  97. let valueAsNumber: number;
  98. if (this.props.isInteger) {
  99. valueAsNumber = parseInt(this.state.value);
  100. } else {
  101. valueAsNumber = parseFloat(this.state.value);
  102. }
  103. return (
  104. <div>
  105. {
  106. !this.props.useEuler &&
  107. <div className={this.props.additionalClass ? this.props.additionalClass + " floatLine" : "floatLine"}>
  108. <div className="label">
  109. {this.props.label}
  110. </div>
  111. <div className="value">
  112. <input type="number" step={this.props.step || this.props.isInteger ? "1" : "0.01"} className="numeric-input" value={this.state.value} onBlur={() => this.unlock()} onFocus={() => this.lock()} onChange={evt => this.updateValue(evt.target.value)} />
  113. </div>
  114. </div>
  115. }
  116. {
  117. this.props.useEuler &&
  118. <SliderLineComponent label={this.props.label} minimum={0} maximum={360} step={0.1} directValue={Tools.ToDegrees(valueAsNumber)} onChange={value => this.updateValue(Tools.ToRadians(value).toString())} />
  119. }
  120. </div>
  121. );
  122. }
  123. }