matrixLineComponent.tsx 6.2 KB

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