Vue鼠标框选生成坐标组件

最近工作中遇到一个需求,需要在一个图片上,手动框选一些区域,然后生成相对于图片区域的坐标。
于是想到之前用到过的一个裁剪图片的插件vue-cropper,一样是框选图片区域,于是学习了一下它的源码,并在此基础上自己实现了一个框选图片区域生成坐标的组件。
实现功能:
  1. 鼠标按下拖拽生成框选,不限制个数
  2. 可调整框选大小
  3. 可移动框选位置
  4. 可缩放
  5. 可单独控制每个框选是否可以编辑
先来看看效果:

在实现功能之前我们要知道一些属性的区别:
Vue鼠标框选生成坐标组件
文章图片

clientXclientY 表示鼠标相对于当前窗口的坐标,所以我们每次创建框选/改变框选大小/移动框选之前,都要先记录一下当时的clientX,clientY,然后在移动鼠标时用现在的clientX,clientY和之前记录的去对比,计算出鼠标移动的距离,以此来改变框选的宽度和位置,下面代码中的fwfh就是用来记录这个的。
【Vue鼠标框选生成坐标组件】offsetXoffsetY 是鼠标相对于绑定事件的那个元素,在这个组件中,绑定事件的是最外层的div元素,所以用这两个值,在创建框的时候来确定框选左上角的位置。
创建框选的步骤:
  1. 按下鼠标,触发mousedown事件,通过offsetX、offsetY来确定框选左上角在组件内的位置并记录,绑定mousemove,mouseup事件。
  2. 移动鼠标调整框选大小,触发mousemove事件,计算出新框选的左上角坐标和宽高。
  3. 鼠标抬起,触发mouseup事件,移除刚刚绑定的mousemove,mouseup事件。
每个框选有4个属性 cropXcropYcropWcropH 来记录框选的左上角坐标以及宽高,并有四个对应的old属性来记录旧坐标,记录旧坐标的目的是为了计算新坐标,栗子:
Vue鼠标框选生成坐标组件
文章图片

我们将框选拖大,如上图,那么新框选的左上角没变
cropW(新框选长度) = oldCropW + fw
cropH(新框选高度) = oldCrop + fh
再举个栗子,我们拖动框选右下角,把他拖到上方
Vue鼠标框选生成坐标组件
文章图片

由上图所知:
  • cropW = fw - oldCropW
  • cropH = fh - oldCropH
  • cropX = oldCropX - cropW
  • cropY = oldCropY - cropH
改变框大小位置的计算逻辑大概就是这样,当然在计算坐标时还需要判断一下,不能让框选超出了范围。
代码如下:
.cropper-container { position: relative; width: 100%; height: 100%; box-sizing: border-box; user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; cursor: crosshair; }.crop-box, .cropper-face { position: absolute; top: 0; right: 0; bottom: 0; left: 0; user-select: none; box-sizing: border-box; }.crop-box { border: 1px solid #39f; }.cropper-face { top: 0; left: 0; cursor: move; }.crop-line { position: absolute; display: block; width: 100%; height: 100%; }.line-top { top: -3px; left: 0; height: 5px; cursor: row-resize; }.line-left { top: 0; left: -3px; width: 5px; cursor: col-resize; }.line-bottom { bottom: -3px; left: 0; height: 5px; cursor: row-resize; }.line-right { top: 0; right: -3px; width: 5px; cursor: col-resize; }.crop-point { position: absolute; width: 7px; height: 7px; opacity: .75; background-color: #39f; border-radius: 100%; }.point1 { top: -4px; left: -4px; cursor: nwse-resize; }.point2 { top: -4px; left: 50%; transform: translateX(-50%); cursor: row-resize; }.point3 { top: -4px; right: -4px; cursor: nesw-resize; }.point4 { top: 50%; right: -4px; transform: translateY(-50%); cursor: col-resize; }.point5 { bottom: -4px; right: -4px; cursor: nwse-resize; }.point6 { bottom: -4px; left: 50%; transform: translateX(-50%); cursor: row-resize; }.point7 { bottom: -4px; left: -4px; cursor: nesw-resize; }.point8 { top: 50%; left: -4px; transform: translateY(-50%); cursor: col-resize; }

结尾
我是周小羊,一个前端萌新,写文章是为了记录自己日常工作遇到的问题和学习的内容,提升自己,如果您觉得本文对你有用的话,麻烦点个赞鼓励一下哟~

    推荐阅读