手写视频裁剪框

news2024/9/24 9:25:37

在这里插入图片描述

     <!-- 截取框 -->
                <div
                  v-show="isShow"
                  class="crop-box"
                  :style="{
                    width: cropWidth + 'px',
                    height: cropHeight + 'px',
                    left: cropX + 'px',
                    top: cropY + 'px',
                  }"
                  ref="cropBox"
                  @mousedown="startInteraction"
                >
                  <!-- 内容在这里 -->
                  <div class="crop-box-content"></div>
                  <div
                    @mousedown="dd"
                    data-v-23936b6b=""
                    data-action="se"
                    class="east-south-side"
                  ></div>
                </div>

js

  startInteraction(e) {
      const box = this.$refs.cropBox;
      const boxRect = box.getBoundingClientRect();
      const mouseX = e.clientX - boxRect.left;
      const mouseY = e.clientY - boxRect.top;

      if (mouseX <= this.resizeHandleSize && mouseY <= this.resizeHandleSize) {
        this.resizeDirection = "tl";
      } else if (
        mouseX >= boxRect.width - this.resizeHandleSize &&
        mouseY <= this.resizeHandleSize
      ) {
        this.resizeDirection = "tr";
      } else if (
        mouseX >= boxRect.width - this.resizeHandleSize - 20 &&
        mouseY >= boxRect.height - this.resizeHandleSize - 20
      ) {
        this.resizeDirection = "br";
      } else if (
        mouseX <= this.resizeHandleSize &&
        mouseY >= boxRect.height - this.resizeHandleSize
      ) {
        this.resizeDirection = "bl";
      } else {
        this.resizeDirection = null;
        this.startDragging(e);
        return;
      }

      this.startX = e.clientX;
      this.startY = e.clientY;
      this.startWidth = this.cropWidth;
      this.startHeight = this.cropHeight;
      this.startCropX = this.cropX;
      this.startCropY = this.cropY;
      this.isResizing = true;

      document.addEventListener("mousemove", this.handleResize);
      document.addEventListener("mouseup", this.stopInteraction);
    },
    startDragging(e) {
      this.startX = e.clientX;
      this.startY = e.clientY;
      this.startCropX = this.cropX;
      this.startCropY = this.cropY;
      this.isDragging = true;

      document.addEventListener("mousemove", this.handleDrag);
      document.addEventListener("mouseup", this.stopInteraction);
    },
    handleResize(e) {
      if (this.isResizing) {
        const deltaX = e.clientX - this.startX;
        const deltaY = e.clientY - this.startY;
        let newWidth, newHeight;

        switch (this.resizeDirection) {
          case "tl":
            return;
            newWidth = this.startWidth - deltaX;
            newHeight = this.calculateHeight(newWidth);
            this.cropX = this.startCropX + deltaX;
            this.cropY = this.startCropY + deltaY;
            break;
          case "tr":
            return;

            newWidth = this.startWidth + deltaX;
            newHeight = this.calculateHeight(newWidth);
            this.cropY = this.startCropY + deltaY;
            break;
          case "br":
            newWidth = this.startWidth + deltaX;
            // newHeight = this.calculateHeight(newWidth);
            newHeight = (newWidth * 16) / 9;
            break;
          case "bl":
            return;

            newWidth = this.startWidth - deltaX;
            newHeight = this.calculateHeight(newWidth);
            this.cropX = this.startCropX + deltaX;
            break;
          default:
            break;
        }

        this.cropWidth = Math.max(newWidth, 50); // 最小宽度
        this.cropHeight = Math.max(newHeight, 50); // 最小高度

        // 检查是否超出父容器范围
        const cropper = this.$refs.videoAndCropper;
        // console.log(
        // "🚀 ~ file: index02.vue:1687 ~ handleResize ~ cropper:",
        // cropper.offsetHeight
        // );
        const parentRect = this.$el.getBoundingClientRect();
        // // console.log("🚀 ~ file: index02.vue:1687 ~ handleResize ~ parentRect:", parentRect)

        if (this.cropY + this.cropHeight > cropper.offsetHeight) {
          this.cropHeight = cropper.offsetHeight;
        }

        if (this.cropHeight == cropper.offsetHeight) {
          this.cropWidth = (this.cropHeight / 16) * 9;
        }

        //  if (this.cropX + this.cropWidth > parentRect.width) {
        //   this.cropWidth = parentRect.width - this.cropX;
        // }
      }
    },

   handleDrag(e) {
      // 通过$refs获取元素引用
      const element = this.$refs.videoAndCropper;

      // 获取元素的高度和宽度
      const height = element.clientHeight; // 获取元素内部高度,包括内边距,不包括边框
      const width = element.clientWidth; // 获取元素内部宽度,包括内边距,不包括边框

      if (this.isDragging) {
        const deltaX = e.clientX - this.startX;
        const deltaY = e.clientY - this.startY;

        // 计算新的位置
        const newCropX = this.startCropX + deltaX;
        const newCropY = this.startCropY + deltaY;
        // console.log(
        // "🚀 ~ file: index02.vue:1677 ~ handleDrag ~ newCropY:",
        // newCropY + this.cropHeight
        // );
        // 检查是否超出父容器范围
        const parentRect = this.$el.getBoundingClientRect();
        // console.log(
        // "🚀 ~ file: index02.vue:1651 ~ handleResize ~ parentRect:",
        // parentRect
        // );
        // console.log(
        // "🚀 ~ file: index02.vue:1694 ~ handleDrag ~ height:",
        // height
        // );

        if (newCropX >= 0 && newCropX + this.cropWidth <= parentRect.width) {
          this.cropX = newCropX;
        }
        if (newCropY >= 0 && newCropY + this.cropHeight <= parentRect.height) {
          this.cropY = newCropY;
        }

        //    if (newCropY + this.cropHeight >= height) {
        //     console.log(3333);
        //   return;
        // }

        if (newCropX + this.cropWidth >= width) {
          this.cropX = width - this.cropWidth;
        }

        if (newCropY + this.cropHeight >= height) {
          this.cropY = height - this.cropHeight;
        }
      }
    },
    stopInteraction() {
      this.isResizing = false;
      this.isDragging = false;
      this.resizeDirection = null;
      document.removeEventListener("mousemove", this.handleResize);
      document.removeEventListener("mousemove", this.handleDrag);
      document.removeEventListener("mouseup", this.stopInteraction);
    },

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

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

