"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const three_module = require("../../../../../../three@0.154.0/node_modules/three/build/three.module.js");
const controls = require("../features/controls.js");
const utilities = require("../utilities.js");
const Damper = require("./Damper.js");
/* @license
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const PAN_SENSITIVITY = 0.018;
const TAP_DISTANCE = 2;
const TAP_MS = 300;
const vector2 = new three_module.Vector2();
const vector3 = new three_module.Vector3();
const DEFAULT_OPTIONS = Object.freeze({
  minimumRadius: 0,
  maximumRadius: Infinity,
  minimumPolarAngle: Math.PI / 8,
  maximumPolarAngle: Math.PI - Math.PI / 8,
  minimumAzimuthalAngle: -Infinity,
  maximumAzimuthalAngle: Infinity,
  minimumFieldOfView: 10,
  maximumFieldOfView: 45,
  touchAction: "none"
});
const KEYBOARD_ORBIT_INCREMENT = Math.PI / 8;
const ZOOM_SENSITIVITY = 0.04;
const PAN_KEY_INCREMENT = 10;
const ChangeSource = {
  USER_INTERACTION: "user-interaction",
  NONE: "none",
  AUTOMATIC: "automatic"
};
class SmoothControls extends three_module.EventDispatcher {
  constructor(camera, element, scene) {
    super();
    this.camera = camera;
    this.element = element;
    this.scene = scene;
    this.orbitSensitivity = 1;
    this.inputSensitivity = 1;
    this.changeSource = ChangeSource.NONE;
    this._interactionEnabled = false;
    this._disableZoom = false;
    this.isUserPointing = false;
    this.enablePan = true;
    this.enableTap = true;
    this.panProjection = new three_module.Matrix3();
    this.panPerPixel = 0;
    this.spherical = new three_module.Spherical();
    this.goalSpherical = new three_module.Spherical();
    this.thetaDamper = new Damper.Damper();
    this.phiDamper = new Damper.Damper();
    this.radiusDamper = new Damper.Damper();
    this.logFov = Math.log(DEFAULT_OPTIONS.maximumFieldOfView);
    this.goalLogFov = this.logFov;
    this.fovDamper = new Damper.Damper();
    this.touchMode = null;
    this.pointers = [];
    this.startTime = 0;
    this.startPointerPosition = { clientX: 0, clientY: 0 };
    this.lastSeparation = 0;
    this.touchDecided = false;
    this.onContext = (event) => {
      if (this.enablePan) {
        event.preventDefault();
      } else {
        for (const pointer of this.pointers) {
          this.onPointerUp(new PointerEvent("pointercancel", Object.assign(Object.assign({}, this.startPointerPosition), { pointerId: pointer.id })));
        }
      }
    };
    this.touchModeZoom = (dx, dy) => {
      if (!this._disableZoom) {
        const touchDistance = this.twoTouchDistance(this.pointers[0], this.pointers[1]);
        const deltaZoom = ZOOM_SENSITIVITY * (this.lastSeparation - touchDistance) * 50 / this.scene.height;
        this.lastSeparation = touchDistance;
        this.userAdjustOrbit(0, 0, deltaZoom);
      }
      if (this.panPerPixel > 0) {
        this.movePan(dx, dy);
      }
    };
    this.disableScroll = (event) => {
      event.preventDefault();
    };
    this.touchModeRotate = (dx, dy) => {
      const { touchAction } = this._options;
      if (!this.touchDecided && touchAction !== "none") {
        this.touchDecided = true;
        const dxMag = Math.abs(dx);
        const dyMag = Math.abs(dy);
        if (this.changeSource === ChangeSource.USER_INTERACTION && (touchAction === "pan-y" && dyMag > dxMag || touchAction === "pan-x" && dxMag > dyMag)) {
          this.touchMode = null;
          return;
        } else {
          this.element.addEventListener("touchmove", this.disableScroll, { passive: false });
        }
      }
      this.handleSinglePointerMove(dx, dy);
    };
    this.onPointerDown = (event) => {
      if (this.pointers.length > 2) {
        return;
      }
      const { element: element2 } = this;
      if (this.pointers.length === 0) {
        element2.addEventListener("pointermove", this.onPointerMove);
        element2.addEventListener("pointerup", this.onPointerUp);
        this.touchMode = null;
        this.touchDecided = false;
        this.startPointerPosition.clientX = event.clientX;
        this.startPointerPosition.clientY = event.clientY;
        this.startTime = performance.now();
      }
      try {
        element2.setPointerCapture(event.pointerId);
      } catch (_a) {
      }
      this.pointers.push({ clientX: event.clientX, clientY: event.clientY, id: event.pointerId });
      this.isUserPointing = false;
      if (event.pointerType === "touch") {
        this.changeSource = event.altKey ? (
          // set by interact() in controls.ts
          ChangeSource.AUTOMATIC
        ) : ChangeSource.USER_INTERACTION;
        this.onTouchChange(event);
      } else {
        this.changeSource = ChangeSource.USER_INTERACTION;
        this.onMouseDown(event);
      }
      if (this.changeSource === ChangeSource.USER_INTERACTION) {
        this.dispatchEvent({ type: "user-interaction" });
      }
    };
    this.onPointerMove = (event) => {
      const pointer = this.pointers.find((pointer2) => pointer2.id === event.pointerId);
      if (pointer == null) {
        return;
      }
      if (event.pointerType === "mouse" && event.buttons === 0) {
        this.onPointerUp(event);
        return;
      }
      const numTouches = this.pointers.length;
      const dx = (event.clientX - pointer.clientX) / numTouches;
      const dy = (event.clientY - pointer.clientY) / numTouches;
      if (dx === 0 && dy === 0) {
        return;
      }
      pointer.clientX = event.clientX;
      pointer.clientY = event.clientY;
      if (event.pointerType === "touch") {
        this.changeSource = event.altKey ? (
          // set by interact() in controls.ts
          ChangeSource.AUTOMATIC
        ) : ChangeSource.USER_INTERACTION;
        if (this.touchMode !== null) {
          this.touchMode(dx, dy);
        }
      } else {
        this.changeSource = ChangeSource.USER_INTERACTION;
        if (this.panPerPixel > 0) {
          this.movePan(dx, dy);
        } else {
          this.handleSinglePointerMove(dx, dy);
        }
      }
    };
    this.onPointerUp = (event) => {
      const { element: element2 } = this;
      const index = this.pointers.findIndex((pointer) => pointer.id === event.pointerId);
      if (index !== -1) {
        this.pointers.splice(index, 1);
      }
      if (this.panPerPixel > 0 && !event.altKey) {
        this.resetRadius();
      }
      if (this.pointers.length === 0) {
        element2.removeEventListener("pointermove", this.onPointerMove);
        element2.removeEventListener("pointerup", this.onPointerUp);
        element2.removeEventListener("touchmove", this.disableScroll);
        if (this.enablePan && this.enableTap) {
          this.recenter(event);
        }
      } else if (this.touchMode !== null) {
        this.onTouchChange(event);
      }
      this.scene.element[controls.$panElement].style.opacity = 0;
      element2.style.cursor = "grab";
      this.panPerPixel = 0;
      if (this.isUserPointing) {
        this.dispatchEvent({ type: "pointer-change-end" });
      }
    };
    this.onWheel = (event) => {
      this.changeSource = ChangeSource.USER_INTERACTION;
      const deltaZoom = event.deltaY * (event.deltaMode == 1 ? 18 : 1) * ZOOM_SENSITIVITY / 30;
      this.userAdjustOrbit(0, 0, deltaZoom);
      event.preventDefault();
      this.dispatchEvent({ type: "user-interaction" });
    };
    this.onKeyDown = (event) => {
      const { changeSource } = this;
      this.changeSource = ChangeSource.USER_INTERACTION;
      const relevantKey = event.shiftKey && this.enablePan ? this.panKeyCodeHandler(event) : this.orbitZoomKeyCodeHandler(event);
      if (relevantKey) {
        event.preventDefault();
        this.dispatchEvent({ type: "user-interaction" });
      } else {
        this.changeSource = changeSource;
      }
    };
    this._options = Object.assign({}, DEFAULT_OPTIONS);
    this.setOrbit(0, Math.PI / 2, 1);
    this.setFieldOfView(100);
    this.jumpToGoal();
  }
  get interactionEnabled() {
    return this._interactionEnabled;
  }
  enableInteraction() {
    if (this._interactionEnabled === false) {
      const { element } = this;
      element.addEventListener("pointerdown", this.onPointerDown);
      element.addEventListener("pointercancel", this.onPointerUp);
      if (!this._disableZoom) {
        element.addEventListener("wheel", this.onWheel);
      }
      element.addEventListener("keydown", this.onKeyDown);
      element.addEventListener("touchmove", () => {
      }, { passive: false });
      element.addEventListener("contextmenu", this.onContext);
      this.element.style.cursor = "grab";
      this._interactionEnabled = true;
      this.updateTouchActionStyle();
    }
  }
  disableInteraction() {
    if (this._interactionEnabled === true) {
      const { element } = this;
      element.removeEventListener("pointerdown", this.onPointerDown);
      element.removeEventListener("pointermove", this.onPointerMove);
      element.removeEventListener("pointerup", this.onPointerUp);
      element.removeEventListener("pointercancel", this.onPointerUp);
      element.removeEventListener("wheel", this.onWheel);
      element.removeEventListener("keydown", this.onKeyDown);
      element.removeEventListener("contextmenu", this.onContext);
      element.style.cursor = "";
      this.touchMode = null;
      this._interactionEnabled = false;
      this.updateTouchActionStyle();
    }
  }
  /**
   * The options that are currently configured for the controls instance.
   */
  get options() {
    return this._options;
  }
  set disableZoom(disable) {
    if (this._disableZoom != disable) {
      this._disableZoom = disable;
      if (disable === true) {
        this.element.removeEventListener("wheel", this.onWheel);
      } else {
        this.element.addEventListener("wheel", this.onWheel);
      }
      this.updateTouchActionStyle();
    }
  }
  /**
   * Copy the spherical values that represent the current camera orbital
   * position relative to the configured target into a provided Spherical
   * instance. If no Spherical is provided, a new Spherical will be allocated
   * to copy the values into. The Spherical that values are copied into is
   * returned.
   */
  getCameraSpherical(target = new three_module.Spherical()) {
    return target.copy(this.spherical);
  }
  /**
   * Returns the camera's current vertical field of view in degrees.
   */
  getFieldOfView() {
    return this.camera.fov;
  }
  /**
   * Configure the _options of the controls. Configured _options will be
   * merged with whatever _options have already been configured for this
   * controls instance.
   */
  applyOptions(_options) {
    Object.assign(this._options, _options);
    this.setOrbit();
    this.setFieldOfView(Math.exp(this.goalLogFov));
  }
  /**
   * Sets the near and far planes of the camera.
   */
  updateNearFar(nearPlane, farPlane) {
    this.camera.far = farPlane === 0 ? 2 : farPlane;
    this.camera.near = Math.max(nearPlane, this.camera.far / 1e3);
    this.camera.updateProjectionMatrix();
  }
  /**
   * Sets the aspect ratio of the camera
   */
  updateAspect(aspect) {
    this.camera.aspect = aspect;
    this.camera.updateProjectionMatrix();
  }
  /**
   * Set the absolute orbital goal of the camera. The change will be
   * applied over a number of frames depending on configured acceleration and
   * dampening _options.
   *
   * Returns true if invoking the method will result in the camera changing
   * position and/or rotation, otherwise false.
   */
  setOrbit(goalTheta = this.goalSpherical.theta, goalPhi = this.goalSpherical.phi, goalRadius = this.goalSpherical.radius) {
    const { minimumAzimuthalAngle, maximumAzimuthalAngle, minimumPolarAngle, maximumPolarAngle, minimumRadius, maximumRadius } = this._options;
    const { theta, phi, radius } = this.goalSpherical;
    const nextTheta = utilities.clamp(goalTheta, minimumAzimuthalAngle, maximumAzimuthalAngle);
    if (!isFinite(minimumAzimuthalAngle) && !isFinite(maximumAzimuthalAngle)) {
      this.spherical.theta = this.wrapAngle(this.spherical.theta - nextTheta) + nextTheta;
    }
    const nextPhi = utilities.clamp(goalPhi, minimumPolarAngle, maximumPolarAngle);
    const nextRadius = utilities.clamp(goalRadius, minimumRadius, maximumRadius);
    if (nextTheta === theta && nextPhi === phi && nextRadius === radius) {
      return false;
    }
    if (!isFinite(nextTheta) || !isFinite(nextPhi) || !isFinite(nextRadius)) {
      return false;
    }
    this.goalSpherical.theta = nextTheta;
    this.goalSpherical.phi = nextPhi;
    this.goalSpherical.radius = nextRadius;
    this.goalSpherical.makeSafe();
    return true;
  }
  /**
   * Subset of setOrbit() above, which only sets the camera's radius.
   */
  setRadius(radius) {
    this.goalSpherical.radius = radius;
    this.setOrbit();
  }
  /**
   * Sets the goal field of view for the camera
   */
  setFieldOfView(fov) {
    const { minimumFieldOfView, maximumFieldOfView } = this._options;
    fov = utilities.clamp(fov, minimumFieldOfView, maximumFieldOfView);
    this.goalLogFov = Math.log(fov);
  }
  /**
   * Sets the smoothing decay time.
   */
  setDamperDecayTime(decayMilliseconds) {
    this.thetaDamper.setDecayTime(decayMilliseconds);
    this.phiDamper.setDecayTime(decayMilliseconds);
    this.radiusDamper.setDecayTime(decayMilliseconds);
    this.fovDamper.setDecayTime(decayMilliseconds);
  }
  /**
   * Adjust the orbital position of the camera relative to its current orbital
   * position. Does not let the theta goal get more than pi ahead of the current
   * theta, which ensures interpolation continues in the direction of the delta.
   * The deltaZoom parameter adjusts both the field of view and the orbit radius
   * such that they progress across their allowed ranges in sync.
   */
  adjustOrbit(deltaTheta, deltaPhi, deltaZoom) {
    const { theta, phi, radius } = this.goalSpherical;
    const { minimumRadius, maximumRadius, minimumFieldOfView, maximumFieldOfView } = this._options;
    const dTheta = this.spherical.theta - theta;
    const dThetaLimit = Math.PI - 1e-3;
    const goalTheta = theta - utilities.clamp(deltaTheta, -dThetaLimit - dTheta, dThetaLimit - dTheta);
    const goalPhi = phi - deltaPhi;
    const deltaRatio = deltaZoom === 0 ? 0 : ((deltaZoom > 0 ? maximumRadius : minimumRadius) - radius) / (Math.log(deltaZoom > 0 ? maximumFieldOfView : minimumFieldOfView) - this.goalLogFov);
    const goalRadius = radius + deltaZoom * (isFinite(deltaRatio) ? deltaRatio : (maximumRadius - minimumRadius) * 2);
    this.setOrbit(goalTheta, goalPhi, goalRadius);
    if (deltaZoom !== 0) {
      const goalLogFov = this.goalLogFov + deltaZoom;
      this.setFieldOfView(Math.exp(goalLogFov));
    }
  }
  /**
   * Move the camera instantly instead of accelerating toward the goal
   * parameters.
   */
  jumpToGoal() {
    this.update(0, Damper.SETTLING_TIME);
  }
  /**
   * Update controls. In most cases, this will result in the camera
   * interpolating its position and rotation until it lines up with the
   * designated goal orbital position. Returns false if the camera did not move.
   *
   * Time and delta are measured in milliseconds.
   */
  update(_time, delta) {
    if (this.isStationary()) {
      return false;
    }
    const { maximumPolarAngle, maximumRadius } = this._options;
    const dTheta = this.spherical.theta - this.goalSpherical.theta;
    if (Math.abs(dTheta) > Math.PI && !isFinite(this._options.minimumAzimuthalAngle) && !isFinite(this._options.maximumAzimuthalAngle)) {
      this.spherical.theta -= Math.sign(dTheta) * 2 * Math.PI;
    }
    this.spherical.theta = this.thetaDamper.update(this.spherical.theta, this.goalSpherical.theta, delta, Math.PI);
    this.spherical.phi = this.phiDamper.update(this.spherical.phi, this.goalSpherical.phi, delta, maximumPolarAngle);
    this.spherical.radius = this.radiusDamper.update(this.spherical.radius, this.goalSpherical.radius, delta, maximumRadius);
    this.logFov = this.fovDamper.update(this.logFov, this.goalLogFov, delta, 1);
    this.moveCamera();
    return true;
  }
  updateTouchActionStyle() {
    const { style } = this.element;
    if (this._interactionEnabled) {
      const { touchAction } = this._options;
      if (this._disableZoom && touchAction !== "none") {
        style.touchAction = "manipulation";
      } else {
        style.touchAction = touchAction;
      }
    } else {
      style.touchAction = "";
    }
  }
  isStationary() {
    return this.goalSpherical.theta === this.spherical.theta && this.goalSpherical.phi === this.spherical.phi && this.goalSpherical.radius === this.spherical.radius && this.goalLogFov === this.logFov;
  }
  moveCamera() {
    this.spherical.makeSafe();
    this.camera.position.setFromSpherical(this.spherical);
    this.camera.setRotationFromEuler(new three_module.Euler(this.spherical.phi - Math.PI / 2, this.spherical.theta, 0, "YXZ"));
    if (this.camera.fov !== Math.exp(this.logFov)) {
      this.camera.fov = Math.exp(this.logFov);
      this.camera.updateProjectionMatrix();
    }
  }
  userAdjustOrbit(deltaTheta, deltaPhi, deltaZoom) {
    this.adjustOrbit(deltaTheta * this.orbitSensitivity * this.inputSensitivity, deltaPhi * this.orbitSensitivity * this.inputSensitivity, deltaZoom * this.inputSensitivity);
  }
  // Wraps to between -pi and pi
  wrapAngle(radians) {
    const normalized = (radians + Math.PI) / (2 * Math.PI);
    const wrapped = normalized - Math.floor(normalized);
    return wrapped * 2 * Math.PI - Math.PI;
  }
  pixelLengthToSphericalAngle(pixelLength) {
    return 2 * Math.PI * pixelLength / this.scene.height;
  }
  twoTouchDistance(touchOne, touchTwo) {
    const { clientX: xOne, clientY: yOne } = touchOne;
    const { clientX: xTwo, clientY: yTwo } = touchTwo;
    const xDelta = xTwo - xOne;
    const yDelta = yTwo - yOne;
    return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
  }
  handleSinglePointerMove(dx, dy) {
    const deltaTheta = this.pixelLengthToSphericalAngle(dx);
    const deltaPhi = this.pixelLengthToSphericalAngle(dy);
    if (this.isUserPointing === false) {
      this.isUserPointing = true;
      this.dispatchEvent({ type: "pointer-change-start" });
    }
    this.userAdjustOrbit(deltaTheta, deltaPhi, 0);
  }
  initializePan() {
    const { theta, phi } = this.spherical;
    const psi = theta - this.scene.yaw;
    this.panPerPixel = PAN_SENSITIVITY / this.scene.height;
    this.panProjection.set(-Math.cos(psi), -Math.cos(phi) * Math.sin(psi), 0, 0, Math.sin(phi), 0, Math.sin(psi), -Math.cos(phi) * Math.cos(psi), 0);
  }
  movePan(dx, dy) {
    const { scene } = this;
    const dxy = vector3.set(dx, dy, 0).multiplyScalar(this.inputSensitivity);
    const metersPerPixel = this.spherical.radius * Math.exp(this.logFov) * this.panPerPixel;
    dxy.multiplyScalar(metersPerPixel);
    const target = scene.getTarget();
    target.add(dxy.applyMatrix3(this.panProjection));
    scene.boundingSphere.clampPoint(target, target);
    scene.setTarget(target.x, target.y, target.z);
  }
  recenter(pointer) {
    if (performance.now() > this.startTime + TAP_MS || Math.abs(pointer.clientX - this.startPointerPosition.clientX) > TAP_DISTANCE || Math.abs(pointer.clientY - this.startPointerPosition.clientY) > TAP_DISTANCE) {
      return;
    }
    const { scene } = this;
    const hit = scene.positionAndNormalFromPoint(scene.getNDC(pointer.clientX, pointer.clientY));
    if (hit == null) {
      const { cameraTarget } = scene.element;
      scene.element.cameraTarget = "";
      scene.element.cameraTarget = cameraTarget;
      this.userAdjustOrbit(0, 0, 1);
    } else {
      scene.target.worldToLocal(hit.position);
      scene.setTarget(hit.position.x, hit.position.y, hit.position.z);
    }
  }
  resetRadius() {
    const { scene } = this;
    const hit = scene.positionAndNormalFromPoint(vector2.set(0, 0));
    if (hit == null) {
      return;
    }
    scene.target.worldToLocal(hit.position);
    const goalTarget = scene.getTarget();
    const { theta, phi } = this.spherical;
    const psi = theta - scene.yaw;
    const n = vector3.set(Math.sin(phi) * Math.sin(psi), Math.cos(phi), Math.sin(phi) * Math.cos(psi));
    const dr = n.dot(hit.position.sub(goalTarget));
    goalTarget.add(n.multiplyScalar(dr));
    scene.setTarget(goalTarget.x, goalTarget.y, goalTarget.z);
    this.setOrbit(void 0, void 0, this.goalSpherical.radius - dr);
  }
  onTouchChange(event) {
    if (this.pointers.length === 1) {
      this.touchMode = this.touchModeRotate;
    } else {
      if (this._disableZoom) {
        this.touchMode = null;
        this.element.removeEventListener("touchmove", this.disableScroll);
        return;
      }
      this.touchMode = this.touchDecided && this.touchMode === null ? null : this.touchModeZoom;
      this.touchDecided = true;
      this.element.addEventListener("touchmove", this.disableScroll, { passive: false });
      this.lastSeparation = this.twoTouchDistance(this.pointers[0], this.pointers[1]);
      if (this.enablePan && this.touchMode != null) {
        this.initializePan();
        if (!event.altKey) {
          this.scene.element[controls.$panElement].style.opacity = 1;
        }
      }
    }
  }
  onMouseDown(event) {
    this.panPerPixel = 0;
    if (this.enablePan && (event.button === 2 || event.ctrlKey || event.metaKey || event.shiftKey)) {
      this.initializePan();
      this.scene.element[controls.$panElement].style.opacity = 1;
    }
    this.element.style.cursor = "grabbing";
  }
  /**
   * Handles the orbit and Zoom key presses
   * Uses constants for the increment.
   * @param event The keyboard event for the .key value
   * @returns boolean to indicate if the key event has been handled
   */
  orbitZoomKeyCodeHandler(event) {
    let relevantKey = true;
    switch (event.key) {
      case "PageUp":
        this.userAdjustOrbit(0, 0, ZOOM_SENSITIVITY);
        break;
      case "PageDown":
        this.userAdjustOrbit(0, 0, -1 * ZOOM_SENSITIVITY);
        break;
      case "ArrowUp":
        this.userAdjustOrbit(0, -KEYBOARD_ORBIT_INCREMENT, 0);
        break;
      case "ArrowDown":
        this.userAdjustOrbit(0, KEYBOARD_ORBIT_INCREMENT, 0);
        break;
      case "ArrowLeft":
        this.userAdjustOrbit(-KEYBOARD_ORBIT_INCREMENT, 0, 0);
        break;
      case "ArrowRight":
        this.userAdjustOrbit(KEYBOARD_ORBIT_INCREMENT, 0, 0);
        break;
      default:
        relevantKey = false;
        break;
    }
    return relevantKey;
  }
  /**
   * Handles the Pan key presses
   * Uses constants for the increment.
   * @param event The keyboard event for the .key value
   * @returns boolean to indicate if the key event has been handled
   */
  panKeyCodeHandler(event) {
    this.initializePan();
    let relevantKey = true;
    switch (event.key) {
      case "ArrowUp":
        this.movePan(0, -1 * PAN_KEY_INCREMENT);
        break;
      case "ArrowDown":
        this.movePan(0, PAN_KEY_INCREMENT);
        break;
      case "ArrowLeft":
        this.movePan(-1 * PAN_KEY_INCREMENT, 0);
        break;
      case "ArrowRight":
        this.movePan(PAN_KEY_INCREMENT, 0);
        break;
      default:
        relevantKey = false;
        break;
    }
    return relevantKey;
  }
}
exports.ChangeSource = ChangeSource;
exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
exports.SmoothControls = SmoothControls;
//# sourceMappingURL=SmoothControls.js.map
