matrixLineComponent.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import * as React from "react";
  2. import { Vector3, Matrix, Vector4, Quaternion } from "babylonjs/Maths/math.vector";
  3. import { Observable } from "babylonjs/Misc/observable";
  4. import { PropertyChangedEvent } from "./propertyChangedEvent";
  5. import { Vector4LineComponent } from './vector4LineComponent';
  6. import { OptionsLineComponent } from './optionsLineComponent';
  7. import { SliderLineComponent } from './sliderLineComponent';
  8. import { GlobalState } from '../globalState';
  9. interface IMatrixLineComponentProps {
  10. label: string;
  11. target: any;
  12. propertyName: string;
  13. step?: number;
  14. onChange?: (newValue: Matrix) => void;
  15. onModeChange?: (mode: number) => void;
  16. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  17. mode?: number;
  18. globalState: GlobalState;
  19. }
  20. export class MatrixLineComponent extends React.Component<IMatrixLineComponentProps, { value: Matrix, mode: number, angle: number}> {
  21. private _localChange = false;
  22. constructor(props: IMatrixLineComponentProps) {
  23. super(props);
  24. let matrix: Matrix = this.props.target[this.props.propertyName].clone();
  25. let angle = 0;
  26. if (this.props.mode) {
  27. let quat = new Quaternion();
  28. matrix.decompose(undefined, quat);
  29. let euler = quat.toEulerAngles();
  30. switch (this.props.mode) {
  31. case 1:
  32. angle = euler.x;
  33. break;
  34. case 2:
  35. angle = euler.y;
  36. break;
  37. case 3:
  38. angle = euler.z;
  39. break;
  40. }
  41. }
  42. this.state = { value:matrix, mode: this.props.mode || 0, angle: angle };
  43. }
  44. shouldComponentUpdate(nextProps: IMatrixLineComponentProps, nextState: { value: Matrix, mode: number, angle: number }) {
  45. const nextPropsValue = nextProps.target[nextProps.propertyName];
  46. if (!nextPropsValue.equals(nextState.value) || this._localChange) {
  47. nextState.value = nextPropsValue.clone();
  48. this._localChange = false;
  49. return true;
  50. }
  51. return nextState.mode !== this.state.mode || nextState.angle !== this.state.angle;
  52. }
  53. raiseOnPropertyChanged(previousValue: Vector3) {
  54. if (this.props.onChange) {
  55. this.props.onChange(this.state.value);
  56. }
  57. if (!this.props.onPropertyChangedObservable) {
  58. return;
  59. }
  60. this.props.onPropertyChangedObservable.notifyObservers({
  61. object: this.props.target,
  62. property: this.props.propertyName,
  63. value: this.state.value,
  64. initialValue: previousValue
  65. });
  66. }
  67. updateMatrix() {
  68. const store = this.props.target[this.props.propertyName].clone();
  69. this.props.target[this.props.propertyName] = this.state.value;
  70. this.setState({ value: store });
  71. this.raiseOnPropertyChanged(store);
  72. }
  73. updateRow(value: Vector4, row: number) {
  74. this._localChange = true;
  75. this.state.value.setRow(row, value);
  76. this.updateMatrix();
  77. }
  78. updateBasedOnMode(value: number) {
  79. switch (this.state.mode) {
  80. case 1: {
  81. Matrix.RotationXToRef(this.state.angle, this.state.value);
  82. break;
  83. }
  84. case 2: {
  85. Matrix.RotationYToRef(this.state.angle, this.state.value);
  86. break;
  87. }
  88. case 3: {
  89. Matrix.RotationZToRef(this.state.angle, this.state.value);
  90. break;
  91. }
  92. }
  93. this.updateMatrix();
  94. this.setState({angle: value});
  95. }
  96. render() {
  97. var modeOptions = [
  98. { label: "User-defined", value: 0 },
  99. { label: "Rotation over X axis", value: 1 },
  100. { label: "Rotation over Y axis", value: 2 },
  101. { label: "Rotation over Z axis", value: 3 },
  102. ];
  103. return (
  104. <div className="vector3Line">
  105. <div className="firstLine">
  106. <div className="label">
  107. {this.props.label}
  108. </div>
  109. </div>
  110. <div className="secondLine">
  111. <OptionsLineComponent label="Mode"
  112. className="no-right-margin"
  113. options={modeOptions} target={this}
  114. noDirectUpdate={true}
  115. getSelection={() => {
  116. return this.state.mode;
  117. }}
  118. onSelect={(value: any) => {
  119. this.props.target[this.props.propertyName] = Matrix.Identity();
  120. Matrix.IdentityToRef(this.state.value);
  121. this.setState({mode: value, angle: 0});
  122. this.updateMatrix();
  123. if (this.props.onModeChange) {
  124. this.props.onModeChange(value);
  125. }
  126. }} />
  127. </div>
  128. {
  129. this.state.mode === 0 &&
  130. <div className="secondLine">
  131. <Vector4LineComponent globalState={this.props.globalState} label="Row #0" value={this.state.value.getRow(0)!} onChange={value => this.updateRow(value, 0)}/>
  132. <Vector4LineComponent globalState={this.props.globalState} label="Row #1" value={this.state.value.getRow(1)!} onChange={value => this.updateRow(value, 1)}/>
  133. <Vector4LineComponent globalState={this.props.globalState} label="Row #2" value={this.state.value.getRow(2)!} onChange={value => this.updateRow(value, 2)}/>
  134. <Vector4LineComponent globalState={this.props.globalState} label="Row #3" value={this.state.value.getRow(3)!} onChange={value => this.updateRow(value, 3)}/>
  135. </div>
  136. }
  137. {
  138. this.state.mode !== 0 &&
  139. <div className="secondLine">
  140. <SliderLineComponent label="Angle" minimum={0} maximum={2 * Math.PI} useEuler={true} step={0.1} globalState={this.props.globalState} directValue={this.state.angle} onChange={value => this.updateBasedOnMode(value)}/>
  141. </div>
  142. }
  143. </div>
  144. );
  145. }
  146. }