图形编辑器:拖拽阻塞优化

news2024/9/29 18:13:36

大家好,我是前端西瓜哥。在图形编辑器中,想象这么一个场景,我们撤销了一些重要的操作,然后想选中一个图形,看看它的属性。你点了上去,然后你发现你再也无法重做了。

你以为你点了一下,但其实你点击的时候,鼠标还是小小移动了一点,飘了一个像素点。对编辑器来说,它识别到让图形移动一个像素点的操作,就生成了一个新的版本,然后重做栈(redoStack)被清空了,你退回前的操作就没了。

为了解决这类用户微小操作的问题,我们可以巧妙地给拖拽行为加一个 阻塞阈值。具体就是就是按下鼠标后,移动鼠标的距离要大于某个值,我们才认为发生了拖拽,并执行对应工具的逻辑。

下面为我们要实现的效果。此处为了更好地演示效果,将阈值设置得很大。通常设置个 4px 就够了。

可以看到,按下鼠标然后移动,如果移动的位移太小,矩形是不会被移动的,直到达到一定位移阈值后,矩形才会乖乖听话跟随鼠标进行移动

阈值表示位移距离,使用的是视口坐标系,而不是场景坐标系。

代码改造

原来的逻辑:

let isPressing = false;
let currentTool = null; // 当前工具对象

// 鼠标按下
function handleDown(e) {
  isPressing = true;
  currentTool.start(e);
}

// 鼠标移动
function handleMove(e) {
  if (isPressing) {
    currentTool.drag(e);
  } else {
    // 非拖拽的移动事件
    // 比如选择工具停留在图形上,图形要高亮,此时没发生拖拽
    currentTool.move(e);
  }
}

// 鼠标释放
function handleUp(e) {
  currentTool.end(e);
  isPressing = false;
}

鼠标按下时,isPressing 设置为 true,表示发生了鼠标按下事件。

此时鼠标再移动,我们就能知道这是一个 “拖拽” 的行为,即按下鼠标不放然后移动鼠标的行为。此时调用工具对象的 drag 方法。

最后鼠标释放,将状态 isPressing 重置。

现在我们进行改造。

let isPressing = false;
let currentTool = null; // 当前工具对象

let isEnableDragging = false; // 是否调用工具对象的 drag 方法
let startPos = null; // 保存鼠标按下时的坐标
const blockStep = 4; // 阈值

function handleDown(e) {
  isPressing = true;
  isEnableDragging = false;
  startPos = { x: e.clientX, y: e.clientY };
  currentTool.start(e);
}

function handleMove(e) {
  // 判断位移是否突破阈值,是的话更新状态为 “可拖拽”
  if (
    !isEnableDragging &&
    (Math.abs(e.clientX - startPos.x) > blockStep ||
      Math.abs(e.clientX - startPos.x) > blockStep)
  ) {
    isEnableDragging = true;
  }
  if (isPressing) {
    if (isEnableDragging) {
      // “可拖拽” 状态,调用工具的 drag 方法
      currentTool.drag(e);
    }
  } else {
    currentTool.move(e);
  }
}

function handleUp(e) {
  currentTool.end(e);

  // 初始化状态
  isPressing = false;
  isEnableDragging = false;
  startPos = null;
}

核心思路是引入 isEnableDragging 状态,表示鼠标移动时,是否达到移动的条件。

我们在鼠标移动事件中,计算鼠标按下和鼠标移动之间的距离是否超过某个值,如果超过阈值,就将 isEnableDragging 状态转换为 true。

然后判断 isEnableDragging 为 true,就调用工具对象的 drag 方法。

需要注意的是,不要只用位移距离来判断是否可以拖拽,要配合状态。否则突破阈值后,又移动回来,你会发现你又卡住了,因为此时阈值因为再次计算,没能达到阈值。

所以加了个 isEnableDragging 状态,在第一次突破阈值设置为 true 后,就再也不用计算位移了,之后一直都是可拖拽状态,直到鼠标释放重置状态。

结尾

拖拽阻塞是开发图形编辑器的一点小细节,并不复杂,但能带来很好的用户体验。

我是前端西瓜哥,欢迎关注我,学习更多前端知识。

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

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

相关文章

Java知识复习(七)常见的设计模式(装饰、代理、观察、策略、建造)

前言 参考书籍:《秒懂设计模式》 1、装饰器模式(Decorator) 1、装饰器模式:对原始对象动态地进行“包装”,是对类实例“装饰”的结果;类似于继承的效果,但这个过程是动态的,是可设…

Java基础常见面试题-异常-泛型-反射-注解-SPI-序列化-IO流

Java基础常见面试题-异常-泛型 1 Exception 和 Error 有什么区别? 1**Exception** :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异…

构建系统发育树简述

1. 要点 系统发育树代表了关于一组生物之间的进化关系的假设。可以使用物种或其他群体的形态学(体型)、生化、行为或分子特征来构建系统发育树。在构建树时,我们根据共享的派生特征(不同于该组祖先的特征)将物种组织成…

Spring AOP之基于注解的使用

1、技术说明 AOP是思想,AspectJ是AOP思想的实现。 动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模…

【SPSS】单样本T检验分析详细操作教程(附案例实战)

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

