Konva框选移动

news2024/11/27 22:34:03

效果,可以单独点击控制大小,也可框选控制

代码:

<template>
  <div class="rect">
    <div id="canvas"></div> <!-- 画布容器 -->
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'; // 导入 Vue 的 onMounted 钩子
import Konva from 'konva'; // 导入 Konva 图形库

// 声明 stage、layer 和 transformer
let stage: Konva.Stage | null = null; // 初始化 stage 为 null
const layer: Konva.Layer = new Konva.Layer(); // 创建一个新的图层
const tr: Konva.Transformer = new Konva.Transformer(); // 创建一个 Transformer 用于选中和调整形状

// 在组件挂载后初始化
onMounted(() => {
  init(); // 调用初始化函数
});

const init = () => {
  const el = document.getElementById("canvas"); // 获取画布 DOM 元素
  if (!el) {
    return; // 如果没有找到画布元素,结束函数
  }

  const { clientWidth, clientHeight } = el; // 获取画布的宽度和高度

  // 创建一个 Konva Stage 平台
  stage = new Konva.Stage({
    container: 'canvas', // 指定画布容器
    width: clientWidth, // 设置宽度
    height: clientHeight, // 设置高度
  });

  stage.add(layer); // 将层添加到舞台

  // 创建第一个矩形
  const rect1 = new Konva.Rect({
    name: "rect", // 给图形添加名称
    x: clientWidth / 2 - 100, // 设置 x 坐标
    y: clientHeight / 2, // 设置 y 坐标
    width: 200, // 矩形的宽度
    height: 100, // 矩形的高度
    fill: "#ff8800", // 填充颜色
    stroke: 'black', // 边框颜色
    strokeWidth: 1, // 边框宽度
    draggable: true, // 设置可拖拽
  });
  layer.add(rect1); // 将第一个矩形添加到图层

  // 创建第二个矩形
  const rect2 = new Konva.Rect({
    name: "rect", // 同样的名称,可能导致选择问题
    x: clientWidth / 2 + 100, // 设置 x 坐标
    y: clientHeight / 2, // 设置 y 坐标
    width: 200, // 矩形的宽度
    height: 100, // 矩形的高度
    fill: "#ff00ff", // 填充颜色
    stroke: 'black', // 边框颜色
    strokeWidth: 1, // 边框宽度
    draggable: true, // 设置可拖拽
  });
  layer.add(rect2); // 将第二个矩形添加到图层

  // 新增一个矩形用于框选功能
  const selectionRect = new Konva.Rect({
    fill: "rgba(0,0,255,0.1)", // 填充颜色
    visible: false, // 初始时隐藏
    stroke: "rgba(0,0,255,0.5)", // 边框颜色
    strokeWidth: 1, // 边框宽度
  });
  layer.add(selectionRect); // 将选择矩形添加到图层

  layer.add(tr); // 将 Transformer 添加到图层

  // 点击图形时进行编辑,点击画布则取消编辑
  stage.on("click tap", (e) => {
    const dom = e.target; // 获取点击的目标
    if (dom.getType() === "Shape") { // 判断目标是否为形状
      tr.nodes([dom]); // 选中该形状
    } else {
      tr.nodes([]); // 如果点击的是画布,则清空选中
    }
  });

  let x1 = 0, y1 = 0, x2 = 0, y2 = 0; // 初始化坐标变量

  // 鼠标按下时开始框选
  stage.on("mousedown touchstart", (e) => {
    if (e.target !== stage) { // 如果点击的不是画布
      return; // 结束函数
    }
    e.evt.preventDefault(); // 阻止默认行为

    // 获取鼠标位置
    const { x, y } = stage.getPointerPosition() as Konva.Vector2d;
    x1 = x; // 记录起始点 x 坐标
    x2 = x; // 记录起始点 x 坐标
    y1 = y; // 记录起始点 y 坐标
    y2 = y; // 记录起始点 y 坐标
    selectionRect.visible(true); // 显示选择框
    selectionRect.width(0); // 初始化宽度为 0
    selectionRect.height(0); // 初始化高度为 0
  });

  // 鼠标移动时更新选择框
  stage.on("mousemove touchmove", (e) => {
    if (!selectionRect.visible()) { // 如果选择框不可见
      return; // 结束函数
    }
    const { x, y } = stage.getPointerPosition() as Konva.Vector2d; // 获取当前鼠标位置
    x2 = x; // 更新结束点 x 坐标
    y2 = y; // 更新结束点 y 坐标

    // 更新选择矩形的属性
    selectionRect.setAttrs({
      x: Math.min(x1, x2), // 设置选择框的 x 坐标
      y: Math.min(y1, y2), // 设置选择框的 y 坐标
      width: Math.abs(x1 - x2), // 设置选择框的宽度
      height: Math.abs(y1 - y2), // 设置选择框的高度
    });
  });

  // 鼠标松开时完成选择
  stage.on("mouseup touchend", (e) => {
    if (!stage || !selectionRect.visible()) { // 如果舞台不存在或选择框不可见
      return; // 结束函数
    }

    // 隐藏选择框
    selectionRect.visible(false);

    // 获取所有矩形形状并进行选择
    const shapes = stage.find(".rect"); // 查找所有矩形
    const box = selectionRect.getClientRect(); // 获取选择框的边界
    const selected = shapes.filter((shape) =>
      Konva.Util.haveIntersection(box, shape.getClientRect()) // 判断是否与选择框相交
    );
    tr.nodes(selected); // 将选中的形状传给 Transformer
  });
}
</script>

