floatLineComponent.tsx 4.9 KB

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