arcRotateCameraMouseWheelInput.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Nullable } from "../../types";
  2. import { serialize } from "../../Misc/decorators";
  3. import { EventState, Observer } from "../../Misc/observable";
  4. import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
  5. import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
  6. import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
  7. import { Scalar } from '../../Maths/math.scalar';
  8. import { Tools } from '../../Misc/tools';
  9. import { IWheelEvent } from "../../Events/deviceInputEvents";
  10. /**
  11. * Manage the mouse wheel inputs to control an arc rotate camera.
  12. * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
  13. */
  14. export class ArcRotateCameraMouseWheelInput implements ICameraInput<ArcRotateCamera> {
  15. /**
  16. * Defines the camera the input is attached to.
  17. */
  18. public camera: ArcRotateCamera;
  19. /**
  20. * Gets or Set the mouse wheel precision or how fast is the camera zooming.
  21. */
  22. @serialize()
  23. public wheelPrecision = 3.0;
  24. /**
  25. * wheelDeltaPercentage will be used instead of wheelPrecision if different from 0.
  26. * It defines the percentage of current camera.radius to use as delta when wheel is used.
  27. */
  28. @serialize()
  29. public wheelDeltaPercentage = 0;
  30. private _wheel: Nullable<(p: PointerInfo, s: EventState) => void>;
  31. private _observer: Nullable<Observer<PointerInfo>>;
  32. private computeDeltaFromMouseWheelLegacyEvent(mouseWheelDelta: number, radius: number) {
  33. var delta = 0;
  34. var wheelDelta = (mouseWheelDelta * 0.01 * this.wheelDeltaPercentage) * radius;
  35. if (mouseWheelDelta > 0) {
  36. delta = wheelDelta / (1.0 + this.wheelDeltaPercentage);
  37. } else {
  38. delta = wheelDelta * (1.0 + this.wheelDeltaPercentage);
  39. }
  40. return delta;
  41. }
  42. /**
  43. * Attach the input controls to a specific dom element to get the input from.
  44. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
  45. */
  46. public attachControl(noPreventDefault?: boolean): void {
  47. // was there a second variable defined?
  48. noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
  49. this._wheel = (p, s) => {
  50. //sanity check - this should be a PointerWheel event.
  51. if (p.type !== PointerEventTypes.POINTERWHEEL) { return; }
  52. var event = <IWheelEvent>p.event;
  53. var delta = 0;
  54. let mouseWheelLegacyEvent = event as any;
  55. let wheelDelta = 0;
  56. if (mouseWheelLegacyEvent.wheelDelta) {
  57. wheelDelta = mouseWheelLegacyEvent.wheelDelta;
  58. } else {
  59. wheelDelta = -(event.deltaY || event.detail) * 60;
  60. }
  61. if (this.wheelDeltaPercentage) {
  62. delta = this.computeDeltaFromMouseWheelLegacyEvent(wheelDelta, this.camera.radius);
  63. // If zooming in, estimate the target radius and use that to compute the delta for inertia
  64. // this will stop multiple scroll events zooming in from adding too much inertia
  65. if (delta > 0) {
  66. var estimatedTargetRadius = this.camera.radius;
  67. var targetInertia = this.camera.inertialRadiusOffset + delta;
  68. for (var i = 0; i < 20 && Math.abs(targetInertia) > 0.001; i++) {
  69. estimatedTargetRadius -= targetInertia;
  70. targetInertia *= this.camera.inertia;
  71. }
  72. estimatedTargetRadius = Scalar.Clamp(estimatedTargetRadius, 0, Number.MAX_VALUE);
  73. delta = this.computeDeltaFromMouseWheelLegacyEvent(wheelDelta, estimatedTargetRadius);
  74. }
  75. } else {
  76. delta = wheelDelta / (this.wheelPrecision * 40);
  77. }
  78. if (delta) {
  79. this.camera.inertialRadiusOffset += delta;
  80. }
  81. if (event.preventDefault) {
  82. if (!noPreventDefault) {
  83. event.preventDefault();
  84. }
  85. }
  86. };
  87. this._observer = this.camera.getScene().onPointerObservable.add(this._wheel, PointerEventTypes.POINTERWHEEL);
  88. }
  89. /**
  90. * Detach the current controls from the specified dom element.
  91. */
  92. public detachControl(): void;
  93. /**
  94. * Detach the current controls from the specified dom element.
  95. * @param ignored defines an ignored parameter kept for backward compatibility. If you want to define the source input element, you can set engine.inputElement before calling camera.attachControl
  96. */
  97. public detachControl(ignored?: any): void {
  98. if (this._observer) {
  99. this.camera.getScene().onPointerObservable.remove(this._observer);
  100. this._observer = null;
  101. this._wheel = null;
  102. }
  103. }
  104. /**
  105. * Gets the class name of the current input.
  106. * @returns the class name
  107. */
  108. public getClassName(): string {
  109. return "ArcRotateCameraMouseWheelInput";
  110. }
  111. /**
  112. * Get the friendly name associated with the input class.
  113. * @returns the input friendly name
  114. */
  115. public getSimpleName(): string {
  116. return "mousewheel";
  117. }
  118. }
  119. (<any>CameraInputTypes)["ArcRotateCameraMouseWheelInput"] = ArcRotateCameraMouseWheelInput;