相关文章

【信息论与编码】习题-单选题

目录 单选题1.下列说法正确的是&#xff08;B&#xff09;2.在信息论中&#xff0c;若用对数底2为&#xff0c;则信息量的单位为&#xff08;C&#xff09;3.率失真函数的下限为&#xff08;A&#xff09;4.给定xi条件下随机事件yj所包含的不确定度和条件自信息量p(yj /xi)。&a…

stable diffusion 人物高级提示词(二)衣物、身材

一、衣服大类 英文中文Shirt衬衫Blouse女式衬衫Dress连衣裙Skirt裙子Pants裤子Jeans牛仔裤Swimsuit泳衣Underwear内衣Bra文胸Panties内裤Stockings长筒袜Shoes鞋子Socks袜子 二、细分分类 dress 是连衣裙&#xff1a; 英文解释Formal Dress正式礼服&#xff0c;通常用于正式…

代码随想录刷题第三十八天| 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

代码随想录刷题第三十八天 动态规划基础理论 斐波那契数 (LC 509) 题目思路&#xff1a; 代码实现&#xff1a; class Solution:def fib(self, n: int) -> int:if n<1: return ndp [0 for _ in range(n1)]dp[1] 1for i in range(2, n1):dp[i] dp[i-1]dp[i-2] …

专业课130+,总分390+四川大学951信号与系统考研通信,电子信息经验分享

今年专业课130&#xff0c;总分390&#xff0c;顺利上岸&#xff0c;将近一年复习一路走来&#xff0c;感慨很多&#xff0c;希望以下经历可以给后来的同学提供一些参考。 初试备考经验 公共课&#xff1a;三门公共课&#xff0c;政治&#xff0c;英语&#xff0c;数学。在备…

软件测试|SQL TOP提取顶部数据该如何使用?

简介 在SQL查询语言中&#xff0c;TOP子句是一个非常有用的功能&#xff0c;它允许我们从数据库中提取指定数量的顶部数据记录。本文将深入探讨SQL TOP子句的使用方法&#xff0c;以及在实际应用中的一些常见场景和技巧。 SQL TOP SQL是一种用于管理和操作关系型数据库的强大…

16 Linux 内核定时器

一、Linux 时间管理和内核定时器简介 1. 内核时间管理简介 Linux 内核中有大量的函数需要时间管理&#xff0c;比如周期性的调度程序、延时程序、定时器等。 硬件定时器提供时钟源&#xff0c;时钟源的频率可以设置&#xff0c;设置好以后就周期性的产生定时中断&#xff0c;系…

提升图像分割精度:学习UNet++算法

文章目录 一、UNet 算法简介1.1 什么是 UNet 算法1.2 UNet 的优缺点1.3 UNet 在图像分割领域的应用 二、准备工作2.1 Python 环境配置2.2 相关库的安装 三、数据处理3.1 数据的获取与预处理3.2 数据的可视化与分析 四、网络结构4.1 UNet 的网络结构4.2 UNet 各层的作用 五、训练…

04、Kafka ------ CMAK 各个功能的作用解释(Cluster、集群、Broker、位移主题、复制因子、领导者副本、主题)

