babylon.autoRotationBehavior.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. module BABYLON {
  2. export class AutoRotationBehavior implements Behavior<ArcRotateCamera> {
  3. public get name(): string {
  4. return "AutoRotation";
  5. }
  6. private _zoomStopsAnimation = false;
  7. private _idleRotationSpeed = 0.05;
  8. private _idleRotationWaitTime = 2000;
  9. private _idleRotationSpinupTime = 2000;
  10. /**
  11. * Sets the flag that indicates if user zooming should stop animation.
  12. */
  13. public set zoomStopsAnimation(flag: boolean) {
  14. this._zoomStopsAnimation = flag;
  15. }
  16. /**
  17. * Gets the flag that indicates if user zooming should stop animation.
  18. */
  19. public get zoomStopsAnimation(): boolean {
  20. return this._zoomStopsAnimation;
  21. }
  22. /**
  23. * Sets the default speed at which the camera rotates around the model.
  24. */
  25. public set idleRotationSpeed(speed: number) {
  26. this._idleRotationSpeed = speed;
  27. }
  28. /**
  29. * Gets the default speed at which the camera rotates around the model.
  30. */
  31. public get idleRotationSpeed() {
  32. return this._idleRotationSpeed;
  33. }
  34. /**
  35. * Sets the time (in milliseconds) to wait after user interaction before the camera starts rotating.
  36. */
  37. public set idleRotationWaitTime(time: number) {
  38. this._idleRotationWaitTime = time;
  39. }
  40. /**
  41. * Gets the time (milliseconds) to wait after user interaction before the camera starts rotating.
  42. */
  43. public get idleRotationWaitTime() {
  44. return this._idleRotationWaitTime;
  45. }
  46. /**
  47. * Sets the time (milliseconds) to take to spin up to the full idle rotation speed.
  48. */
  49. public set idleRotationSpinupTime(time: number) {
  50. this._idleRotationSpinupTime = time;
  51. }
  52. /**
  53. * Gets the time (milliseconds) to take to spin up to the full idle rotation speed.
  54. */
  55. public get idleRotationSpinupTime() {
  56. return this._idleRotationSpinupTime;
  57. }
  58. /**
  59. * Gets a value indicating if the camera is currently rotating because of this behavior
  60. */
  61. public get rotationInProgress(): boolean {
  62. return Math.abs(this._cameraRotationSpeed) > 0;
  63. }
  64. // Default behavior functions
  65. private _onPrePointerObservableObserver: Nullable<Observer<PointerInfoPre>>;
  66. private _onAfterCheckInputsObserver: Nullable<Observer<Camera>>;
  67. private _attachedCamera: Nullable<ArcRotateCamera>;
  68. private _isPointerDown = false;
  69. private _lastFrameTime: Nullable<number> = null;
  70. private _lastInteractionTime = -Infinity;
  71. private _cameraRotationSpeed: number = 0;
  72. public attach(camera: ArcRotateCamera): void {
  73. this._attachedCamera = camera;
  74. let scene = this._attachedCamera.getScene();
  75. this._onPrePointerObservableObserver = scene.onPrePointerObservable.add((pointerInfoPre) => {
  76. if (pointerInfoPre.type === PointerEventTypes.POINTERDOWN) {
  77. this._isPointerDown = true;
  78. return
  79. }
  80. if (pointerInfoPre.type === PointerEventTypes.POINTERUP) {
  81. this._isPointerDown = false;
  82. }
  83. });
  84. this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(() => {
  85. let now = Tools.Now;
  86. let dt = 0;
  87. if (this._lastFrameTime != null) {
  88. dt = now - this._lastFrameTime;
  89. }
  90. this._lastFrameTime = now;
  91. // Stop the animation if there is user interaction and the animation should stop for this interaction
  92. this._applyUserInteraction();
  93. let timeToRotation = now - this._lastInteractionTime - this._idleRotationWaitTime;
  94. let scale = Math.max(Math.min(timeToRotation / (this._idleRotationSpinupTime), 1), 0);
  95. this._cameraRotationSpeed = this._idleRotationSpeed * scale;
  96. // Step camera rotation by rotation speed
  97. if (this._attachedCamera) {
  98. this._attachedCamera.alpha -= this._cameraRotationSpeed * (dt / 1000);
  99. }
  100. });
  101. }
  102. public detach(): void {
  103. if (!this._attachedCamera) {
  104. return;
  105. }
  106. let scene = this._attachedCamera.getScene();
  107. if (this._onPrePointerObservableObserver) {
  108. scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
  109. }
  110. this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
  111. this._attachedCamera = null;
  112. }
  113. /**
  114. * Returns true if user is scrolling.
  115. * @return true if user is scrolling.
  116. */
  117. private _userIsZooming(): boolean {
  118. if (!this._attachedCamera) {
  119. return false;
  120. }
  121. return this._attachedCamera.inertialRadiusOffset !== 0;
  122. }
  123. private _lastFrameRadius = 0;
  124. private _shouldAnimationStopForInteraction(): boolean {
  125. if (!this._attachedCamera) {
  126. return false;
  127. }
  128. var zoomHasHitLimit = false;
  129. if (this._lastFrameRadius === this._attachedCamera.radius && this._attachedCamera.inertialRadiusOffset !== 0) {
  130. zoomHasHitLimit = true;
  131. }
  132. // Update the record of previous radius - works as an approx. indicator of hitting radius limits
  133. this._lastFrameRadius = this._attachedCamera.radius;
  134. return this._zoomStopsAnimation ? zoomHasHitLimit : this._userIsZooming();
  135. }
  136. /**
  137. * Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
  138. */
  139. private _applyUserInteraction(): void {
  140. if (this._userIsMoving() && !this._shouldAnimationStopForInteraction()) {
  141. this._lastInteractionTime = Tools.Now;
  142. }
  143. }
  144. // Tools
  145. private _userIsMoving(): boolean {
  146. if (!this._attachedCamera) {
  147. return false;
  148. }
  149. return this._attachedCamera.inertialAlphaOffset !== 0 ||
  150. this._attachedCamera.inertialBetaOffset !== 0 ||
  151. this._attachedCamera.inertialRadiusOffset !== 0 ||
  152. this._attachedCamera.inertialPanningX !== 0 ||
  153. this._attachedCamera.inertialPanningY !== 0 ||
  154. this._isPointerDown;
  155. }
  156. }
  157. }