如何将 DOM 图像拖放到画布中
在这个演示中,我们将展示如何将放置在画布外部的 DOM 元素拖放到舞台中。
您看到的第一张图像是一个 DOM 图像。我们可以使用 HTML5 拖放 来启用它的拖动。
如果您需要在触摸设备上为 DOM 元素启用拖放,则需要一些额外的步骤。您可以在 这里 阅读更多信息。
说明: 将尤达拖放到画布中。
- Vanilla
- React
- Vue
import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; // 添加 DOM 元素以在容器外部渲染 document.getElementById('container').insertAdjacentHTML( 'beforebegin', ` <p>将尤达拖放到灰色区域。</p> <div id="drag-items"> <img src="https://konvajs.org/assets/yoda.jpg" draggable="true" style="height: 100px; margin: 5px;" /> <img src="https://konvajs.org/assets/darth-vader.jpg" draggable="true" style="height: 100px; margin: 5px;" /> </div> ` ); // 用灰色背景样式化容器 document.getElementById('container').style.backgroundColor = 'rgba(0, 0, 0, 0.1)'; // 创建舞台和图层 const stage = new Konva.Stage({ container: 'container', width: width, height: height - 150, // 留出空间给 DOM 元素 }); const layer = new Konva.Layer(); stage.add(layer); // 跟踪拖动元素的 URL let itemURL = ''; document .getElementById('drag-items') .addEventListener('dragstart', function (e) { itemURL = e.target.src; }); // 处理容器上的 dragover const container = stage.container(); container.addEventListener('dragover', function (e) { e.preventDefault(); // 重要 - 必须阻止默认行为 }); // 处理容器上的 drop container.addEventListener('drop', function (e) { e.preventDefault(); // 手动注册指针位置,因为这是一个 DOM 事件 stage.setPointersPositions(e); // 加载图像并将其添加到图层 Konva.Image.fromURL(itemURL, function (image) { // 根据图像尺寸计算合适的大小 const img = image.image(); const maxDimension = 100; let width = img.width; let height = img.height; if (width > height) { height = (height / width) * maxDimension; width = maxDimension; } else { width = (width / height) * maxDimension; height = maxDimension; } image.size({ width: width, height: height }); layer.add(image); image.position(stage.getPointerPosition()); image.draggable(true); }); });
import { useState, useRef, useEffect } from 'react'; import { Stage, Layer, Image } from 'react-konva'; import { useImage } from 'react-konva-utils'; const DragItem = ({ src, onDragStart }) => { return ( <img src={src} draggable={true} style={{ height: '100px', margin: '5px' }} onDragStart={() => onDragStart(src)} /> ); }; const App = () => { const [images, setImages] = useState([]); const [dragImageSrc, setDragImageSrc] = useState(''); const stageRef = useRef(null); const handleDragStart = (src) => { setDragImageSrc(src); }; const handleDragOver = (e) => { e.preventDefault(); // 阻止默认行为 }; const handleDrop = (e) => { e.preventDefault(); if (!dragImageSrc || !stageRef.current) return; // 获取舞台和指针位置 const stage = stageRef.current; // 手动注册指针位置,因为这是一个 DOM 事件 stage.setPointersPositions(e); const position = stage.getPointerPosition(); // 将新图像添加到列表中 setImages([ ...images, { src: dragImageSrc, x: position.x, y: position.y, id: Date.now().toString() } ]); }; return ( <div> <p>将尤达拖放到灰色区域。</p> <div style={{ marginBottom: '10px' }}> <DragItem src="https://konvajs.org/assets/yoda.jpg" onDragStart={handleDragStart} /> <DragItem src="https://konvajs.org/assets/darth-vader.jpg" onDragStart={handleDragStart} /> </div> <div onDragOver={handleDragOver} onDrop={handleDrop} style={{ backgroundColor: 'rgba(0, 0, 0, 0.1)' }} > <Stage width={window.innerWidth} height={window.innerHeight - 150} ref={stageRef} > <Layer> {images.map((img) => ( <KonvaImage key={img.id} src={img.src} x={img.x} y={img.y} draggable /> ))} </Layer> </Stage> </div> </div> ); }; // 单独的组件,用于 Konva 图像的正确加载 const KonvaImage = ({ src, x, y, draggable }) => { const [image] = useImage(src); if (!image) return null; // 计算合适的大小 const maxDimension = 100; let width = image.width; let height = image.height; if (width > height) { height = (height / width) * maxDimension; width = maxDimension; } else { width = (width / height) * maxDimension; height = maxDimension; } return ( <Image image={image} x={x} y={y} width={width} height={height} draggable={draggable} /> ); }; export default App;
<template> <div> <p>将尤达拖放到灰色区域。</p> <div style="margin-bottom: 10px;"> <img src="https://konvajs.org/assets/yoda.jpg" draggable="true" style="height: 100px; margin: 5px;" @dragstart="handleDragStart('https://konvajs.org/assets/yoda.jpg')" /> <img src="https://konvajs.org/assets/darth-vader.jpg" draggable="true" style="height: 100px; margin: 5px;" @dragstart="handleDragStart('https://konvajs.org/assets/darth-vader.jpg')" /> </div> <div @dragover.prevent @drop="handleDrop" style="background-color: rgba(0, 0, 0, 0.1);" > <v-stage ref="stageRef" :config="stageConfig" > <v-layer> <v-image v-for="img in images" :key="img.id" :config="getImageConfig(img)" /> </v-layer> </v-stage> </div> </div> </template> <script setup> import { ref, onMounted, computed } from 'vue'; const stageConfig = { width: window.innerWidth, height: window.innerHeight - 150 }; const stageRef = ref(null); const images = ref([]); const dragImageSrc = ref(''); const loadedImages = ref({}); // 处理拖动开始,以跟踪正在拖动的图像 const handleDragStart = (src) => { dragImageSrc.value = src; }; // 处理 drop 事件,将图像添加到舞台 const handleDrop = (e) => { e.preventDefault(); if (!dragImageSrc.value || !stageRef.value) return; // 获取舞台引用并注册指针位置 const stage = stageRef.value.getNode(); stage.setPointersPositions(e); const position = stage.getPointerPosition(); // 如果尚未加载图像,则加载图像 if (!loadedImages.value[dragImageSrc.value]) { const img = new Image(); img.onload = () => { loadedImages.value = { ...loadedImages.value, [dragImageSrc.value]: img }; // 将图像添加到舞台 addImageToStage(dragImageSrc.value, position); }; img.src = dragImageSrc.value; } else { // 图像已加载,添加到舞台 addImageToStage(dragImageSrc.value, position); } }; // 辅助函数将图像添加到舞台 const addImageToStage = (src, position) => { images.value.push({ src: src, x: position.x, y: position.y, id: Date.now().toString() }); }; // 配置图像属性 const getImageConfig = (img) => { const image = loadedImages.value[img.src]; if (!image) return { x: img.x, y: img.y, draggable: true }; // 计算合适的大小 const maxDimension = 100; let width = image.width; let height = image.height; if (width > height) { height = (height / width) * maxDimension; width = maxDimension; } else { width = (width / height) * maxDimension; height = maxDimension; } return { image: image, x: img.x, y: img.y, width: width, height: height, draggable: true }; }; </script>