Expand Image on Hover
This demo shows how to create an effect where images expand when the mouse hovers over them. The images are also draggable.
Instructions: Hover your mouse over the images to see them expand.
- Vanilla
- React
- Vue
import Konva from 'konva';
const width = window.innerWidth;
const height = window.innerHeight;
const stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
const layer = new Konva.Layer();
stage.add(layer);
// Create Darth Vader image
const darthVaderImg = new Konva.Image({
x: 110,
y: 88,
width: 200,
height: 137,
offset: {
x: 100,
y: 68,
},
draggable: true,
});
layer.add(darthVaderImg);
// Create Yoda image
const yodaImg = new Konva.Image({
x: 290,
y: 70,
width: 93,
height: 104,
offset: {
x: 46,
y: 52,
},
draggable: true,
});
layer.add(yodaImg);
// Load Darth Vader image
const imageObj1 = new Image();
imageObj1.onload = function () {
darthVaderImg.image(imageObj1);
};
imageObj1.src = 'https://konvajs.org/assets/darth-vader.jpg';
// Load Yoda image
const imageObj2 = new Image();
imageObj2.onload = function () {
yodaImg.image(imageObj2);
};
imageObj2.src = 'https://konvajs.org/assets/yoda.jpg';
// Use event delegation to update pointer style and apply scaling
layer.on('mouseover', function (evt) {
const shape = evt.target;
document.body.style.cursor = 'pointer';
// Scale up the image on hover
shape.to({
scaleX: 1.2,
scaleY: 1.2,
duration: 0.2,
});
});
layer.on('mouseout', function (evt) {
const shape = evt.target;
document.body.style.cursor = 'default';
// Scale back to normal when mouse leaves
shape.to({
scaleX: 1,
scaleY: 1,
duration: 0.2,
});
});
import { useState, useEffect } from 'react';
import { Stage, Layer, Image } from 'react-konva';
import { useImage } from 'react-konva-utils';
const ImageWithHover = ({ src, x, y, width, height, offsetX, offsetY }) => {
const [image] = useImage(src);
const [isHovered, setIsHovered] = useState(false);
const [position, setPosition] = useState({ x, y });
const scale = isHovered ? 1.2 : 1;
return (
<Image
image={image}
x={position.x}
y={position.y}
width={width}
height={height}
offsetX={offsetX}
offsetY={offsetY}
scaleX={scale}
scaleY={scale}
draggable
onDragMove={(e) => setPosition(e.target.position())}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
/>
);
};
const App = () => {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<ImageWithHover
src="https://konvajs.org/assets/darth-vader.jpg"
x={110}
y={88}
width={200}
height={137}
offsetX={100}
offsetY={68}
/>
<ImageWithHover
src="https://konvajs.org/assets/yoda.jpg"
x={290}
y={70}
width={93}
height={104}
offsetX={46}
offsetY={52}
/>
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageConfig">
<v-layer ref="layerRef">
<v-image
v-for="(img, index) in images"
:key="index"
:config="getImageConfig(img, index)"
@mouseenter="handleMouseEnter(index)"
@mouseleave="handleMouseLeave(index)"
/>
</v-layer>
</v-stage>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue';
const stageConfig = {
width: window.innerWidth,
height: window.innerHeight
};
const layerRef = ref(null);
const hoveredIndex = ref(null);
const loadedImages = ref({});
// Define image data
const images = ref([
{
src: 'https://konvajs.org/assets/darth-vader.jpg',
x: 110,
y: 88,
width: 200,
height: 137,
offsetX: 100,
offsetY: 68,
loaded: false
},
{
src: 'https://konvajs.org/assets/yoda.jpg',
x: 290,
y: 70,
width: 93,
height: 104,
offsetX: 46,
offsetY: 52,
loaded: false
}
]);
// Load images
onMounted(() => {
images.value.forEach((img, index) => {
const imageObj = new Image();
imageObj.onload = () => {
loadedImages.value = {
...loadedImages.value,
[index]: imageObj
};
};
imageObj.src = img.src;
});
});
// Get configuration for each image
const getImageConfig = (img, index) => {
const isHovered = hoveredIndex.value === index;
const scale = isHovered ? 1.2 : 1;
return {
image: loadedImages.value[index],
x: img.x,
y: img.y,
width: img.width,
height: img.height,
offsetX: img.offsetX,
offsetY: img.offsetY,
scaleX: scale,
scaleY: scale,
draggable: true
};
};
// Mouse event handlers
const handleMouseEnter = (index) => {
hoveredIndex.value = index;
document.body.style.cursor = 'pointer';
};
const handleMouseLeave = () => {
hoveredIndex.value = null;
document.body.style.cursor = 'default';
};
</script>