Overview
The useZoomImageWheel composable provides wheel-based image zoom functionality with support for mouse wheel, pinch-to-zoom gestures, and programmatic zoom controls. It enables users to zoom and pan images using scroll/wheel events and touch gestures.
Signature
function useZoomImageWheel(): {
createZoomImage: (
container: HTMLElement,
options?: ZoomImageWheelOptions
) => void
zoomImageState: ZoomImageWheelState
setZoomImageState: (state: ZoomImageWheelStateUpdate) => void
}
Return Value
Initializes the zoom functionality on the specified container element.
zoomImageState
ZoomImageWheelState
required
Reactive state object containing current zoom propertiesCurrent zoom level (1 = 100%, 2 = 200%, etc.)
Whether zoom functionality is enabled
Current X-axis position of the zoomed image in pixels
Current Y-axis position of the zoomed image in pixels
Current rotation angle in degrees
Updates the zoom state programmatically
Examples
Basic Usage
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageWheel } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage, zoomImageState } = useZoomImageWheel()
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value)
}
})
</script>
<template>
<div>
<p>Current zoom: {{ Math.round(zoomImageState.currentZoom * 100) }}%</p>
<div ref="imageContainerRef" class="h-[300px] w-[200px] cursor-crosshair">
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
</div>
</div>
</template>
With Custom Options
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageWheel } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage, zoomImageState } = useZoomImageWheel()
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
maxZoom: 6,
wheelZoomRatio: 0.2,
initialState: {
currentZoom: 1.5,
currentRotation: 0
}
})
}
})
</script>
<template>
<div ref="imageContainerRef" class="h-[300px] w-[200px]">
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
</div>
</template>
Programmatic Controls
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageWheel } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const {
createZoomImage,
zoomImageState,
setZoomImageState
} = useZoomImageWheel()
const zoomIn = () => {
setZoomImageState({
currentZoom: zoomImageState.currentZoom + 0.5
})
}
const zoomOut = () => {
setZoomImageState({
currentZoom: zoomImageState.currentZoom - 0.5
})
}
const rotate = () => {
setZoomImageState({
currentRotation: zoomImageState.currentRotation + 90
})
}
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value)
}
})
</script>
<template>
<div>
<div class="flex space-x-2 mb-4">
<button @click="zoomIn" class="px-4 py-2 bg-gray-100 rounded">
Zoom In
</button>
<button @click="zoomOut" class="px-4 py-2 bg-gray-100 rounded">
Zoom Out
</button>
<button @click="rotate" class="px-4 py-2 bg-gray-100 rounded">
Rotate 90°
</button>
</div>
<div ref="imageContainerRef" class="h-[300px] w-[200px] cursor-crosshair">
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
</div>
</div>
</template>
With Image Cropping
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageWheel } from '@zoom-image/vue'
import { cropImage } from '@zoom-image/core'
const imageContainerRef = ref<HTMLDivElement>()
const croppedImage = ref<string>()
const { createZoomImage, zoomImageState } = useZoomImageWheel()
const handleCrop = async () => {
if (!imageContainerRef.value) return
croppedImage.value = await cropImage({
currentZoom: zoomImageState.currentZoom,
image: imageContainerRef.value.querySelector('img') as HTMLImageElement,
positionX: zoomImageState.currentPositionX,
positionY: zoomImageState.currentPositionY,
rotation: zoomImageState.currentRotation
})
}
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value)
}
})
</script>
<template>
<div>
<div class="flex items-center gap-4">
<div ref="imageContainerRef" class="h-[300px] w-[200px] cursor-crosshair">
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
</div>
<img
v-if="croppedImage"
:src="croppedImage"
alt="Cropped result"
class="h-[300px] w-[200px]"
/>
</div>
<button @click="handleCrop" class="mt-4 px-4 py-2 bg-gray-100 rounded">
Crop Image
</button>
</div>
</template>
Cleanup
The composable automatically cleans up event listeners and resources when the component is unmounted using Vue’s onUnmounted hook. If you need to reinitialize the zoom on the same container, simply call createZoomImage again - it will automatically clean up the previous instance.
<script setup lang="ts">
import { ref } from 'vue'
import { useZoomImageWheel } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage } = useZoomImageWheel()
const reinitialize = () => {
if (imageContainerRef.value) {
// Previous instance is automatically cleaned up
createZoomImage(imageContainerRef.value, {
maxZoom: 8
})
}
}
</script>
See Also