✨ Drag to move in file preview
This commit is contained in:
@@ -68,13 +68,21 @@
|
|||||||
@touchstart="handleTouchStart"
|
@touchstart="handleTouchStart"
|
||||||
@touchmove="handleTouchMove"
|
@touchmove="handleTouchMove"
|
||||||
@touchend="handleTouchEnd"
|
@touchend="handleTouchEnd"
|
||||||
|
@mousedown="handleMouseDown"
|
||||||
|
@mousemove="handleMouseMove"
|
||||||
|
@mouseup="handleMouseUp"
|
||||||
|
@mouseleave="handleMouseUp"
|
||||||
@dblclick="handleDoubleClick"
|
@dblclick="handleDoubleClick"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="fileType === 'image'"
|
v-if="fileType === 'image'"
|
||||||
:src="fileSource"
|
:src="fileSource"
|
||||||
class="preview-image"
|
class="preview-image"
|
||||||
:style="{ transform: `scale(${zoomLevel})` }"
|
:style="{
|
||||||
|
transform: `translate(${translateX}px, ${translateY}px) scale(${zoomLevel})`,
|
||||||
|
cursor:
|
||||||
|
zoomLevel > 1 ? (isDragging ? 'grabbing' : 'grab') : 'default'
|
||||||
|
}"
|
||||||
alt="Image preview"
|
alt="Image preview"
|
||||||
/>
|
/>
|
||||||
<video
|
<video
|
||||||
@@ -251,6 +259,13 @@ const zoomLevel = ref<number>(1)
|
|||||||
const initialDistance = ref<number>(0)
|
const initialDistance = ref<number>(0)
|
||||||
const isPinching = ref<boolean>(false)
|
const isPinching = ref<boolean>(false)
|
||||||
|
|
||||||
|
// Drag functionality
|
||||||
|
const translateX = ref(0)
|
||||||
|
const translateY = ref(0)
|
||||||
|
const isDragging = ref(false)
|
||||||
|
const startX = ref(0)
|
||||||
|
const startY = ref(0)
|
||||||
|
|
||||||
// View transition state
|
// View transition state
|
||||||
const isTransitioning = ref<boolean>(false)
|
const isTransitioning = ref<boolean>(false)
|
||||||
const transitionImage = ref<string>("")
|
const transitionImage = ref<string>("")
|
||||||
@@ -397,52 +412,101 @@ function handleZoom(event: WheelEvent) {
|
|||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const delta = event.deltaY > 0 ? -0.1 : 0.1
|
const delta = event.deltaY > 0 ? -0.1 : 0.1
|
||||||
zoomLevel.value = Math.max(0.1, Math.min(5, zoomLevel.value + delta))
|
const newZoom = Math.max(0.1, Math.min(5, zoomLevel.value + delta))
|
||||||
|
|
||||||
|
if (newZoom <= 1) {
|
||||||
|
translateX.value = 0
|
||||||
|
translateY.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomLevel.value = newZoom
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTouchStart(event: TouchEvent) {
|
function handleTouchStart(event: TouchEvent) {
|
||||||
if (fileType.value !== "image" || event.touches.length !== 2) return
|
if (fileType.value !== "image") return
|
||||||
|
|
||||||
event.preventDefault()
|
if (event.touches.length === 2) {
|
||||||
isPinching.value = true
|
event.preventDefault()
|
||||||
const touch1 = event.touches[0]!
|
isPinching.value = true
|
||||||
const touch2 = event.touches[1]!
|
const touch1 = event.touches[0]!
|
||||||
initialDistance.value = Math.sqrt(
|
const touch2 = event.touches[1]!
|
||||||
Math.pow(touch2.clientX - touch1.clientX, 2) +
|
initialDistance.value = Math.sqrt(
|
||||||
Math.pow(touch2.clientY - touch1.clientY, 2)
|
Math.pow(touch2.clientX - touch1.clientX, 2) +
|
||||||
)
|
Math.pow(touch2.clientY - touch1.clientY, 2)
|
||||||
|
)
|
||||||
|
} else if (event.touches.length === 1 && zoomLevel.value > 1) {
|
||||||
|
isDragging.value = true
|
||||||
|
startX.value = event.touches[0]!.clientX - translateX.value
|
||||||
|
startY.value = event.touches[0]!.clientY - translateY.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTouchMove(event: TouchEvent) {
|
function handleTouchMove(event: TouchEvent) {
|
||||||
if (
|
if (fileType.value !== "image") return
|
||||||
fileType.value !== "image" ||
|
|
||||||
!isPinching.value ||
|
|
||||||
event.touches.length !== 2
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
event.preventDefault()
|
if (isPinching.value && event.touches.length === 2) {
|
||||||
const touch1 = event.touches[0]!
|
event.preventDefault()
|
||||||
const touch2 = event.touches[1]!
|
const touch1 = event.touches[0]!
|
||||||
const currentDistance = Math.sqrt(
|
const touch2 = event.touches[1]!
|
||||||
Math.pow(touch2.clientX - touch1.clientX, 2) +
|
const currentDistance = Math.sqrt(
|
||||||
Math.pow(touch2.clientY - touch1.clientY, 2)
|
Math.pow(touch2.clientX - touch1.clientX, 2) +
|
||||||
)
|
Math.pow(touch2.clientY - touch1.clientY, 2)
|
||||||
|
)
|
||||||
|
|
||||||
const scale = currentDistance / initialDistance.value
|
const scale = currentDistance / initialDistance.value
|
||||||
zoomLevel.value = Math.max(0.1, Math.min(5, zoomLevel.value * scale))
|
const newZoom = Math.max(0.1, Math.min(5, zoomLevel.value * scale))
|
||||||
|
|
||||||
|
if (newZoom <= 1) {
|
||||||
|
translateX.value = 0
|
||||||
|
translateY.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomLevel.value = newZoom
|
||||||
|
} else if (isDragging.value && event.touches.length === 1) {
|
||||||
|
event.preventDefault()
|
||||||
|
translateX.value = event.touches[0]!.clientX - startX.value
|
||||||
|
translateY.value = event.touches[0]!.clientY - startY.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTouchEnd(_event: TouchEvent) {
|
function handleTouchEnd(_event: TouchEvent) {
|
||||||
if (fileType.value !== "image") return
|
if (fileType.value !== "image") return
|
||||||
|
|
||||||
isPinching.value = false
|
isPinching.value = false
|
||||||
|
isDragging.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseDown(event: MouseEvent) {
|
||||||
|
if (fileType.value !== "image" || zoomLevel.value <= 1) return
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
isDragging.value = true
|
||||||
|
startX.value = event.clientX - translateX.value
|
||||||
|
startY.value = event.clientY - translateY.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseMove(event: MouseEvent) {
|
||||||
|
if (!isDragging.value) return
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
translateX.value = event.clientX - startX.value
|
||||||
|
translateY.value = event.clientY - startY.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseUp() {
|
||||||
|
isDragging.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDoubleClick() {
|
function handleDoubleClick() {
|
||||||
if (fileType.value !== "image") return
|
if (fileType.value !== "image") return
|
||||||
|
|
||||||
zoomLevel.value = zoomLevel.value > 1 ? 1 : 2
|
if (zoomLevel.value > 1) {
|
||||||
|
zoomLevel.value = 1
|
||||||
|
translateX.value = 0
|
||||||
|
translateY.value = 0
|
||||||
|
} else {
|
||||||
|
zoomLevel.value = 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"daisyui": "^5.5.5",
|
"daisyui": "^5.5.5",
|
||||||
"naive-ui": "^2.43.2",
|
"naive-ui": "^2.43.2",
|
||||||
"tailwindcss": "^4.1.17"
|
"tailwindcss": "^4.1.17",
|
||||||
|
"unplugin-auto-import": "^20.3.0",
|
||||||
|
"unplugin-vue-components": "^30.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user