@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
228 lines • 10.8 kB
JavaScript
import { __decorate } from "../../tslib.es6.js";
import { serialize } from "../../Misc/decorators.js";
import { CameraInputTypes } from "../../Cameras/cameraInputsManager.js";
import { OrbitCameraPointersInput } from "../../Cameras/Inputs/orbitCameraPointersInput.js";
/**
* Manage the pointers inputs to control an arc rotate camera.
* Uses the inputMap on the movement class to determine which button maps to which interaction.
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
*/
export class ArcRotateCameraPointersInput extends OrbitCameraPointersInput {
constructor() {
super(...arguments);
/**
* Defines the buttons associated with the input to handle camera move.
*/
this.buttons = [0, 1, 2];
/**
* Defines the pointer angular sensibility along the X axis or how fast is
* the camera rotating.
*/
this.angularSensibilityX = 1000.0;
/**
* Defines the pointer angular sensibility along the Y axis or how fast is
* the camera rotating.
*/
this.angularSensibilityY = 1000.0;
/**
* Defines the pointer pinch precision or how fast is the camera zooming.
*/
this.pinchPrecision = 12.0;
/**
* pinchDeltaPercentage will be used instead of pinchPrecision if different
* from 0.
* It defines the percentage of current camera.radius to use as delta when
* pinch zoom is used.
*/
this.pinchDeltaPercentage = 0;
/**
* When useNaturalPinchZoom is true, multi touch zoom will zoom in such
* that any object in the plane at the camera's target point will scale
* perfectly with finger motion.
* Overrides pinchDeltaPercentage and pinchPrecision.
*/
this.useNaturalPinchZoom = false;
/**
* Defines the pointer panning sensibility or how fast is the camera moving.
*/
this.panningSensibility = 1000.0;
/**
* Revers pinch action direction.
*/
this.pinchInwards = true;
/** Cached resolved inputMap entry for the current pointer gesture */
this._activeEntry = null;
/** Cached conditions object for pointer-lock fallback resolution to avoid per-event allocations */
this._pointerLockConditions = { button: 0, modifiers: {} };
/**
* Modifier state stored separately from `_pointerConditions` so it can be typed as a
* concrete (non-optional) object. This avoids non-null assertions when updating modifier
* fields on every pointer-down, and the conditions object holds the same reference so
* resolveInteraction sees the live state.
*/
this._pointerModifiers = { ctrl: false, alt: false, shift: false };
/** Cached conditions object for pointer-down resolution */
this._pointerConditions = { modifiers: this._pointerModifiers };
}
/**
* Gets the class name of the current input.
* @returns the class name
*/
getClassName() {
return "ArcRotateCameraPointersInput";
}
/**
* Move camera from multi touch panning positions.
* @param previousMultiTouchPanPosition
* @param multiTouchPanPosition
*/
_computeMultiTouchPanning(previousMultiTouchPanPosition, multiTouchPanPosition) {
if (previousMultiTouchPanPosition && multiTouchPanPosition) {
const moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x;
const moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
// Multi-touch pan is a gesture (no button), so consult the default pointer→pan entry for an
// explicit `sensitivity` override. When unset, fall back to the legacy `panningSensibility`
// (treating panningSensibility=0 as "panning disabled" for backward compatibility).
const panEntry = this.camera.movement.input.getEntry("pointer", "pan");
const panScale = panEntry?.sensitivity ?? (this.panningSensibility !== 0 ? 1 / this.panningSensibility : 0);
if (panScale !== 0) {
this.camera.movement.activeInput = true;
this.camera.movement.panAccumulatedPixels.x += -moveDeltaX * panScale;
this.camera.movement.panAccumulatedPixels.y += moveDeltaY * panScale;
}
}
}
/**
* Move camera from multitouch (pinch) zoom distances.
* @param previousPinchSquaredDistance
* @param pinchSquaredDistance
*/
_computePinchZoom(previousPinchSquaredDistance, pinchSquaredDistance) {
const radius = this.camera.radius || ArcRotateCameraPointersInput.MinimumRadiusForPinch;
if (this.useNaturalPinchZoom) {
this.camera.radius = (radius * Math.sqrt(previousPinchSquaredDistance)) / Math.sqrt(pinchSquaredDistance);
}
else if (this.pinchDeltaPercentage) {
const delta = (pinchSquaredDistance - previousPinchSquaredDistance) * 0.001 * radius * this.pinchDeltaPercentage;
this.camera.movement.activeInput = true;
this.camera.movement.zoomAccumulatedPixels += delta;
}
else {
const delta = (pinchSquaredDistance - previousPinchSquaredDistance) /
((this.pinchPrecision * (this.pinchInwards ? 1 : -1) * (this.angularSensibilityX + this.angularSensibilityY)) / 2);
this.camera.movement.activeInput = true;
this.camera.movement.zoomAccumulatedPixels += delta;
}
}
/**
* Called on pointer POINTERMOVE event if only a single touch is active.
* @param point current touch point
* @param offsetX offset on X
* @param offsetY offset on Y
*/
onTouch(point, offsetX, offsetY) {
// In pointer-lock mode, mouse movement rotates the camera even without a button held.
// This matches legacy behavior where pointer-lock mouse deltas always drove rotation.
const entry = this._activeEntry ?? (this.camera.getEngine().isPointerLock ? this.camera.movement.input.resolveInteraction("pointer", this._pointerLockConditions) : null);
if (entry) {
// Per-pixel scale. The inputMap entry's `sensitivity` takes precedence so consumers can
// tune feel declaratively (and so we can phase out the legacy sensibility properties).
// When `sensitivity` is unset, fall back to the legacy properties for backward compat.
// For rotate, a single `sensitivity` value applies to both axes; the legacy fallback
// preserves separate X/Y tuning via `angularSensibilityX/Y`.
if (entry.interaction === "pan") {
const panScale = entry.sensitivity ?? (this.panningSensibility !== 0 ? 1 / this.panningSensibility : 0);
if (panScale !== 0) {
this.camera.movement.activeInput = true;
this.camera.movement.panAccumulatedPixels.x += -offsetX * panScale;
this.camera.movement.panAccumulatedPixels.y += offsetY * panScale;
}
}
else if (entry.interaction === "rotate") {
const rotateScaleX = entry.sensitivityX ?? entry.sensitivity ?? 1 / this.angularSensibilityX;
const rotateScaleY = entry.sensitivityY ?? entry.sensitivity ?? 1 / this.angularSensibilityY;
this.camera.movement.activeInput = true;
this.camera.movement.rotationAccumulatedPixels.x += -offsetX * rotateScaleX;
this.camera.movement.rotationAccumulatedPixels.y += -offsetY * rotateScaleY;
}
}
}
/**
* Called on pointer POINTERDOUBLETAP event.
*/
onDoubleTap() {
if (this.camera.useInputToRestoreState) {
this.camera.restoreState();
}
}
/**
* Called on pointer POINTERMOVE event if multiple touches are active.
* @param pointA point A
* @param pointB point B
* @param previousPinchSquaredDistance distance between points in previous pinch
* @param pinchSquaredDistance distance between points in current pinch
* @param previousMultiTouchPanPosition multi-touch position in previous step
* @param multiTouchPanPosition multi-touch position in current step
*/
onMultiTouch(pointA, pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition) {
this._shouldStartPinchZoom =
this._twoFingerActivityCount < 20 && Math.abs(Math.sqrt(pinchSquaredDistance) - Math.sqrt(previousPinchSquaredDistance)) > this.camera.pinchToPanMaxDistance;
super.onMultiTouch(pointA, pointB, previousPinchSquaredDistance, pinchSquaredDistance, previousMultiTouchPanPosition, multiTouchPanPosition);
}
/**
* Called each time a new POINTERDOWN event occurs. Ie, for each button
* press.
* @param evt Defines the event to track
*/
onButtonDown(evt) {
this._pointerConditions.button = evt.button;
this._pointerModifiers.ctrl = evt.ctrlKey;
this._pointerModifiers.alt = evt.altKey;
this._pointerModifiers.shift = evt.shiftKey;
this._activeEntry = this.camera.movement.input.resolveInteraction("pointer", this._pointerConditions);
super.onButtonDown(evt);
}
/**
* Called each time a new POINTERUP event occurs. Ie, for each button
* release.
* @param _evt Defines the event to track
*/
onButtonUp(_evt) {
this._activeEntry = null;
super.onButtonUp(_evt);
}
/**
* Called when window becomes inactive.
*/
onLostFocus() {
this._activeEntry = null;
super.onLostFocus();
}
}
/**
* The minimum radius used for pinch, to avoid radius lock at 0
*/
ArcRotateCameraPointersInput.MinimumRadiusForPinch = 0.001;
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "buttons", void 0);
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "angularSensibilityX", void 0);
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "angularSensibilityY", void 0);
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "pinchPrecision", void 0);
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "pinchDeltaPercentage", void 0);
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "useNaturalPinchZoom", void 0);
__decorate([
serialize()
], ArcRotateCameraPointersInput.prototype, "panningSensibility", void 0);
CameraInputTypes["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;
//# sourceMappingURL=arcRotateCameraPointersInput.js.map