|
@@ -1,35 +1,41 @@
|
|
|
import { Nullable } from "../../types";
|
|
|
import { serialize } from "../../Misc/decorators";
|
|
|
-import { EventState, Observer } from "../../Misc/observable";
|
|
|
-import { Tools } from "../../Misc/tools";
|
|
|
import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
|
|
|
-import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
|
|
|
-import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
|
|
|
+import { CameraInputTypes } from "../../Cameras/cameraInputsManager";
|
|
|
+import { BaseCameraPointersInput } from "../../Cameras/Inputs/BaseCameraPointersInput";
|
|
|
+import { PointerTouch } from "../../Events/pointerEvents";
|
|
|
|
|
|
/**
|
|
|
* Manage the pointers inputs to control an arc rotate camera.
|
|
|
* @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
|
|
|
*/
|
|
|
-export class ArcRotateCameraPointersInput implements ICameraInput<ArcRotateCamera> {
|
|
|
+export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
|
|
|
/**
|
|
|
* Defines the camera the input is attached to.
|
|
|
*/
|
|
|
public camera: ArcRotateCamera;
|
|
|
|
|
|
/**
|
|
|
+ * The class name of the current input.
|
|
|
+ */
|
|
|
+ protected _className = "ArcRotateCameraPointersInput";
|
|
|
+
|
|
|
+ /**
|
|
|
* Defines the buttons associated with the input to handle camera move.
|
|
|
*/
|
|
|
@serialize()
|
|
|
public buttons = [0, 1, 2];
|
|
|
|
|
|
/**
|
|
|
- * Defines the pointer angular sensibility along the X axis or how fast is the camera rotating.
|
|
|
+ * Defines the pointer angular sensibility along the X axis or how fast is
|
|
|
+ * the camera rotating.
|
|
|
*/
|
|
|
@serialize()
|
|
|
public angularSensibilityX = 1000.0;
|
|
|
|
|
|
/**
|
|
|
- * Defines the pointer angular sensibility along the Y axis or how fast is the camera rotating.
|
|
|
+ * Defines the pointer angular sensibility along the Y axis or how fast is
|
|
|
+ * the camera rotating.
|
|
|
*/
|
|
|
@serialize()
|
|
|
public angularSensibilityY = 1000.0;
|
|
@@ -41,8 +47,10 @@ export class ArcRotateCameraPointersInput implements ICameraInput<ArcRotateCamer
|
|
|
public 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.
|
|
|
+ * 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.
|
|
|
*/
|
|
|
@serialize()
|
|
|
public pinchDeltaPercentage = 0;
|
|
@@ -60,7 +68,8 @@ export class ArcRotateCameraPointersInput implements ICameraInput<ArcRotateCamer
|
|
|
public multiTouchPanning: boolean = true;
|
|
|
|
|
|
/**
|
|
|
- * Defines whether panning is enabled for both pan (2 fingers swipe) and zoom (pinch) through multitouch.
|
|
|
+ * Defines whether panning is enabled for both pan (2 fingers swipe) and
|
|
|
+ * zoom (pinch) through multitouch.
|
|
|
*/
|
|
|
@serialize()
|
|
|
public multiTouchPanAndZoom: boolean = true;
|
|
@@ -71,351 +80,138 @@ export class ArcRotateCameraPointersInput implements ICameraInput<ArcRotateCamer
|
|
|
public pinchInwards = true;
|
|
|
|
|
|
private _isPanClick: boolean = false;
|
|
|
- private _pointerInput: (p: PointerInfo, s: EventState) => void;
|
|
|
- private _observer: Nullable<Observer<PointerInfo>>;
|
|
|
- private _onMouseMove: Nullable<(e: MouseEvent) => any>;
|
|
|
- private _onGestureStart: Nullable<(e: PointerEvent) => void>;
|
|
|
- private _onGesture: Nullable<(e: MSGestureEvent) => void>;
|
|
|
- private _MSGestureHandler: Nullable<MSGesture>;
|
|
|
- private _onLostFocus: Nullable<(e: FocusEvent) => any>;
|
|
|
- private _onContextMenu: Nullable<(e: Event) => void>;
|
|
|
+ private _twoFingerActivityCount: number = 0;
|
|
|
+ private _isPinching: boolean = false;
|
|
|
|
|
|
/**
|
|
|
- * Attach the input controls to a specific dom element to get the input from.
|
|
|
- * @param element Defines the element the controls should be listened from
|
|
|
- * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
|
|
|
+ * Called on pointer POINTERMOVE event if only a single touch is active.
|
|
|
*/
|
|
|
- public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
|
|
|
- var engine = this.camera.getEngine();
|
|
|
- var cacheSoloPointer: Nullable<{ x: number, y: number, pointerId: number, type: any }>; // cache pointer object for better perf on camera rotation
|
|
|
- var pointA: Nullable<{ x: number, y: number, pointerId: number, type: any }> = null;
|
|
|
- var pointB: Nullable<{ x: number, y: number, pointerId: number, type: any }> = null;
|
|
|
- var previousPinchSquaredDistance = 0;
|
|
|
- var initialDistance = 0;
|
|
|
- var twoFingerActivityCount = 0;
|
|
|
- var previousMultiTouchPanPosition: { x: number, y: number, isPaning: boolean, isPinching: boolean } = { x: 0, y: 0, isPaning: false, isPinching: false };
|
|
|
-
|
|
|
- this._pointerInput = (p, s) => {
|
|
|
- var evt = <PointerEvent>p.event;
|
|
|
- let isTouch = (<any>p.event).pointerType === "touch";
|
|
|
-
|
|
|
- if (engine.isInVRExclusivePointerMode) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (p.type !== PointerEventTypes.POINTERMOVE && this.buttons.indexOf(evt.button) === -1) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let srcElement = <HTMLElement>(evt.srcElement || evt.target);
|
|
|
-
|
|
|
- if (p.type === PointerEventTypes.POINTERDOWN && srcElement) {
|
|
|
- try {
|
|
|
- srcElement.setPointerCapture(evt.pointerId);
|
|
|
- } catch (e) {
|
|
|
- //Nothing to do with the error. Execution will continue.
|
|
|
- }
|
|
|
-
|
|
|
- // Manage panning with pan button click
|
|
|
- this._isPanClick = evt.button === this.camera._panningMouseButton;
|
|
|
-
|
|
|
- // manage pointers
|
|
|
- cacheSoloPointer = { x: evt.clientX, y: evt.clientY, pointerId: evt.pointerId, type: evt.pointerType };
|
|
|
- if (pointA === null) {
|
|
|
- pointA = cacheSoloPointer;
|
|
|
- }
|
|
|
- else if (pointB === null) {
|
|
|
- pointB = cacheSoloPointer;
|
|
|
- }
|
|
|
- if (!noPreventDefault) {
|
|
|
- evt.preventDefault();
|
|
|
- element.focus();
|
|
|
- }
|
|
|
- }
|
|
|
- else if (p.type === PointerEventTypes.POINTERDOUBLETAP) {
|
|
|
- if (this.camera.useInputToRestoreState) {
|
|
|
- this.camera.restoreState();
|
|
|
- }
|
|
|
- }
|
|
|
- else if (p.type === PointerEventTypes.POINTERUP && srcElement) {
|
|
|
- try {
|
|
|
- srcElement.releasePointerCapture(evt.pointerId);
|
|
|
- } catch (e) {
|
|
|
- //Nothing to do with the error.
|
|
|
- }
|
|
|
-
|
|
|
- cacheSoloPointer = null;
|
|
|
- previousPinchSquaredDistance = 0;
|
|
|
- previousMultiTouchPanPosition.isPaning = false;
|
|
|
- previousMultiTouchPanPosition.isPinching = false;
|
|
|
- twoFingerActivityCount = 0;
|
|
|
- initialDistance = 0;
|
|
|
-
|
|
|
- if (!isTouch) {
|
|
|
- pointB = null; // Mouse and pen are mono pointer
|
|
|
- }
|
|
|
-
|
|
|
- //would be better to use pointers.remove(evt.pointerId) for multitouch gestures,
|
|
|
- //but emptying completly pointers collection is required to fix a bug on iPhone :
|
|
|
- //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers
|
|
|
- //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
|
|
|
- if (engine._badOS) {
|
|
|
- pointA = pointB = null;
|
|
|
- }
|
|
|
- else {
|
|
|
- //only remove the impacted pointer in case of multitouch allowing on most
|
|
|
- //platforms switching from rotate to zoom and pan seamlessly.
|
|
|
- if (pointB && pointA && pointA.pointerId == evt.pointerId) {
|
|
|
- pointA = pointB;
|
|
|
- pointB = null;
|
|
|
- cacheSoloPointer = { x: pointA.x, y: pointA.y, pointerId: pointA.pointerId, type: evt.pointerType };
|
|
|
- }
|
|
|
- else if (pointA && pointB && pointB.pointerId == evt.pointerId) {
|
|
|
- pointB = null;
|
|
|
- cacheSoloPointer = { x: pointA.x, y: pointA.y, pointerId: pointA.pointerId, type: evt.pointerType };
|
|
|
- }
|
|
|
- else {
|
|
|
- pointA = pointB = null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!noPreventDefault) {
|
|
|
- evt.preventDefault();
|
|
|
- }
|
|
|
- } else if (p.type === PointerEventTypes.POINTERMOVE) {
|
|
|
- if (!noPreventDefault) {
|
|
|
- evt.preventDefault();
|
|
|
- }
|
|
|
-
|
|
|
- // One button down
|
|
|
- if (pointA && pointB === null && cacheSoloPointer) {
|
|
|
- if (this.panningSensibility !== 0 &&
|
|
|
- ((evt.ctrlKey && this.camera._useCtrlForPanning) || this._isPanClick)) {
|
|
|
- this.camera.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / this.panningSensibility;
|
|
|
- this.camera.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / this.panningSensibility;
|
|
|
- } else {
|
|
|
- var offsetX = evt.clientX - cacheSoloPointer.x;
|
|
|
- var offsetY = evt.clientY - cacheSoloPointer.y;
|
|
|
- this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
|
|
|
- this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
|
|
|
- }
|
|
|
-
|
|
|
- cacheSoloPointer.x = evt.clientX;
|
|
|
- cacheSoloPointer.y = evt.clientY;
|
|
|
- }
|
|
|
-
|
|
|
- // Two buttons down: pinch/pan
|
|
|
- else if (pointA && pointB) {
|
|
|
- //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be useful to force preventDefault to avoid html page scroll/zoom in some mobile browsers
|
|
|
- var ed = (pointA.pointerId === evt.pointerId) ? pointA : pointB;
|
|
|
- ed.x = evt.clientX;
|
|
|
- ed.y = evt.clientY;
|
|
|
- var direction = this.pinchInwards ? 1 : -1;
|
|
|
- var distX = pointA.x - pointB.x;
|
|
|
- var distY = pointA.y - pointB.y;
|
|
|
- var pinchSquaredDistance = (distX * distX) + (distY * distY);
|
|
|
- var pinchDistance = Math.sqrt(pinchSquaredDistance);
|
|
|
-
|
|
|
- if (previousPinchSquaredDistance === 0) {
|
|
|
- initialDistance = pinchDistance;
|
|
|
- previousPinchSquaredDistance = pinchSquaredDistance;
|
|
|
- previousMultiTouchPanPosition.x = (pointA.x + pointB.x) / 2;
|
|
|
- previousMultiTouchPanPosition.y = (pointA.y + pointB.y) / 2;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (this.multiTouchPanAndZoom) {
|
|
|
- if (this.pinchDeltaPercentage) {
|
|
|
- this.camera.inertialRadiusOffset += ((pinchSquaredDistance - previousPinchSquaredDistance) * 0.001) * this.camera.radius * this.pinchDeltaPercentage;
|
|
|
- } else {
|
|
|
- this.camera.inertialRadiusOffset += (pinchSquaredDistance - previousPinchSquaredDistance) /
|
|
|
- (this.pinchPrecision *
|
|
|
- ((this.angularSensibilityX + this.angularSensibilityY) / 2) *
|
|
|
- direction);
|
|
|
- }
|
|
|
-
|
|
|
- if (this.panningSensibility !== 0) {
|
|
|
- var pointersCenterX = (pointA.x + pointB.x) / 2;
|
|
|
- var pointersCenterY = (pointA.y + pointB.y) / 2;
|
|
|
- var pointersCenterDistX = pointersCenterX - previousMultiTouchPanPosition.x;
|
|
|
- var pointersCenterDistY = pointersCenterY - previousMultiTouchPanPosition.y;
|
|
|
-
|
|
|
- previousMultiTouchPanPosition.x = pointersCenterX;
|
|
|
- previousMultiTouchPanPosition.y = pointersCenterY;
|
|
|
-
|
|
|
- this.camera.inertialPanningX += -(pointersCenterDistX) / (this.panningSensibility);
|
|
|
- this.camera.inertialPanningY += (pointersCenterDistY) / (this.panningSensibility);
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- twoFingerActivityCount++;
|
|
|
-
|
|
|
- if (previousMultiTouchPanPosition.isPinching || (twoFingerActivityCount < 20 && Math.abs(pinchDistance - initialDistance) > this.camera.pinchToPanMaxDistance)) {
|
|
|
- if (this.pinchDeltaPercentage) {
|
|
|
- this.camera.inertialRadiusOffset += ((pinchSquaredDistance - previousPinchSquaredDistance) * 0.001) * this.camera.radius * this.pinchDeltaPercentage;
|
|
|
- } else {
|
|
|
- this.camera.inertialRadiusOffset += (pinchSquaredDistance - previousPinchSquaredDistance) /
|
|
|
- (this.pinchPrecision *
|
|
|
- ((this.angularSensibilityX + this.angularSensibilityY) / 2) *
|
|
|
- direction);
|
|
|
- }
|
|
|
- previousMultiTouchPanPosition.isPaning = false;
|
|
|
- previousMultiTouchPanPosition.isPinching = true;
|
|
|
- }
|
|
|
- else {
|
|
|
- if (cacheSoloPointer && cacheSoloPointer.pointerId === ed.pointerId && this.panningSensibility !== 0 && this.multiTouchPanning) {
|
|
|
- if (!previousMultiTouchPanPosition.isPaning) {
|
|
|
- previousMultiTouchPanPosition.isPaning = true;
|
|
|
- previousMultiTouchPanPosition.isPinching = false;
|
|
|
- previousMultiTouchPanPosition.x = ed.x;
|
|
|
- previousMultiTouchPanPosition.y = ed.y;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this.camera.inertialPanningX += -(ed.x - previousMultiTouchPanPosition.x) / (this.panningSensibility);
|
|
|
- this.camera.inertialPanningY += (ed.y - previousMultiTouchPanPosition.y) / (this.panningSensibility);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (cacheSoloPointer && cacheSoloPointer.pointerId === evt.pointerId) {
|
|
|
- previousMultiTouchPanPosition.x = ed.x;
|
|
|
- previousMultiTouchPanPosition.y = ed.y;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- previousPinchSquaredDistance = pinchSquaredDistance;
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE | PointerEventTypes.POINTERDOUBLETAP);
|
|
|
-
|
|
|
- this._onContextMenu = (evt) => {
|
|
|
- evt.preventDefault();
|
|
|
- };
|
|
|
-
|
|
|
- if (!this.camera._useCtrlForPanning) {
|
|
|
- element.addEventListener("contextmenu", this._onContextMenu, false);
|
|
|
- }
|
|
|
-
|
|
|
- this._onLostFocus = () => {
|
|
|
- //this._keys = [];
|
|
|
- pointA = pointB = null;
|
|
|
- previousPinchSquaredDistance = 0;
|
|
|
- previousMultiTouchPanPosition.isPaning = false;
|
|
|
- previousMultiTouchPanPosition.isPinching = false;
|
|
|
- twoFingerActivityCount = 0;
|
|
|
- cacheSoloPointer = null;
|
|
|
- initialDistance = 0;
|
|
|
- };
|
|
|
-
|
|
|
- this._onMouseMove = (evt) => {
|
|
|
- if (!engine.isPointerLock) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
|
|
|
- var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
|
|
|
-
|
|
|
+ protected onTouch(point: Nullable<PointerTouch>,
|
|
|
+ offsetX: number,
|
|
|
+ offsetY: number): void {
|
|
|
+ if (this.panningSensibility !== 0 &&
|
|
|
+ ((this._ctrlKey && this.camera._useCtrlForPanning) || this._isPanClick)) {
|
|
|
+ this.camera.inertialPanningX += -offsetX / this.panningSensibility;
|
|
|
+ this.camera.inertialPanningY += offsetY / this.panningSensibility;
|
|
|
+ } else {
|
|
|
this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
|
|
|
this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
|
|
|
-
|
|
|
- if (!noPreventDefault) {
|
|
|
- evt.preventDefault();
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- this._onGestureStart = (e) => {
|
|
|
- if (window.MSGesture === undefined) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!this._MSGestureHandler) {
|
|
|
- this._MSGestureHandler = new MSGesture();
|
|
|
- this._MSGestureHandler.target = element;
|
|
|
- }
|
|
|
-
|
|
|
- this._MSGestureHandler.addPointer(e.pointerId);
|
|
|
- };
|
|
|
-
|
|
|
- this._onGesture = (e) => {
|
|
|
- this.camera.radius *= e.scale;
|
|
|
-
|
|
|
- if (e.preventDefault) {
|
|
|
- if (!noPreventDefault) {
|
|
|
- e.stopPropagation();
|
|
|
- e.preventDefault();
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- element.addEventListener("mousemove", this._onMouseMove, false);
|
|
|
- element.addEventListener("MSPointerDown", <EventListener>this._onGestureStart, false);
|
|
|
- element.addEventListener("MSGestureChange", <EventListener>this._onGesture, false);
|
|
|
-
|
|
|
- Tools.RegisterTopRootEvents([
|
|
|
- { name: "blur", handler: this._onLostFocus }
|
|
|
- ]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Detach the current controls from the specified dom element.
|
|
|
- * @param element Defines the element to stop listening the inputs from
|
|
|
+ * Called on pointer POINTERDOUBLETAP event.
|
|
|
*/
|
|
|
- public detachControl(element: Nullable<HTMLElement>): void {
|
|
|
- if (this._onLostFocus) {
|
|
|
- Tools.UnregisterTopRootEvents([
|
|
|
- { name: "blur", handler: this._onLostFocus }
|
|
|
- ]);
|
|
|
+ protected onDoubleTap(type: string) {
|
|
|
+ if (this.camera.useInputToRestoreState) {
|
|
|
+ this.camera.restoreState();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (element && this._observer) {
|
|
|
- this.camera.getScene().onPointerObservable.remove(this._observer);
|
|
|
- this._observer = null;
|
|
|
-
|
|
|
- if (this._onContextMenu) {
|
|
|
- element.removeEventListener("contextmenu", this._onContextMenu);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Called on pointer POINTERMOVE event if multiple touches are active.
|
|
|
+ */
|
|
|
+ protected onMultiTouch(pointA: Nullable<PointerTouch>,
|
|
|
+ pointB: Nullable<PointerTouch>,
|
|
|
+ previousPinchSquaredDistance: number,
|
|
|
+ pinchSquaredDistance: number,
|
|
|
+ previousMultiTouchPanPosition: Nullable<PointerTouch>,
|
|
|
+ multiTouchPanPosition: Nullable<PointerTouch>): void
|
|
|
+ {
|
|
|
+ if (previousPinchSquaredDistance === 0 && previousMultiTouchPanPosition === null) {
|
|
|
+ // First time this method is called for new pinch.
|
|
|
+ // Next time this is called there will be a
|
|
|
+ // previousPinchSquaredDistance and pinchSquaredDistance to compare.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (pinchSquaredDistance === 0 && multiTouchPanPosition === null) {
|
|
|
+ // Last time this method is called at the end of a pinch.
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (this._onMouseMove) {
|
|
|
- element.removeEventListener("mousemove", this._onMouseMove);
|
|
|
+ var direction = this.pinchInwards ? 1 : -1;
|
|
|
+
|
|
|
+ if (this.multiTouchPanAndZoom) {
|
|
|
+ if (this.pinchDeltaPercentage) {
|
|
|
+ this.camera.inertialRadiusOffset +=
|
|
|
+ (pinchSquaredDistance - previousPinchSquaredDistance) * 0.001 *
|
|
|
+ this.camera.radius * this.pinchDeltaPercentage;
|
|
|
+ } else {
|
|
|
+ this.camera.inertialRadiusOffset +=
|
|
|
+ (pinchSquaredDistance - previousPinchSquaredDistance) /
|
|
|
+ (this.pinchPrecision * direction *
|
|
|
+ (this.angularSensibilityX + this.angularSensibilityY) / 2);
|
|
|
}
|
|
|
|
|
|
- if (this._onGestureStart) {
|
|
|
- element.removeEventListener("MSPointerDown", <EventListener>this._onGestureStart);
|
|
|
+ if (this.panningSensibility !== 0 &&
|
|
|
+ previousMultiTouchPanPosition && multiTouchPanPosition) {
|
|
|
+ var moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x;
|
|
|
+ var moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
|
|
|
+ this.camera.inertialPanningX += -moveDeltaX / this.panningSensibility;
|
|
|
+ this.camera.inertialPanningY += moveDeltaY / this.panningSensibility;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ this._twoFingerActivityCount++;
|
|
|
+ var previousPinchDistance = Math.sqrt(previousPinchSquaredDistance);
|
|
|
+ var pinchDistance = Math.sqrt(pinchSquaredDistance);
|
|
|
+ if (this._isPinching ||
|
|
|
+ (this._twoFingerActivityCount < 20 &&
|
|
|
+ Math.abs(pinchDistance - previousPinchDistance) >
|
|
|
+ this.camera.pinchToPanMaxDistance)) {
|
|
|
+ // Since pinch has not been active long, assume we intend to zoom.
|
|
|
+ if (this.pinchDeltaPercentage) {
|
|
|
+ this.camera.inertialRadiusOffset +=
|
|
|
+ (pinchSquaredDistance - previousPinchSquaredDistance) * 0.001 *
|
|
|
+ this.camera.radius * this.pinchDeltaPercentage;
|
|
|
+ } else {
|
|
|
+ this.camera.inertialRadiusOffset +=
|
|
|
+ (pinchSquaredDistance - previousPinchSquaredDistance) /
|
|
|
+ (this.pinchPrecision * direction *
|
|
|
+ (this.angularSensibilityX + this.angularSensibilityY) / 2);
|
|
|
+ }
|
|
|
|
|
|
- if (this._onGesture) {
|
|
|
- element.removeEventListener("MSGestureChange", <EventListener>this._onGesture);
|
|
|
+ // Since we are pinching, remain pinching on next iteration.
|
|
|
+ this._isPinching = true;
|
|
|
+ } else {
|
|
|
+ // Pause between pinch starting and moving implies not a zoom event.
|
|
|
+ // Pan instead.
|
|
|
+ if (this.panningSensibility !== 0 && this.multiTouchPanning &&
|
|
|
+ multiTouchPanPosition && previousMultiTouchPanPosition) {
|
|
|
+ var moveDeltaX = multiTouchPanPosition.x - previousMultiTouchPanPosition.x;
|
|
|
+ var moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
|
|
|
+ this.camera.inertialPanningX += -moveDeltaX / this.panningSensibility;
|
|
|
+ this.camera.inertialPanningY += moveDeltaY / this.panningSensibility;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- this._isPanClick = false;
|
|
|
- this.pinchInwards = true;
|
|
|
-
|
|
|
- this._onMouseMove = null;
|
|
|
- this._onGestureStart = null;
|
|
|
- this._onGesture = null;
|
|
|
- this._MSGestureHandler = null;
|
|
|
- this._onLostFocus = null;
|
|
|
- this._onContextMenu = null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Gets the class name of the current intput.
|
|
|
- * @returns the class name
|
|
|
+ * Called each time a new POINTERDOWN event occurs. Ie, for each button
|
|
|
+ * press.
|
|
|
+ */
|
|
|
+ protected onButtonDown(evt: PointerEvent, buttonCount: number): void {
|
|
|
+ this._isPanClick = evt.button === this.camera._panningMouseButton;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Called each time a new POINTERUP event occurs. Ie, for each button
|
|
|
+ * release.
|
|
|
*/
|
|
|
- public getClassName(): string {
|
|
|
- return "ArcRotateCameraPointersInput";
|
|
|
+ protected onButtonUp(evt: PointerEvent): void {
|
|
|
+ this._twoFingerActivityCount = 0;
|
|
|
+ this._isPinching = false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Get the friendly name associated with the input class.
|
|
|
- * @returns the input friendly name
|
|
|
+ * Called when window becomes inactive.
|
|
|
*/
|
|
|
- public getSimpleName(): string {
|
|
|
- return "pointers";
|
|
|
+ protected onLostFocus(): void {
|
|
|
+ this._isPanClick = false;
|
|
|
+ this._twoFingerActivityCount = 0;
|
|
|
+ this._isPinching = false;
|
|
|
}
|
|
|
}
|
|
|
+(<any>CameraInputTypes)["ArcRotateCameraPointersInput"] =
|
|
|
+ ArcRotateCameraPointersInput;
|
|
|
|
|
|
-(<any>CameraInputTypes)["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;
|