可视化编辑器 之 元素拖拽位置、大小、旋转解析

2,116 阅读4分钟

本文主要讲解元素拖拽移动,调整大小,拖拽旋转角度的基本实现原理。这些也都是一款可视化编辑器内的基本功能。

一、元素拖拽

元素拖拽相对比较简单,主要就是通过监听元素的mousedownmousemove事件,在拖拽过程中不断设置元素的lefttop实现位移。

鼠标在拖动元素的时候,无非就是 上、下、左、右四个方向,通过将鼠标移动前后的坐标对比,算出x、y轴的移动距离,从而计算出元素的最终位置。

iShot_2022-11-01_11.49.42.png


// 1.监听元素的鼠标按下和移动事件
<template>
  <div id="drag" ref="drag" @mousedown="mouseDown" @mousemove="mouseMove">拖拽</div>
</template>

// 2.定义数据
data() {
    return {
      startLeft:0, // 元素拖拽时的初始偏移
      startTop:0, 
      startX: 0, // 记录鼠标按下时的初始坐标
      startY: 0,
      dragState:false, // 判断是否可拖动
    };
}

// 3.在元素上按下鼠标时,记录相应数据
 mouseDown(e) {
  // 鼠标按下时的坐标
  this.startX = e.pageX;
  this.startY = e.pageY;
  
  // 鼠标按下时元素的初始位置
  this.startLeft = this.$refs.drag.offsetLeft; 
  this.startTop = this.$refs.drag.offsetTop;
  
  //标识是否在可拖拽元素上按下
  this.dragState = true; 
}

// 4.鼠标移动时进行位置的设置
 mouseMove(e){
  if(this.mouseState) {
    // 通过对比鼠标移动前后的坐标可计算出当前的位置
    // diffX > 0 表示向右拖动,反之向左
    // diffY > 0 标识向下拖动,反之向上
    const diffX = e.pageX - this.startX,
          diffY = e.pageY - this.startY;
    const left = this.startLeft + diffX,
          top = this.startTop + diffY;

    this.$refs.drag.style.cssText = `left:${left}px;top:${top}px`;
  }
}

Demo:code.juejin.cn/pen/7160500…

二、拖拽调整尺寸

拖拽调节尺寸主要通过附着在元素上的8个节点来操作的,如下图:

iShot_2022-11-01_11.51.00.png

拖拽每个节点对应的操作都些许不同:

  1. topLeft(上左):元素left、topwidth、height都会变化
  2. topCenter(上中):topheight会变化
  3. topRight(上右):topwidth、height会变化
  4. rightCenter(右中):仅width会变化
  5. bottomRight(下右):width、height会变化
  6. bottomCenter(下中):仅height会变化
  7. bottomLeft(下左):leftwidth、height会变化
  8. leftCenter(左中):leftwidth会变化

理清每个节点的作用,编写操作逻辑的时候就明了了。

跟拖拽元素一样,在节点上按下鼠标时,记录鼠标初始坐标,然后在移动过程中计算x、y轴的移动距离,再根据拖拽的节点编写对应的操作逻辑。

1.拖动rightCenter(右中)bottomCenter(下中)最简单,仅需使用初始宽、高和对应轴线的位移距离相加就行

2.拖动topCenter(上中)leftCenter(左中),除了要修改对应轴线的偏移之外,同时还需要用宽高减去对应轴线移动的距离,调整尺寸。对应轴线的位移距离为负数时,表示尺寸增大,反之减少。

3.拖动四个对角的节点,有两种操作逻辑:一种是不锁定比例,拖拽元素尺寸自由变化;另一种是锁定比例,等比缩放尺寸,我这边采用的是等比缩放。

  • 通常拖动四角的节点会产生x、y轴两个方向的位移,我这边是根据x轴位移距离来做相应的计算。
  • 比如我们拖动右下角的节点,x轴移动20像素,y轴移动15像素。我们以x轴为准,计算出元素拖动后的宽度 新的宽度 = 原始宽度 + 20,高度则等比进行放大新的宽度 / 原始宽度 * 原始高度
  • 其他几个对角的拖动,中心思想都是一样的,就不赘述了,大家可以看下方demo

正常在项目中,拖拽调整尺寸的时候,应当加一个最小尺寸的限制,低于设置的值就无法再继续缩小,demo中仅简单实现功能,未做细节处理。

Demo:code.juejin.cn/pen/7160599…

三、拖拽旋转

iShot_2022-11-01_14.10.24.png

拖拽选旋转角度相对比较简单,通过一个Math.atan2(y,x)这个公式就可以计算出来。

公式简介: Math.atan2() 返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值),也就是Math.atan2(y,x)
注意点: 1.返回的是一个逆时针的弧度 2.先传递 y 坐标,然后是 x 坐标 )

如下图: 蓝点是鼠标位置,橙点作为元素的中心,也就是原点。我们需要计算出蓝点相对于橙点的坐标.

x = 蓝点原始X - A(元素的左偏移) - B(元素宽度 / 2)

y = 蓝点原始Y - C(元素顶部偏移) - D(元素高度 / 2)

计算夹角(弧度):radian = Math.atan2(y, x);

弧度转角度: angle = radian / Math.PI / 180

iShot_2022-11-01_14.38.19.png

Demo:code.juejin.cn/pen/7160890…

相关文章