animationGroupPropertyGridComponent.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import * as React from "react";
  2. import { Nullable } from "babylonjs/types";
  3. import { Observable, Observer } from "babylonjs/Misc/observable";
  4. import { AnimationGroup } from "babylonjs/Animations/animationGroup";
  5. import { Scene } from "babylonjs/scene";
  6. import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
  7. import { ButtonLineComponent } from "../../../../../sharedUiComponents/lines/buttonLineComponent";
  8. import { LineContainerComponent } from "../../../../../sharedUiComponents/lines/lineContainerComponent";
  9. import { TextLineComponent } from "../../../../../sharedUiComponents/lines/textLineComponent";
  10. import { SliderLineComponent } from "../../../../../sharedUiComponents/lines/sliderLineComponent";
  11. import { LockObject } from "../../../../../sharedUiComponents/tabs/propertyGrids/lockObject";
  12. import { GlobalState } from "../../../../globalState";
  13. import { TextInputLineComponent } from "../../../../../sharedUiComponents/lines/textInputLineComponent";
  14. interface IAnimationGroupGridComponentProps {
  15. globalState: GlobalState;
  16. animationGroup: AnimationGroup;
  17. scene: Scene;
  18. lockObject: LockObject;
  19. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  20. }
  21. export class AnimationGroupGridComponent extends React.Component<
  22. IAnimationGroupGridComponentProps,
  23. { playButtonText: string; currentFrame: number }
  24. > {
  25. private _onAnimationGroupPlayObserver: Nullable<Observer<AnimationGroup>>;
  26. private _onAnimationGroupPauseObserver: Nullable<Observer<AnimationGroup>>;
  27. private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
  28. private timelineRef: React.RefObject<SliderLineComponent>;
  29. constructor(props: IAnimationGroupGridComponentProps) {
  30. super(props);
  31. const animationGroup = this.props.animationGroup;
  32. this.state = { playButtonText: animationGroup.isPlaying ? "Pause" : "Play", currentFrame: 0 };
  33. this.connect(this.props.animationGroup);
  34. this._onBeforeRenderObserver = this.props.scene.onBeforeRenderObservable.add(() => {
  35. this.updateCurrentFrame(this.props.animationGroup);
  36. });
  37. this.timelineRef = React.createRef();
  38. }
  39. disconnect(animationGroup: AnimationGroup) {
  40. if (this._onAnimationGroupPlayObserver) {
  41. animationGroup.onAnimationGroupPlayObservable.remove(this._onAnimationGroupPlayObserver);
  42. this._onAnimationGroupPlayObserver = null;
  43. }
  44. if (this._onAnimationGroupPauseObserver) {
  45. animationGroup.onAnimationGroupPauseObservable.remove(this._onAnimationGroupPauseObserver);
  46. this._onAnimationGroupPauseObserver = null;
  47. }
  48. }
  49. connect(animationGroup: AnimationGroup) {
  50. this._onAnimationGroupPlayObserver = animationGroup.onAnimationGroupPlayObservable.add(() => {
  51. this.forceUpdate();
  52. });
  53. this._onAnimationGroupPauseObserver = animationGroup.onAnimationGroupPauseObservable.add(() => {
  54. this.forceUpdate();
  55. });
  56. this.updateCurrentFrame(animationGroup);
  57. }
  58. updateCurrentFrame(animationGroup: AnimationGroup) {
  59. var targetedAnimations = animationGroup.targetedAnimations;
  60. if (targetedAnimations.length > 0) {
  61. var runtimeAnimations = animationGroup.targetedAnimations[0].animation.runtimeAnimations;
  62. if (runtimeAnimations.length > 0) {
  63. this.setState({ currentFrame: runtimeAnimations[0].currentFrame });
  64. } else {
  65. this.setState({ currentFrame: 0 });
  66. }
  67. }
  68. }
  69. shouldComponentUpdate(nextProps: IAnimationGroupGridComponentProps): boolean {
  70. if (this.props.animationGroup !== nextProps.animationGroup) {
  71. this.disconnect(this.props.animationGroup);
  72. this.connect(nextProps.animationGroup);
  73. }
  74. return true;
  75. }
  76. componentWillUnmount() {
  77. this.disconnect(this.props.animationGroup);
  78. if (this._onBeforeRenderObserver) {
  79. this.props.scene.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
  80. this._onBeforeRenderObserver = null;
  81. }
  82. }
  83. playOrPause() {
  84. const animationGroup = this.props.animationGroup;
  85. if (animationGroup.isPlaying) {
  86. this.setState({ playButtonText: "Play" });
  87. animationGroup.pause();
  88. } else {
  89. this.setState({ playButtonText: "Pause" });
  90. this.props.scene.animationGroups.forEach((grp) => grp.pause());
  91. animationGroup.play(true);
  92. }
  93. }
  94. onCurrentFrameChange(value: number) {
  95. const animationGroup = this.props.animationGroup;
  96. if (!animationGroup.isPlaying) {
  97. animationGroup.play(true);
  98. animationGroup.goToFrame(value);
  99. animationGroup.pause();
  100. } else {
  101. animationGroup.goToFrame(value);
  102. }
  103. this.setState({ currentFrame: value });
  104. }
  105. render() {
  106. const animationGroup = this.props.animationGroup;
  107. const playButtonText = animationGroup.isPlaying ? "Pause" : "Play";
  108. return (
  109. <div className="pane">
  110. <LineContainerComponent title="GENERAL">
  111. <TextLineComponent label="Class" value={animationGroup.getClassName()} />
  112. <TextInputLineComponent
  113. lockObject={this.props.lockObject}
  114. label="Name"
  115. target={animationGroup}
  116. propertyName="name"
  117. onPropertyChangedObservable={this.props.onPropertyChangedObservable}
  118. />
  119. </LineContainerComponent>
  120. <LineContainerComponent title="CONTROLS">
  121. <ButtonLineComponent label={playButtonText} onClick={() => this.playOrPause()} />
  122. <SliderLineComponent
  123. label="Speed ratio"
  124. minimum={0}
  125. maximum={10}
  126. step={0.1}
  127. target={animationGroup}
  128. propertyName="speedRatio"
  129. onPropertyChangedObservable={this.props.onPropertyChangedObservable}
  130. />
  131. <SliderLineComponent
  132. ref={this.timelineRef}
  133. label="Current frame"
  134. minimum={animationGroup.from}
  135. maximum={animationGroup.to}
  136. step={(animationGroup.to - animationGroup.from) / 1000.0}
  137. directValue={this.state.currentFrame}
  138. onInput={(value) => this.onCurrentFrameChange(value)}
  139. />
  140. </LineContainerComponent>
  141. <LineContainerComponent title="INFOS">
  142. <TextLineComponent
  143. label="Animation count"
  144. value={animationGroup.targetedAnimations.length.toString()}
  145. />
  146. <TextLineComponent label="From" value={animationGroup.from.toFixed(2)} />
  147. <TextLineComponent label="To" value={animationGroup.to.toFixed(2)} />
  148. <TextLineComponent label="Unique ID" value={animationGroup.uniqueId.toString()} />
  149. </LineContainerComponent>
  150. </div>
  151. );
  152. }
  153. }