<style scoped lang="scss">
.rect {
  padding: 20px; // 设置外边距

  #canvas {
    background-color: #eee; // 设置背景颜色
    border: 1px solid #666; // 设置边框
    height: calc(100vh - 42px); // 设置画布高度
  }
}
</style>

 逻辑过程

逻辑步骤说明

  1. 创建画布容器 - 在模板中定义画布的容器。
  2. 导入 Vue 和 Konva - 引入所需的库和模块。
  3. 初始化变量 - 创建舞台、层和变换器的实例。
  4. 挂载后初始化 - 在组件挂载时调用初始化函数。
  5. 获取 DOM 元素 - 获取画布的 DOM 元素,准备进行绘制。
  6. 创建舞台 - 创建 Konva 的舞台实例,并设置画布的尺寸。
  7. 添加层到舞台 - 将图层添加到舞台,以便在其上绘制图形。
  8. 创建矩形 - 依次创建第一个和第二个矩形,并设置其属性。
  9. 添加矩形到层 - 将创建的矩形添加到图层。
  10. 创建选择矩形 - 创建一个用于框选的矩形,但初始时设置为不可见。
  11. 处理点击事件 - 为舞台添加点击事件,以便选择图形或清空选择。
  12. 鼠标事件处理 - 处理鼠标按下、移动和松开事件以实现框选功能。
  13. 更新选择框 - 在鼠标移动时更新选择框的位置和大小。
  14. 完成选择 - 在鼠标松开时,计算选择的矩形,并将其传递给变换器。
  15. 样式设置 - 最后设置样式,定义画布的外观

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2222643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JVM】—G1 GC日志详解

G1 GC日志详解 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; 文章目录 G1 GC日志详解1 G1 GC周期2 G1日…

老牌Trans也放量灌水中?年刊文量1000+,网友分享3个月可录,0版面费!

【SciencePub学术】今天给大家推荐的是一本计算机领域的SCI—《IEEE TRANSACTIONS ON ELECTRON DEVICES》&#xff0c;IEEE-Trans系列&#xff0c;虽然常年只能位居2区&#xff0c;不过投稿难度相对较低&#xff0c;所以还是深受大家喜爱的。 期刊概况 IF&#xff1a;2.9 分…

【计算机网络 - 基础问题】每日 3 题(五十四)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

Spring事务的七种传播行为

Spring事务的七种传播行为 1.事务的传播行为是什么&#xff1f;2.具体传播行为2.1 REQUIRED &#xff0c;默认&#xff0c;存在事务则加入该事务&#xff0c;不存在则新建一个事务2.2 REQUIRES_NEW&#xff0c;每次新开启事务&#xff0c;新老事务相互独立2.3 NESTED&#xff0…

ArcGIS无插件加载(无偏移)在线天地图高清影像与街道地图指南

在地理信息系统&#xff08;GIS&#xff09;的应用中&#xff0c;加载高清影像与街道地图对于地图制图、影像查阅、空间数据分析等工作至关重要。天地图作为官方出品的地图服务&#xff0c;以其标准的数据、较快的影像更新速度等特点受到广泛欢迎。以下是如何在ArcGIS中无插件加…

创建项目模版

一 Vite创建Vue3项目 1.1.创建Vue3项目 1.1.1.运行创建项目命令 # 使用 npm npm create vitelatest 1.1.2、填写项目名称 1.1.3、选择前端框架 1.1.4、选择语法类型 1.1.5、按提示运行代码 1.1.6浏览器问 localhost:5173 预览 1.2项目结构 1.2.1vite.config.ts 1.2.2 pac…

【股票】——1-50篇,第一本

一、背景 偶然间在朋友圈看到了雪球花甲老头的公众号&#xff0c;里面的宏观观点和微观观点讲的都太好了&#xff1b;因为作者有那样的经历&#xff0c;所以才能写出来那样的内容&#xff1b;关于股市的&#xff0c;总共500篇&#xff0c;自己也计划系统性的看一看&#xff1b;…

MissingSemester-版本控制系统Git

title: Git的底层及基础使用 date: 2024-05-16 12:00:00 categories: MissingSemester tags: 版本控制系统Git 版本控制系统Git 什么是Git ​ 版本控制系统 (VCSs) 是一类用于追踪源代码&#xff08;或其他文件、文件夹&#xff09;改动的工具。顾名思义&#xff0c;这些工具…

