UNPKG

@tencentcloud/roomkit-web-vue3

Version:

<h1 align="center"> TUIRoomKit</h1> Conference (TUIRoomKit) is a product suitable for multi-person audio and video conversation scenarios such as business meetings, webinars, and online education. By integrating this product, you can add room management,

231 lines (204 loc) 6.88 kB
/** * <div v-touch-scale="enable"></div> */ const touchScaleElementMap = new Map<HTMLElement, TouchScale>(); class TouchScale { public touchDom: HTMLElement; public transformDom: HTMLElement; public lastPosition = { x: 0, y: 0 }; public lastCenterPosition = { x: 0, y: 0 }; public lastDistance = 0; public currentTranslate = { x: 0, y: 0 }; public currentCenterPosition = { x: 0, y: 0 }; public currentScale = 1; public tempScale = 1; public tempTranslate = { x: 0, y: 0 }; public isOneFingerControl = false; public isTwoFingerControl = false; public isEnabled = false; constructor(el: HTMLElement, binding: any) { this.touchDom = el; this.transformDom = el; this.transformDom.style.transformOrigin = '0 0'; this.isEnabled = !!binding.value; this.handleTouchStart = this.handleTouchStart.bind(this); this.handleTouchMove = this.handleTouchMove.bind(this); this.handleTouchEnd = this.handleTouchEnd.bind(this); this.touchDom?.addEventListener('touchstart', this.handleTouchStart, false); this.touchDom?.addEventListener('touchmove', this.handleTouchMove, false); this.touchDom?.addEventListener('touchend', this.handleTouchEnd, false); } public updateBinding(binding: any) { this.isEnabled = !!binding.value; } public destroy() { this.touchDom?.removeEventListener( 'touchstart', this.handleTouchStart, false ); this.touchDom?.removeEventListener( 'touchmove', this.handleTouchMove, false ); this.touchDom?.removeEventListener('touchend', this.handleTouchEnd, false); } private handleTouchStart(event: TouchEvent) { if (!this.isEnabled) { return; } event.preventDefault(); if (this.currentScale !== 1) { event.stopPropagation(); } if (event.touches.length === 2) { this.handleScaleStart(event); this.isTwoFingerControl = true; } if (event.touches.length === 1) { this.handlePositionStart(event); this.isOneFingerControl = true; } } private handleTouchMove(event: TouchEvent) { if (!this.isEnabled) { return; } event.preventDefault(); if (this.tempScale !== 1) { event.stopPropagation(); } if (event.touches.length === 2 && this.isTwoFingerControl) { this.handleScaleMove(event); } if (event.touches.length === 1 && this.isOneFingerControl) { this.handlePositionMove(event); } } private handleTouchEnd(event: TouchEvent) { if (!this.isEnabled) { return; } event.preventDefault(); if (this.currentScale !== 1) { event.stopPropagation(); } if (this.isTwoFingerControl) { this.handleScaleEnd(); } this.isTwoFingerControl = false; this.isOneFingerControl = false; } private getDistance(touchTargetA: Touch, touchTargetB: Touch) { return Math.sqrt( Math.pow(touchTargetA.pageX - touchTargetB.pageX, 2) + Math.pow(touchTargetA.pageY - touchTargetB.pageY, 2) ); } private getCenterPointer(touchTargetA: Touch, touchTargetB: Touch) { return { x: (touchTargetA.pageX + touchTargetB.pageX) / 2, y: (touchTargetA.pageY + touchTargetB.pageY) / 2, }; } private getTranslateLimitedObj( translateObj: { x: number; y: number }, scale: number ) { const translateResult = { ...translateObj }; if (translateObj.x > 0) { translateResult.x = 0; } if (translateObj.x < 0 - (scale - 1) * this.transformDom.offsetWidth) { translateResult.x = 0 - (scale - 1) * this.transformDom.offsetWidth; } if (translateObj.y > 0) { translateResult.y = 0; } if (translateObj.y < 0 - (scale - 1) * this.transformDom.offsetHeight) { translateResult.y = 0 - (scale - 1) * this.transformDom.offsetHeight; } return translateResult; } private handleScaleStart(event: TouchEvent) { const [initATarget, initBTarget] = event.touches; this.lastDistance = this.getDistance(initATarget, initBTarget); this.lastCenterPosition = this.getCenterPointer(initATarget, initBTarget); } private handleScaleMove(event: TouchEvent) { const [moveATarget, moveBTarget] = event.touches; const moveDistance = this.getDistance(moveATarget, moveBTarget); const centerPosition = this.getCenterPointer(moveATarget, moveBTarget); this.tempScale = this.currentScale * (moveDistance / this.lastDistance); if (this.tempScale <= 1) { this.tempTranslate = { x: 0, y: 0 }; this.tempScale = 1; } else { const gapTop = (moveDistance / this.lastDistance) * (this.currentScale * this.lastCenterPosition.y) - this.currentScale * centerPosition.y; const gapLeft = (moveDistance / this.lastDistance) * (this.currentScale * this.lastCenterPosition.x) - this.currentScale * centerPosition.x; this.tempTranslate = { x: this.currentTranslate.x - gapLeft, y: this.currentTranslate.y - gapTop, }; this.tempTranslate = this.getTranslateLimitedObj( this.tempTranslate, this.tempScale ); } this.transformDom.style.transform = `translate(${this.tempTranslate.x}px, ${this.tempTranslate.y}px) scale(${this.tempScale})`; } private handleScaleEnd() { this.currentScale = this.tempScale; this.currentTranslate = this.tempTranslate; } private handlePositionStart(event: TouchEvent) { this.lastPosition = { x: event.touches[0].pageX, y: event.touches[0].pageY, }; } private handlePositionMove(event: TouchEvent) { const currentPosition = { x: event.touches[0].pageX, y: event.touches[0].pageY, }; this.currentTranslate = { x: this.currentTranslate.x + (currentPosition.x - this.lastPosition.x), y: this.currentTranslate.y + (currentPosition.y - this.lastPosition.y), }; this.currentTranslate = this.getTranslateLimitedObj( this.currentTranslate, this.currentScale ); this.lastPosition = currentPosition; this.transformDom.style.transform = `translate(${this.currentTranslate.x}px, ${this.currentTranslate.y}px) scale(${this.currentScale})`; } } const vDblTouch = { mounted(el: HTMLElement, binding: any) { if (binding.value) { const newTouchScale = new TouchScale(el, binding); touchScaleElementMap.set(el, newTouchScale); } }, updated(el: HTMLElement, binding: any) { if (touchScaleElementMap.get(el)) { touchScaleElementMap.get(el)?.updateBinding(binding); } else if (binding.value) { const newTouchScale = new TouchScale(el, binding); touchScaleElementMap.set(el, newTouchScale); } }, beforeUnmount(el: HTMLElement) { touchScaleElementMap.get(el)?.destroy(); touchScaleElementMap.delete(el); }, }; export default vDblTouch;