Drag and Drop Multiple Images with Border Highlighting
This demo shows how to implement highlighting effects with images. When hovering over an image, the border disappears, and it reappears when you move the mouse away.
Instructions: Hover over the images to hide their borders and drag them around the stage.
- Vanilla
- React
- Vue
import Konva from 'konva'; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); const layer = new Konva.Layer(); stage.add(layer); // Create Darth Vader image const darthVaderImg = new Konva.Image({ x: 20, y: 20, width: 200, height: 137, stroke: 'red', strokeWidth: 10, draggable: true, }); layer.add(darthVaderImg); // Create Yoda image const yodaImg = new Konva.Image({ x: 240, y: 20, width: 93, height: 104, draggable: true, stroke: 'red', strokeWidth: 10, }); layer.add(yodaImg); // Load Darth Vader image const imageObj1 = new Image(); imageObj1.onload = function () { darthVaderImg.image(imageObj1); layer.draw(); }; imageObj1.src = 'https://new.konvajs.org/assets/darth-vader.jpg'; // Load Yoda image const imageObj2 = new Image(); imageObj2.onload = function () { yodaImg.image(imageObj2); layer.draw(); }; imageObj2.src = 'https://new.konvajs.org/assets/yoda.jpg'; // Use event delegation to update pointer style and borders layer.on('mouseover', function (evt) { const shape = evt.target; document.body.style.cursor = 'pointer'; shape.strokeEnabled(false); layer.draw(); }); layer.on('mouseout', function (evt) { const shape = evt.target; document.body.style.cursor = 'default'; shape.strokeEnabled(true); layer.draw(); });
import { useState } from 'react'; import { Stage, Layer, Image } from 'react-konva'; import { useImage } from 'react-konva-utils'; const DraggableImage = ({ src, x, y, width, height }) => { const [image] = useImage(src); const [isHovered, setIsHovered] = useState(false); return ( <Image image={image} x={x} y={y} width={width} height={height} stroke="red" strokeWidth={10} strokeEnabled={!isHovered} draggable onMouseEnter={() => { setIsHovered(true); document.body.style.cursor = 'pointer'; }} onMouseLeave={() => { setIsHovered(false); document.body.style.cursor = 'default'; }} /> ); }; const App = () => { return ( <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> <DraggableImage src="https://new.konvajs.org/assets/darth-vader.jpg" x={20} y={20} width={200} height={137} /> <DraggableImage src="https://new.konvajs.org/assets/yoda.jpg" x={240} y={20} width={93} height={104} /> </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://new.konvajs.org/assets/darth-vader.jpg', x: 20, y: 20, width: 200, height: 137 }, { src: 'https://new.konvajs.org/assets/yoda.jpg', x: 240, y: 20, width: 93, height: 104 } ]); // 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; return { image: loadedImages.value[index], x: img.x, y: img.y, width: img.width, height: img.height, stroke: 'red', strokeWidth: 10, strokeEnabled: !isHovered, 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>