hookehuyr

feat(PdfViewer): 添加双指缩放手势支持

实现PDF查看器的双指缩放功能,包括触摸开始、移动和结束的完整手势处理
...@@ -536,18 +536,117 @@ const addPreventSaveListeners = () => { ...@@ -536,18 +536,117 @@ const addPreventSaveListeners = () => {
536 return false; 536 return false;
537 }); 537 });
538 538
539 - // 防止触摸回调(移动端长按) 539 + // 添加双指缩放手势支持
540 - pdfContainer.addEventListener('touchstart', (e) => { 540 + addPinchZoomListeners(pdfContainer);
541 - if (e.touches.length > 1) { 541 + }
542 - e.preventDefault(); 542 +};
543 - }
544 - });
545 543
546 - // 防止双指缩放等手势 544 +// 双指缩放相关变量
547 - pdfContainer.addEventListener('gesturestart', (e) => { 545 +let initialDistance = 0;
546 +let initialZoom = 1;
547 +let isZooming = false;
548 +
549 +/**
550 + * 添加双指缩放手势监听器
551 + */
552 +const addPinchZoomListeners = (container) => {
553 + let touches = [];
554 +
555 + // 计算两点间距离
556 + const getDistance = (touch1, touch2) => {
557 + const dx = touch1.clientX - touch2.clientX;
558 + const dy = touch1.clientY - touch2.clientY;
559 + return Math.sqrt(dx * dx + dy * dy);
560 + };
561 +
562 + // 获取两点中心位置
563 + const getCenter = (touch1, touch2) => {
564 + return {
565 + x: (touch1.clientX + touch2.clientX) / 2,
566 + y: (touch1.clientY + touch2.clientY) / 2
567 + };
568 + };
569 +
570 + // 触摸开始
571 + container.addEventListener('touchstart', (e) => {
572 + touches = Array.from(e.touches);
573 +
574 + if (touches.length === 2) {
575 + // 双指触摸开始
548 e.preventDefault(); 576 e.preventDefault();
549 - }); 577 + isZooming = true;
550 - } 578 + initialDistance = getDistance(touches[0], touches[1]);
579 + initialZoom = zoomLevel.value;
580 + } else if (touches.length > 2) {
581 + // 超过两指时阻止默认行为
582 + e.preventDefault();
583 + }
584 + }, { passive: false });
585 +
586 + // 触摸移动
587 + container.addEventListener('touchmove', (e) => {
588 + if (e.touches.length === 2 && isZooming) {
589 + e.preventDefault();
590 +
591 + const currentTouches = Array.from(e.touches);
592 + const currentDistance = getDistance(currentTouches[0], currentTouches[1]);
593 + const scale = currentDistance / initialDistance;
594 +
595 + // 计算新的缩放级别
596 + let newZoom = initialZoom * scale;
597 + newZoom = Math.max(0.5, Math.min(3, newZoom)); // 限制缩放范围
598 +
599 + // 获取缩放中心点
600 + const center = getCenter(currentTouches[0], currentTouches[1]);
601 + const rect = container.getBoundingClientRect();
602 + const centerX = center.x - rect.left;
603 + const centerY = center.y - rect.top;
604 +
605 + // 应用缩放
606 + applyPinchZoom(newZoom, centerX, centerY, container);
607 + }
608 + }, { passive: false });
609 +
610 + // 触摸结束
611 + container.addEventListener('touchend', (e) => {
612 + if (isZooming && e.touches.length < 2) {
613 + isZooming = false;
614 + initialDistance = 0;
615 + initialZoom = zoomLevel.value;
616 + }
617 + });
618 +
619 + // 触摸取消
620 + container.addEventListener('touchcancel', (e) => {
621 + isZooming = false;
622 + initialDistance = 0;
623 + initialZoom = zoomLevel.value;
624 + });
625 +};
626 +
627 +/**
628 + * 应用双指缩放
629 + */
630 +const applyPinchZoom = (newZoom, centerX, centerY, container) => {
631 + const oldZoom = zoomLevel.value;
632 + const oldScrollLeft = container.scrollLeft;
633 + const oldScrollTop = container.scrollTop;
634 +
635 + // 更新缩放级别
636 + zoomLevel.value = newZoom;
637 +
638 + // 等待DOM更新后调整滚动位置
639 + nextTick(() => {
640 + const zoomRatio = newZoom / oldZoom;
641 +
642 + // 计算新的滚动位置,以缩放中心为锚点
643 + const newScrollLeft = (oldScrollLeft + centerX) * zoomRatio - centerX;
644 + const newScrollTop = (oldScrollTop + centerY) * zoomRatio - centerY;
645 +
646 + // 应用新的滚动位置
647 + container.scrollLeft = Math.max(0, newScrollLeft);
648 + container.scrollTop = Math.max(0, newScrollTop);
649 + });
551 }; 650 };
552 </script> 651 </script>
553 652
......