2024年第九期 | CCF ODC《开源战略动态月报》

点击蓝字 关注我们 CCF Opensource Development Committee 导 读 2024年第九期CCF ODC《开源战略动态月报》共摘选33篇文章&#xff0c;分为8个版块&#xff1a;ODC专栏、开源政策、理论观点、产业动态、技术项目、开源组织与机构、开源报告通讯会议以及RISC-V专栏&#xff0c;…

Webserver(1)Linux开发环境搭建

目录 配置软件虚拟机中安装ubuntu安装ubuntu18的操作系统 安装VM tools安装XshellVscode远程连接到虚拟机 配置软件 VMwareVScodeg安装ubuntu 18.04.iso 或者镜像版本 XShellXFTP 虚拟机中安装ubuntu 安装ubuntu18的操作系统 开启虚拟机 选择中文简体 安装VM tools 打开v…

V2X介绍

文章目录 什么是V2XV2X的发展史早期的DSRC后起之秀C-V2XC-V2X 和DSRC 两者的对比 什么是V2X 所谓V2X&#xff0c;与流行的B2B、B2C如出一辙&#xff0c;意为vehicle to everything&#xff0c;即车对外界的信息交换。车联网通过整合全球定位系统&#xff08;GPS&#xff09;导…

Java基础-注解机制详解

文章目录 注解基础Java内置注解内置注解- Override内置注解 - Deprecated内置注解 - SuppressWarnings 元注解元注解 - Target元注解 - Retention & RetentionTarget元注解 - Documented元注解 - Inherited 注解与反射接口自定义注解 深入理解注解Java8提供了哪些新的注解&…

如何高效集成聚水潭数据至MySQL-技术案例解析

如何高效集成聚水潭数据至MySQL-技术案例解析 聚水潭数据集成到MySQL的技术案例分享 在本次技术案例中&#xff0c;我们将探讨如何通过轻易云数据集成平台&#xff0c;将聚水潭的店铺信息高效地集成到MySQL数据库中。具体方案为“聚水潭-店铺信息查询-->BI崛起-店铺信息表”…

NewStarCTF 2023 公开赛道 Web week1-week2

目录 week1 泄漏的秘密 Begin of Upload Begin of HTTP ErrorFlask ​Begin of PHP R!C!E! EasyLogin ​week2 游戏高手 include 0。0 ez_sql ​Unserialize&#xff1f; Upload again! R!!C!!E!! week1 泄漏的秘密 使用ctf-scan.py&#xff08;https://gith…

随身 WiFi 通过 USB 连接路由器共享网络 扩展网络覆盖范围

本文首发于只抄博客&#xff0c;欢迎点击原文链接了解更多内容。 前言 之前几期随身 WiFi 的玩法都是关于骁龙 410 板子的随身 WiFi&#xff0c;可以刷 Debian 之后作为小型家庭服务器&#xff0c;跑跑 Docker&#xff0c;当当打印服务器什么的。而今天介绍的玩法用的是正儿八…

LockBit多版本简单对比

LockBit家族介绍 LockBit是一种非常知名且活跃的勒索软件家族&#xff0c;自2019年首次被发现以来&#xff0c;已经经历了多个版本的演变。它以其高效的加密速度和自动化攻击能力而闻名&#xff0c;对各类组织构成了严重威胁。 发展时间线如下&#xff1a; 时间 事件 2019年…

linux之网络子系统-路由子系统(3)路由表

一、路由表 linux 路由子系统代码量虽说不是很多&#xff0c;但是难度还是有的&#xff0c;最近在分析路由子系统这一块&#xff0c;对它的框架有了基本的了解。 路由子系统可以划分为三个部分&#xff1a;路由缓存、路由策略、路由表。前两个部分已经分析完&#xff0c;这里…

解决Vmware自动调整分辨率的问题

打开菜单&#xff1a;虚拟机→设置→硬件→显示器→显示缩放比例→勾选拉伸模式 Virtual Machine

【Linux】————磁盘与文件系统

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux 创作时间 &#xff1a;2024年10月17日 一、磁盘的物理结构 磁盘的物理结构如图所示&#xff1a; 其中具体的物理存储结构如下&#xff1a; 磁盘中存储的基本单位为扇区&#xff0c;一个扇区的大小一般为512字…

【python爬虫实战】爬取全年天气数据并做数据可视化分析!附源码

由于篇幅限制&#xff0c;无法展示完整代码&#xff0c;需要的朋友可在下方获取&#xff01;100%免费。 一、主题式网络爬虫设计方案 1. 主题式网络爬虫名称&#xff1a;天气预报爬取数据与可视化数据 2. 主题式网络爬虫爬取的内容与数据特征分析&#xff1a; - 爬取内容&am…