vue3 使用 konva

ops/2024/12/13 21:09:46/

1:安装 npm install vue-konva konva --save
        在main.ts 里面引入
import VueKonva from 'vue-konva';
app.use(VueKonva);
2:效果图

3:直接粘贴复制就能用你 (重要的地方做了备注)

<template><div style="display: flex; height: 100vh;"><!-- 左侧 el-tree 树形结构 --><div style="width: 300px; padding: 20px; background: #f0f0f0; border-right: 2px solid #ccc;"><h3>选择图片</h3><el-tree:data="treeData":props="treeProps"draggabledefault-expand-all@node-drag-start="onDragStart"@node-drag-end="onDragEnd"style="width: 100%;"><template #default="{ node, data }"><span>{{ data.label }}</span></template></el-tree></div><!-- 右侧 Konva 画布区域 --><div ref="stageContainer" @dragover.prevent="onDragOver" @drop.prevent="onDrop"style="flex: 1; height: 100%; background: #fafafa; padding: 20px; position: relative;"><button @click="saveCanvas">保存</button><div id="konva-container" style="width: 100%; height: 100%;background:#f0f0f0;"></div></div></div>
</template><script>
import { onMounted, ref, nextTick } from 'vue';
import Konva from 'konva';
import { ElTree } from 'element-plus';export default {components: {ElTree,},setup() {const stage = ref(null);const layer = ref(null);const draggedNode = ref(null);// 树形数据结构const treeData = ref([{id: 1,label: 'Lion',src: 'https://konvajs.org/assets/lion.png',},]);// 树的配置const treeProps = {label: 'label',children: 'children',};// 初始化 Konva stageonMounted(() => {nextTick(() => {// 这里的宽高,可以改成某个容器的宽高// stageContainer.value.clientWidth// stageContainer.value.clientHeightstage.value = new Konva.Stage({container: 'konva-container',width: window.innerWidth - 350,height: window.innerHeight,});layer.value = new Konva.Layer();stage.value.add(layer.value);// 添加右键菜单事件处理stage.value.on('contextmenu', function (e) {e.evt.preventDefault(); // 阻止默认的右键菜单const clickedItem = e.target;            if (clickedItem.hasName('image')) {console.log(clickedItem)alert("可以做一些提示,比如是否要删除,目前右键直接删除了")// 确认删除// proxy.$modal.confirm('是否确认删除该设备?').then(() => {clickedItem.destroy(); // 删除图片// 同时删除可能存在的变换器stage.value.find('Transformer').forEach((tr) => tr.destroy());layer.value.draw(); // 重绘画布// }).catch(() => {});}});// 点击事件处理stage.value.on('click', function (e) {const clickedItem = e.target;          // 移除所有现有的变换器stage.value.find('Transformer').forEach((tr) => tr.destroy());          // 如果点击的是图片,添加变换器if (clickedItem.hasName('image')) {const transformer = new Konva.Transformer({nodes: [clickedItem],boundBoxFunc: (oldBox, newBox) => {// 限制缩放和移动范围if (newBox.width < 50 || newBox.height < 50) {return oldBox;}return newBox;}});layer.value.add(transformer);}          layer.value.draw();});});});// 拖拽开始时记录节点信息const onDragStart = (event, nodeData) => {draggedNode.value = nodeData;};// 拖拽结束const onDragEnd = () => {draggedNode.value = null;};// 拖拽悬停处理const onDragOver = (event) => {event.preventDefault();};// 拖放处理const onDrop = (event) => {event.preventDefault();if (draggedNode.value) {// 获取相对于 Konva 容器的准确坐标const container = document.getElementById('konva-container');const containerRect = container.getBoundingClientRect();// 这里减50是因为宽是100,减去50为了让图片在鼠标中间// 高同理const x = event.clientX - containerRect.left-50;const y = event.clientY - containerRect.top-50;addImageToCanvas("https://konvajs.org/assets/lion.png", x, y);}};// 将图片添加到 Konva 画布const addImageToCanvas = (imageUrl, x, y) => {const imageObj = new Image();imageObj.src = imageUrl;imageObj.onload = () => {const konvaImage = new Konva.Image({image: imageObj,x: x,y: y,// 自定义字段attrs: { device: "2", adad: "2131", yrr: "2313" },// 默认的宽高width: 100,height: 100,draggable: true,name: 'image',dragBoundFunc: function(pos) {const container = stage.value.container();const containerRect = container.getBoundingClientRect();const minX = 0;const minY = 0;const maxX = containerRect.width - 100;  // 减去默认设置的宽const maxY = containerRect.height - 100; // 减去默认设置的高return {x: Math.max(minX, Math.min(pos.x, maxX)),y: Math.max(minY, Math.min(pos.y, maxY))};}});layer.value.add(konvaImage);layer.value.draw();};};const saveCanvas =async () => {if (!stage.value) return;const images = layer.value.find('Image');const layoutData = images.map(image => {return { pointx: image.x(),pointy: image.y(),width: image.scaleX() * image.width(),height: image.scaleY() * image.height(),rotation: image.rotation()};});console.log(layoutData)try {alert('保存成功');} catch (error) {alert('保存失败');}};return {treeData,treeProps,onDragStart,onDragEnd,onDragOver,onDrop,saveCanvas};},
};
</script><style scoped>
#konva-container {border: 2px dashed #ccc;
}
</style>