目录 启动命令&#xff1a;CMAK的用法★ 在CMAK中添加 Cluster★ 在CMAK中查看指定集群★ 在CMAK中查看 Broker★ 位移主题★ 复制因子★ 领导者副本和追随者副本★ 查看主题 启动命令&#xff1a; 1、启动 zookeeper 服务器端 小黑窗输入命令&#xff1a; zkServer 2、启动 …

编写一个弹跳小球的程序,小球在窗口中四处反弹(python)

import pygame import random# 初始化Pygame pygame.init()# 窗口尺寸 width 800 height 600# 创建窗口 screen pygame.display.set_mode((width, height)) pygame.display.set_caption("Bouncing Ball")# 小球初始位置和速度 ball_radius 20 ball_color (255, …

【kettle】pdi/data-integration 打开ktr文件报错“Unable to load step info from XML“

一、报错内容&#xff1a; Unable to load step info from XML step nodeorg.pentaho.di.core.exception.KettleXMLException: Unable to load step info from XMLat org.pentaho.commons.launcher.Launcher.main (Launcher.java:92)at java.lang.reflect.Method.invoke (Met…

【ARMv8架构系统安装PySide2】

ARMv8架构系统安装PySide2 Step1. 下载Qt资源包Step2. 配置和安装Qt5Step3. 检查Qt-5.15.2安装情况Step4. 安装PySide2所需的依赖库Step5. 下载和配置PySide2Step6. 检验PySide2是否安装成功 Step1. 下载Qt资源包 if you need the whole Qt5 (~900MB): wget http://master.qt…

数据结构(JS实现)

目录 链表链表的特点链表中的常见操作单链表append(data)尾部追加新节点toString()输出链表的节点数据插入节点insert(position,data)get(position)获取链表指定位置节点的数据indexOf(data)查找对应数据节点的位置update(position, newData)更新指定位置节点数据removeAt(posi…

Unity | NGO网络框架

目录 一、相关属性及变量 1.ServerRpc属性 2.ClientRpc属性 3.NetworkVariable变量 二、相关组件 1.NetworkManager 2.Unity Transport 3.Network Object 4.NetworkBehaviour&#xff1a; 5.NetworkTransform Syncing(Synchronizing) Thresholds Interpolation 三…

windows通过ssh连接Liunx服务器并实现上传下载文件

连接ssh 输入&#xff1a;ssh空格用户名ip地址&#xff0c;然后按Enter 有可能出现下图提示&#xff0c;输入yes 回车即可 输入 password &#xff0c;注意密码是不显示的&#xff0c;输入完&#xff0c;再按回车就行了 以上是端口默认22情况下ssh连接&#xff0c;有些公司它…

【VSCode】CMake Language Support 总是下载 .NET 超时,但又不想升级dotnet

错误信息 Error: Could not resolve dotnet path!An error occurred while installing .NET (6.0): .NET Acquisition Failed: Installation failed: Error: .NET installation timed out. You may need to change the timeout time if you have a slow connection. Please se…

VuePress部署到GitHub Pages

一、git push自动部署 1、创建用于工作流的文件 在项目根目录下创建一个用于 GitHub Actions 的工作流 .yml 文件 name: docson:# 每当 push 到 main 分支时触发部署push:branches: [main]# 手动触发部署workflow_dispatch:jobs:docs:runs-on: ubuntu-lateststeps:- uses: a…

湖仓架构的演进

1.数据仓库架构的历史演进 起初&#xff0c;业界数据处理首选方式是数仓架构。通常数据处理的流程是把一些业务数据库&#xff0c;通过ETL的方式加载到Data Warehouse中&#xff0c;再在前端接入一些报表或者BI的工具去展示。 数据仓库概念是 Inmon 于 1990 年提出并给出了完…

Spark Streaming的容错性与高可用性

在实时数据处理领域&#xff0c;容错性和高可用性是至关重要的。Apache Spark Streaming是一个强大的工具&#xff0c;用于实时数据处理和分析&#xff0c;具备卓越的容错性和高可用性。本文将深入探讨Spark Streaming的容错性机制&#xff0c;以及如何实现高可用性的实时数据处…

docker 部署haproxy cpu占用特别高

在部署mysql 主主高可用时&#xff0c;使用haproxy进行负载&#xff0c;在服务部使用的情况下发现服务器cpu占比高&#xff0c;负载也高&#xff0c;因此急需解决这个问题。 1.解决前现状 1.1 部署配置文件 cat > haproxy.cfg << EOF globalmaxconn 4000nbthrea…

【FPGA/verilog -入门学习16】fpga状态机实现

需求&#xff1a; 用两段式状态机设计序列码检测机。这个序列码检测机用于检索连续输入的 1bit 数据 &#xff08;每个时钟周期输入 1bit&#xff09;&#xff0c;当检测到一串“101100”的输入数据时&#xff0c;产生一个时钟周期的 高脉冲指示信号 状态图 //实现状态机切…