quaternionLineComponent.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { Quaternion, Vector3 } from "babylonjs/Maths/math";
  4. import { NumericInputComponent } from "./numericInputComponent";
  5. import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
  6. import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
  7. import { PropertyChangedEvent } from "../../propertyChangedEvent";
  8. import { Tools } from 'babylonjs/Misc/tools';
  9. import { SliderLineComponent } from './sliderLineComponent';
  10. interface IQuaternionLineComponentProps {
  11. label: string;
  12. target: any;
  13. useEuler?: boolean;
  14. propertyName: string;
  15. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  16. }
  17. export class QuaternionLineComponent extends React.Component<IQuaternionLineComponentProps, { isExpanded: boolean, value: Quaternion, eulerValue: Vector3 }> {
  18. private _localChange = false;
  19. constructor(props: IQuaternionLineComponentProps) {
  20. super(props);
  21. let quat = this.props.target[this.props.propertyName].clone();
  22. this.state = { isExpanded: false, value: quat, eulerValue: quat.toEulerAngles() }
  23. }
  24. shouldComponentUpdate(nextProps: IQuaternionLineComponentProps, nextState: { isExpanded: boolean, value: Quaternion }) {
  25. const nextPropsValue = nextProps.target[nextProps.propertyName];
  26. if (!nextPropsValue.equals(nextState.value) || this._localChange) {
  27. nextState.value = nextPropsValue.clone();
  28. this._localChange = false;
  29. return true;
  30. }
  31. return false;
  32. }
  33. switchExpandState() {
  34. this._localChange = true;
  35. this.setState({ isExpanded: !this.state.isExpanded });
  36. }
  37. raiseOnPropertyChanged(currentValue: Quaternion, previousValue: Quaternion) {
  38. if (!this.props.onPropertyChangedObservable) {
  39. return;
  40. }
  41. this.props.onPropertyChangedObservable.notifyObservers({
  42. object: this.props.target,
  43. property: this.props.propertyName,
  44. value: currentValue,
  45. initialValue: previousValue
  46. });
  47. }
  48. updateQuaternion() {
  49. const store = this.props.target[this.props.propertyName].clone();
  50. this.props.target[this.props.propertyName] = this.state.value;
  51. this.setState({ value: store });
  52. this.raiseOnPropertyChanged(this.state.value, store);
  53. }
  54. updateStateX(value: number) {
  55. this._localChange = true;
  56. this.state.value.x = value;
  57. this.updateQuaternion();
  58. }
  59. updateStateY(value: number) {
  60. this._localChange = true;
  61. this.state.value.y = value;
  62. this.updateQuaternion();
  63. }
  64. updateStateZ(value: number) {
  65. this._localChange = true;
  66. this.state.value.z = value;
  67. this.updateQuaternion();
  68. }
  69. updateStateW(value: number) {
  70. this._localChange = true;
  71. this.state.value.w = value;
  72. this.updateQuaternion();
  73. }
  74. updateQuaternionFromEuler() {
  75. let quat = this.state.eulerValue.toQuaternion();
  76. this.state.value.x = quat.x;
  77. this.state.value.y = quat.y;
  78. this.state.value.z = quat.z;
  79. this.state.value.w = quat.w;
  80. this.updateQuaternion();
  81. }
  82. updateStateEulerX(value: number) {
  83. this._localChange = true;
  84. this.state.eulerValue.x = Tools.ToRadians(value);
  85. this.updateQuaternionFromEuler();
  86. }
  87. updateStateEulerY(value: number) {
  88. this._localChange = true;
  89. this.state.eulerValue.y = Tools.ToRadians(value);
  90. this.updateQuaternionFromEuler();
  91. }
  92. updateStateEulerZ(value: number) {
  93. this._localChange = true;
  94. this.state.eulerValue.z = Tools.ToRadians(value);
  95. this.updateQuaternionFromEuler();
  96. }
  97. render() {
  98. const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />
  99. let quat = this.state.value;
  100. let euler = this.state.eulerValue;
  101. return (
  102. <div className="vector3Line">
  103. <div className="firstLine">
  104. <div className="label">
  105. {this.props.label}
  106. </div>
  107. <div className="vector">
  108. {
  109. !this.props.useEuler &&
  110. `X: ${quat.x.toFixed(1)}, Y: ${quat.y.toFixed(1)}, Z: ${quat.z.toFixed(1)}, W: ${quat.w.toFixed(1)}`
  111. }
  112. {
  113. this.props.useEuler &&
  114. `X: ${Tools.ToDegrees(euler.x).toFixed(2)}, Y: ${Tools.ToDegrees(euler.y).toFixed(2)}, Z: ${Tools.ToDegrees(euler.z).toFixed(2)}`
  115. }
  116. </div>
  117. <div className="expand" onClick={() => this.switchExpandState()}>
  118. {chevron}
  119. </div>
  120. </div>
  121. {
  122. this.state.isExpanded && !this.props.useEuler &&
  123. <div className="secondLine">
  124. <NumericInputComponent label="x" value={quat.x} onChange={value => this.updateStateX(value)} />
  125. <NumericInputComponent label="y" value={quat.y} onChange={value => this.updateStateY(value)} />
  126. <NumericInputComponent label="z" value={quat.z} onChange={value => this.updateStateZ(value)} />
  127. <NumericInputComponent label="w" value={quat.w} onChange={value => this.updateStateW(value)} />
  128. </div>
  129. }
  130. {
  131. this.state.isExpanded && this.props.useEuler &&
  132. <div className="secondLine">
  133. <SliderLineComponent label="x" minimum={0} maximum={360} step={0.1} directValue={Tools.ToDegrees(euler.x)} onChange={value => this.updateStateEulerX(value)} />
  134. <SliderLineComponent label="y" minimum={0} maximum={360} step={0.1} directValue={Tools.ToDegrees(euler.y)} onChange={value => this.updateStateEulerY(value)} />
  135. <SliderLineComponent label="z" minimum={0} maximum={360} step={0.1} directValue={Tools.ToDegrees(euler.z)} onChange={value => this.updateStateEulerZ(value)} />
  136. </div>
  137. }
  138. </div>
  139. );
  140. }
  141. }