feat: image pinch to zoom (#1620)
parent
e92d1c6adf
commit
2cf8f591e8
|
@ -1,5 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SwipeDirection } from '@vueuse/core'
|
import { SwipeDirection } from '@vueuse/core'
|
||||||
|
import { useGesture } from '@vueuse/gesture'
|
||||||
|
import type { PermissiveMotionProperties } from '@vueuse/motion'
|
||||||
import { useReducedMotion } from '@vueuse/motion'
|
import { useReducedMotion } from '@vueuse/motion'
|
||||||
import type { mastodon } from 'masto'
|
import type { mastodon } from 'masto'
|
||||||
|
|
||||||
|
@ -23,18 +25,36 @@ const reduceMotion = useReducedMotion()
|
||||||
|
|
||||||
const canAnimate = computed(() => !reduceMotion.value && animateTimeout.value)
|
const canAnimate = computed(() => !reduceMotion.value && animateTimeout.value)
|
||||||
|
|
||||||
|
const { motionProperties } = useMotionProperties(target, {
|
||||||
|
cursor: 'grab',
|
||||||
|
scale: 1,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
})
|
||||||
|
const { set } = useSpring(motionProperties as Partial<PermissiveMotionProperties>)
|
||||||
|
|
||||||
|
function resetZoom() {
|
||||||
|
set({ scale: 1 })
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(modelValue, resetZoom)
|
||||||
|
|
||||||
const { width, height } = useElementSize(target)
|
const { width, height } = useElementSize(target)
|
||||||
const { isSwiping, lengthX, lengthY, direction } = useSwipe(target, {
|
const { isSwiping, lengthX, lengthY, direction } = useSwipe(target, {
|
||||||
threshold: 5,
|
threshold: 5,
|
||||||
passive: false,
|
passive: false,
|
||||||
onSwipeEnd(e, direction) {
|
onSwipeEnd(e, direction) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
if (direction === SwipeDirection.RIGHT && Math.abs(distanceX.value) > threshold)
|
if (direction === SwipeDirection.RIGHT && Math.abs(distanceX.value) > threshold) {
|
||||||
modelValue.value = Math.max(0, modelValue.value - 1)
|
modelValue.value = Math.max(0, modelValue.value - 1)
|
||||||
|
resetZoom()
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
if (direction === SwipeDirection.LEFT && Math.abs(distanceX.value) > threshold)
|
if (direction === SwipeDirection.LEFT && Math.abs(distanceX.value) > threshold) {
|
||||||
modelValue.value = Math.min(media.length - 1, modelValue.value + 1)
|
modelValue.value = Math.min(media.length - 1, modelValue.value + 1)
|
||||||
|
resetZoom()
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
if (direction === SwipeDirection.UP && Math.abs(distanceY.value) > threshold)
|
if (direction === SwipeDirection.UP && Math.abs(distanceY.value) > threshold)
|
||||||
|
@ -42,6 +62,21 @@ const { isSwiping, lengthX, lengthY, direction } = useSwipe(target, {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useGesture({
|
||||||
|
onPinch({ offset: [distance, angle] }) {
|
||||||
|
set({ scale: 1 + distance / 200 })
|
||||||
|
},
|
||||||
|
onMove({ movement: [x, y], dragging, pinching }) {
|
||||||
|
if (dragging && !pinching)
|
||||||
|
set({ x, y })
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
domTarget: target,
|
||||||
|
eventOptions: {
|
||||||
|
passive: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const distanceX = computed(() => {
|
const distanceX = computed(() => {
|
||||||
if (width.value === 0)
|
if (width.value === 0)
|
||||||
return 0
|
return 0
|
||||||
|
|
Loading…
Reference in New Issue