UNPKG

avansel

Version:

Free OpenSource ThreeJS Javascript Virtual Tours viewer

302 lines (240 loc) 9.93 kB
import { MathUtils } from 'three' import Camera from '../Components/Camera' import { normLng } from '../Components/utils' import { controls } from '../config.json' import { CameraPosition } from '../Types' enum TouchType { Touch, Zoom } export default class Controls{ camera: Camera canvas: HTMLCanvasElement tween: boolean fovMax: number fovMin: number isInteracting: boolean onTouchDist: number onTouchFov: number touchType: TouchType onMouseDownMouseX: number onMouseDownMouseY: number lng: number lngVector: number onMouseDownLng: number lat: number latVector: number onMouseDownLat: number fov: number fovVector: number phi: number theta: number onTouchStartHandler: any onClickHandler: any onMouseDownHandler: any onMouseWheelHandler: any onTouchMoveHandler: any onTouchUpHandler: any onMouseMoveHandler: any onMouseUpHandler: any constructor(camera: Camera, canvas: HTMLCanvasElement) { this.camera = camera; this.canvas = canvas this.tween = true this.fovMax = controls.fovMax; this.fovMin = controls.fovMin; this.isInteracting = false this.onMouseDownMouseX = 0 this.onMouseDownMouseY = 0 this.lng = 90 this.lngVector = 90 this.onMouseDownLng = 0 this.lat = 0 this.latVector = 0 this.onMouseDownLat = 0 this.phi = 0 this.theta = 0 this.fov = 70 this.fovVector = 70 this.init() } init(){ this.onTouchStartHandler = this.onTouchStart.bind(this) this.onClickHandler = this.onClick.bind(this) this.onMouseDownHandler = this.onMouseDown.bind(this) this.onMouseWheelHandler = this.onMouseWheel.bind(this) this.canvas.addEventListener('touchstart', this.onTouchStartHandler) this.canvas.addEventListener( 'click', this.onClickHandler ) this.canvas.addEventListener( 'mousedown', this.onMouseDownHandler ) this.canvas.addEventListener( 'mousewheel', this.onMouseWheelHandler ) this.camera.lookAt(this.lat, this.lng) } setTween(tween: boolean){ this.tween = tween } position(): CameraPosition{ return { lat: this.lat, lng: normLng(this.lng), fov: this.fov } } tick(delta: number) { if ( this.isInteracting === false ) { //lng += 0.025; } this.lat = Math.max( - 90, Math.min( 89.9999999999, this.lat ) ); if(this.tween){ if(this.fovVector != this.fov){ let diff = (this.fov - this.fovVector) / 10 if(Math.abs(this.fovVector / diff) > 500000){ this.fov = this.fovVector }else{ this.fov = this.fov - diff } this.onFovChanged() } let posChanged = false if(this.latVector != this.lat){ let diff = (this.lat - this.latVector) / 10 if(Math.abs(this.fov / diff) > 100000){ this.lat = this.latVector }else{ this.lat = this.lat - diff } posChanged = true } if(this.lngVector != this.lng){ let diff = (this.lng - this.lngVector) / 10 if(Math.abs(this.fov / diff) > 100000){ this.lng = this.lngVector }else{ this.lng = this.lng - diff } posChanged = true } if(posChanged) this.onPosChanged(); } } // Touch events onTouchStart(e: TouchEvent){ var touches = e.touches if(touches.length == 1){ this.touchType = TouchType.Touch }else if(touches.length == 2){ this.touchType = TouchType.Zoom } if(this.touchType == TouchType.Touch && e.type == 'touchstart'){ var touch = touches[0] this.isInteracting = true this.onMouseDownMouseX = touch.pageX this.onMouseDownMouseY = touch.pageY this.onMouseDownLng = this.lng this.onMouseDownLat = this.lat } if(this.touchType == TouchType.Zoom){ this.onTouchDist = Math.hypot( touches[0].pageX - touches[1].pageX, touches[0].pageY - touches[1].pageY ) this.onTouchFov = this.fov } this.onTouchMoveHandler = this.onTouchMove.bind(this) this.onTouchUpHandler = this.onTouchUp.bind(this) this.canvas.addEventListener( 'touchmove', this.onTouchMoveHandler ) this.canvas.addEventListener( 'touchend', this.onTouchUpHandler ) this.canvas.addEventListener( 'touchcancel', this.onTouchUpHandler ) e.preventDefault() } onTouchMove(e: TouchEvent){ var touches = e.touches var newTouchType: TouchType if(touches.length == 1){ newTouchType = TouchType.Touch }else if(touches.length == 2){ newTouchType = TouchType.Zoom } if(this.touchType != newTouchType){ return null } if(this.touchType == TouchType.Touch && e.type == 'touchmove'){ var touch = touches[0] this.lng = ( this.onMouseDownMouseX - touch.pageX ) * this.camera.get().fov * controls.moveFactor / this.canvas.clientWidth + this.onMouseDownLng; this.lat = ( touch.pageY - this.onMouseDownMouseY ) * this.camera.get().fov * controls.moveFactor / this.canvas.clientWidth + this.onMouseDownLat; this.latVector = this.lat this.lngVector = this.lng this.onPosChanged() } if(this.touchType == TouchType.Zoom && e.type == 'touchmove'){ var dist = Math.hypot( touches[0].pageX - touches[1].pageX, touches[0].pageY - touches[1].pageY ) var diff = this.onTouchDist - dist this.fov = MathUtils.clamp( this.onTouchFov + diff * this.onTouchFov / 500, this.fovMin, this.fovMax ) this.fovVector = this.fov this.onFovChanged() } } onTouchUp(e: TouchEvent){ this.isInteracting = false this.canvas.removeEventListener( 'touchmove', this.onTouchMoveHandler ) this.canvas.removeEventListener( 'touchend', this.onTouchUpHandler ) this.canvas.removeEventListener( 'touchcancel', this.onTouchMoveHandler ) this.touchType = null if(e.changedTouches.length == 1){ const touch = e.changedTouches[0] if(touch.clientX == this.onMouseDownMouseX && touch.clientY == this.onMouseDownMouseY){ this.onTap(e) } } } onTap(e: TouchEvent){ console.log('onTap') } // mouse events onMouseDown(e: MouseEvent){ this.isInteracting = true this.onMouseDownMouseX = e.clientX this.onMouseDownMouseY = e.clientY this.onMouseDownLng = this.lng this.onMouseDownLat = this.lat this.onMouseMoveHandler = this.onMouseMove.bind(this) this.onMouseUpHandler = this.onMouseUp.bind(this) this.canvas.addEventListener( 'mousemove', this.onMouseMoveHandler ) this.canvas.addEventListener( 'mouseup', this.onMouseUpHandler ) this.canvas.addEventListener( 'mouseleave', this.onMouseUpHandler ) } onMouseMove(e: MouseEvent){ if(this.tween){ this.lngVector = ( this.onMouseDownMouseX - e.clientX ) * this.camera.get().fov * controls.moveFactor / this.canvas.clientWidth + this.onMouseDownLng this.latVector = ( e.clientY - this.onMouseDownMouseY ) * this.camera.get().fov * controls.moveFactor / this.canvas.clientWidth + this.onMouseDownLat }else{ this.lng = ( this.onMouseDownMouseX - e.clientX ) * this.camera.get().fov * controls.moveFactor / this.canvas.clientWidth + this.onMouseDownLng; this.lat = ( e.clientY - this.onMouseDownMouseY ) * this.camera.get().fov * controls.moveFactor / this.canvas.clientWidth + this.onMouseDownLat; this.onPosChanged() } } onMouseUp(e: MouseEvent){ this.isInteracting = false this.canvas.removeEventListener( 'mousemove', this.onMouseMoveHandler ) this.canvas.removeEventListener( 'mouseup', this.onMouseUpHandler ) this.canvas.removeEventListener( 'mouseleave', this.onMouseUpHandler ) } onMouseWheel(e: WheelEvent){ e.preventDefault() e.stopPropagation() if(this.tween){ this.fovVector = MathUtils.clamp(this.fovVector + e.deltaY * this.fovVector / 1000, this.fovMin, this.fovMax ) }else{ this.fov = MathUtils.clamp( this.fov + e.deltaY * this.fov / 1000, this.fovMin, this.fovMax ) this.onFovChanged() } } onClick(e: PointerEvent){ if(e.clientX == this.onMouseDownMouseX && e.clientY == this.onMouseDownMouseY){ this.canvas.dispatchEvent(new CustomEvent('panoClick', {detail: e})) } } onFovChanged(){ this.camera.setFov(this.fov) this.canvas.dispatchEvent( new CustomEvent('fovChanged', {detail: { fov: this.fov }}) ) } onPosChanged(){ this.camera.lookAt(this.lat, this.lng) this.canvas.dispatchEvent(new CustomEvent('cameraMove', {detail: { lat: this.lat, lng: this.lng }})) } }