floatLineComponent.tsx 4.8 KB

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