服务端开发之Java备战秋招面试3

今天继续学习,先做两题算法题练练手,在继续整理八股文,深入理解,才能在面试的时候有更好地表现,一起加油吧,希望秋招多拿几个令人心动的offer,冲吧。 目录 1、算法题:判断链表中是…

带你了解IP报警柱的特点

IP可视报警柱是一款室外防水紧急求助可视对讲终端。安装在学校、广场、道路人流密集和案件高发区域,当发生紧急情况或需要咨询求助时按下呼叫按钮立即可与监控中心值班人员通话,值班人员也可通过前置摄像头了解现场情况并广播喊话。IP可视报警柱的使用特…

【双重注意机制:肺癌:超分】

Dual attention mechanism network for lung cancer images super-resolution (肺癌图像超分辨率的双重注意机制网络) 目前,肺癌的发病率和死亡率均居世界恶性肿瘤之首。提高肺部薄层CT的分辨率对于肺癌筛查的早期诊断尤为重要。针对超分辨…

收割不易,五面Alibaba终拿Java岗offer

前言 前段时间有幸被阿里的一位同学内推,参加了阿里巴巴Java岗位的面试,本人19年双非本科软件工程专业,目前有一年半的工作经验,面试前就职于一家外包公司。如果在自己本人拿到offer之前,如果有人告诉我一年工作经验可…

会声会影2023专业版视频处理制作软件功能详细介绍

会声会影是一款专业的视频处理和制作软件,也是目前影楼制作结婚和一般视频特效制作的必备软件,他是一款专为个人及家庭所设计的数码影片编辑软件,可将数 字或模拟摄像机所拍下来的如成长写真、国外旅游、个人MTV、生日派对、毕业典礼等精彩生…

C++ 修改程序进程的优先级(Linux,Windows)

文章目录1、Linux1.1 常用命令1.1.1 不占用终端运行和后台运行方式1.1.2 查询进程1.1.3 结束进程1.1.4 优先级命令1.2 C 代码示例1.2.1 代码一1.2.2 代码二2、Windows2.1 简介2.2 函数声明2.3 C 代码示例2.3.1 代码一2.3.2 代码二结语1、Linux 1.1 常用命令 1.1.1 不占用终端…

关于死锁的一些基本知识

目录 死锁是什么? 死锁的三种经典情况 1.一个线程,一把锁,连续加锁两次,如果锁是不可重入锁就会死锁。 不可重入锁与可重入锁: 2.两个线程两把锁,t1和t2各自针对于锁A和锁B加锁,再尝试获取…

Redis 集群

文章目录一、集群简介二、Redis集群结构设计🍉2.1 数据存储设计🍉2.2 内部通信设计三、cluster 集群结构搭建🍓3-1 cluster配置 .conf🍓3-2 cluster 节点操作命令🍓3-3 redis-trib 命令🍓3-4 搭建 3主3从结…

用ChatGPT生成Excel公式,太方便了

ChatGPT 自去年 11 月 30 日 OpenAI 重磅推出以来,这款 AI 聊天机器人迅速成为 AI 界的「当红炸子鸡」。一经发布,不少网友更是痴迷到通宵熬夜和它对话聊天,就为了探究 ChatGPT 的应用天花板在哪里,经过试探不少人发现&#xff0c…

同步和非同步整流DC/DC转换区别

在DC/DC转换器中,非隔离式降压开关稳压器包括两种拓扑结构:非同步整流(二极管)型和同步整流型。非同步整流型已经使用多年,具有简单的开关稳压器电路,效率勉强超过80%。随后,电池供电应用&#…

VMware 的网络适配器 桥接-NAT-仅主机

大家使用VMware安装镜像之后,是不是都会考虑虚拟机的镜像系统怎么连上网的,它的连接方式是什么,它ip是什么? 路由器、交换机和网卡 1.路由器 一般有几个功能,第一个是网关、第二个是扩展有线网络端口、第三个是WiFi功…

Redis 被问麻了...

Redis是面试中绕不过的槛,只要在简历中写了用过Redis,肯定逃不过。今天我们就来模拟一下面试官在Redis这个话题上是如何一步一步深入,全面考察候选人对于Redis的掌握情况。 小张: 面试官,你好。我是来参加面试的。 …

Hadoop-MapReduce

Hadoop-MapReduce 文章目录Hadoop-MapReduce1 MapRedcue的介绍1.1 MapReduce定义1.2 MapReduce的思想1.3MapReduce优点1.4MapReduce的缺点1.5 MapReduce进程1.6 MapReduce-WordCount1.6.1 job的讲解2 Hadoop序列化2.1 序列化的定义2.2 hadoop序列化和java序列化的区别3 MapRedu…

RabbitMQ发布确认模式

目录 一、发布确认原理 二、发布确认的策略 (一)开启发布确认的方法 (二)单个确认模式 (三)批量确认模式 (四)异步确认模式 (五)如何处理异步未确认消…

华为CT6100双千M路由记录

该文章仅仅记录使用CT6100的流程,不提供任何参考和建议。 一、简介 设备:华为CT6100瘦客服端,J1800cpu,不包含外壳,有双千M网口,2G内存8G硬盘。系统:esir的高大全openwrt版本用途:对…