http://www.ppmy.cn/ops/141634.html

相关文章

调度系统:使用 Apache Airflow 管理和调度 Couchbase SQL 脚本的实际例子

假设场景如下&#xff1a; 每天定时执行一组 Couchbase SQL 脚本&#xff0c;用于数据同步、聚合和清洗。 脚本包括&#xff1a; 同步数据到 Couchbase 集群。 执行数据聚合查询。 清理过期数据。 要求&#xff1a; 支持任务依赖管理。 提供任务失败后的重试机制。 支…

Python+OpenCV系列:图像的几何变换

Python OpenCV 系列&#xff1a;图像的几何变换 引言 在图像处理领域&#xff0c;几何变换是一个非常重要的操作&#xff0c;它可以改变图像的位置、大小、方向或形状。在计算机视觉中&#xff0c;这些操作对于图像预处理、特征提取和图像增强至关重要。本文将介绍如何利用 …

HTML简单贪吃蛇游戏

1.功能说明&#xff1a; 游戏网格&#xff1a;一个20x20的网格&#xff0c;每个格子的大小为20x20像素。 蛇的移动&#xff1a;玩家可以通过方向键&#xff08;左、上、右、下&#xff09;控制蛇的移动。 食物生成&#xff1a;食物会在随机位置生成&#xff0c;当蛇吃到食物时…

CentOS8或docker镜像centos8更换镜像源

因为 CentOS 8 已经结束生命周期&#xff0c;原来的镜像源不可用了。我们需要将镜像源改为 CentOS 8 的替代源。 在容器中运行以下命令&#xff1a; 首先备份原有的源 cd /etc/yum.repos.d/ mkdir backup mv *.repo backup/ 创建新的源文件 cat > /etc/yum.repos.d/Cent…

npm淘宝镜像证书过期

前言 使用 npm 报错&#xff1a; npm ERR! request to https://registry.npm.taobao.org/xxx failed, reason: certificate has expired 错误原因&#xff1a; 早在 2021 年&#xff0c;淘宝就发文称&#xff0c;npm 淘宝镜像已经从 http://registry.npm.taobao.org 切换到了 h…

Linux 常用命令大全:文件管理、系统信息、网络操作

Linux 系统提供了丰富的命令行工具&#xff0c;用于各种操作和管理任务。以下是一些常用的 Linux 命令及其简要说明&#xff1a; 文件和目录操作 ls - 列出目录内容 ls -l /path/to/directorycd - 更改目录 cd /path/to/directorypwd - 显示当前工作目录 pwdmkdir - 创建目录 …

设置笔记本同时连接内外网

原理&#xff1a;通过笔记本和手机相连&#xff0c;实现双网卡功能能。笔记本连接内网wifi、同时手机端开启usb网络共享&#xff0c;笔记本就有了两个网&#xff0c;然配置那个访问外网&#xff0c;那个访问内网。 1.笔记本wifi连接内网wifi 2.手机端共享网络。 手机打开 -【…

Android系统(android app和系统架构)

文章目录 AndroidAndroid Apps四大组件 Android系统Platform API之下&#xff1a;一个微笑内核adb(Android Debug Bridge) Android包管理机制Android的Intent机制参考 Android LinuxFrameworkJVM 在Linux/Java上做了个二次开发&#xff1f;并不完全是&#xff1a;Android定义…