原生javascript實現上下左右中間八個點控制元素大小、旋轉角度、拖拽位置功能

最近在接觸一個簡單的圖形編輯器,要求是要實現web頁面加載圖標元素並可以通過上下左右中間八個點鼠標控制元素大小。拖拽功能比較簡單,一般都比較容易實現,主要是旋轉和八個點控制元素的大小,旋轉是相對難理解一點,需要到一些數學問題,關於座標系的知識。

整個demo源碼下載地址: 

通過 Math.atan可以計算出反正切的值,從而推算出鼠標移動到哪個象限的時候的角度。四個點的拖拉也這個比較容易實現,自己想一下就可以了

運行結果如下:

部分主要代碼如下:

Rotate.js代碼

const $ = (str) => {
  return document.querySelector(str);
};
const setRotate = (dom, rotate) => {
  dom.style.webkitTransform = 'rotate(' + rotate + 'deg)';
};
let roateBox = $('#rotateBox');

// 旋轉按鈕代碼
// 獲取方形中心座標點即座標軸原點
let centerPointX = roateBox.getBoundingClientRect().left + roateBox.getBoundingClientRect().width / 2;
let centerPointY = roateBox.getBoundingClientRect().top + roateBox.getBoundingClientRect().height / 2;
// 鼠標移動事件
const moveEvent = (e) => {
  let X = e.clientX;
  let Y = e.clientY;
  e.stopPropagation();
  let oY = Math.abs(Y - centerPointY);
  let oX = Math.abs(X - centerPointX);
  // 避免水平和垂直位置的就相當於和座標軸相交的時候設置除數爲0或者不知道爲360度還是180度
  (oY === 0) && (oY = 0.01);
  (oX === 0) && (oX = 0.01);
  let degEnd = Math.atan(oX / oY) / (2 * Math.PI) * 360;

  // 第一象限
  if (X > centerPointX && Y < centerPointY) {
    console.log('第一象限');
    setRotate(roateBox, degEnd);
  }
  // 第二象限
  if (X > centerPointX && Y > centerPointY) {
    console.log('第二象限');
    setRotate(roateBox, (180 - degEnd));
  }
  // 第三象限
  if (X < centerPointX && Y > centerPointY) {
    console.log('第三象限');
    setRotate(roateBox, (degEnd + 180));
  }
  // 第四象限
  if (X < centerPointX && Y < centerPointY) {
    console.log('第四象限');
    setRotate(roateBox, (360 - degEnd));
  }
};

$('#rotateBox .point').addEventListener('mousedown', function (e) {
  e.stopPropagation();
  document.addEventListener('mousemove', moveEvent, false);
}, false);

document.addEventListener('mouseup', function () {
  document.removeEventListener('mousemove', moveEvent);
}, false);

// 釋放文檔按下事件
document.onmouseup = function () {
  document.onmousemove = null;
};

// 右下角拉伸點
let startX, startY, owidth, oheight, oleft, otop;
const MAXWIDTH = 50;  // 限制最大寬度
const MAXHEIGHT = 50; // 限制最大高度
$('#rotateBox .rb-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = moveX - startX;
    let mHeight = moveY - startY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = oleft + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 左下角拉伸點
$('#rotateBox .lb-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = startX - moveX;
    let mHeight = moveY - startY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = moveX + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 左上角拉伸點
$('#rotateBox .lt-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = startX - moveX;
    let mHeight = startY - moveY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = moveX + 'px';
    that.parentNode.style.top = moveY + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);


// 右上角拉伸點
$('#rotateBox .rt-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = moveX - startX;
    let mHeight = startY - moveY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = oleft + 'px';
    that.parentNode.style.top = moveY + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);


// 中上拉伸點
$('#rotateBox .ct-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let mHeight = startY - moveY;
    that.parentNode.style.top = moveY + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 中下拉伸點
$('#rotateBox .cb-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let mHeight = moveY - startY;
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 左中拉伸點
$('#rotateBox .cl-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let moveX = e.clientX;
    let mWidth = startX - moveX;
    that.parentNode.style.left = moveX + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
  };
}, false);

// 右中拉伸點
$('#rotateBox .cr-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let moveX = e.clientX;
    let mWidth = moveX - startX;
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
  };
}, false);

Dragble.js負責拖動元素位置

const $Dragble = {
  dom: '',
  isMove: false,
  left: '',
  top: '',
  mouseStartX: '',
  mouseStartY: '',
  positionType: '',
  mousemove: function(maxleft, maxtop) {
    $Dragble.dom.style.top = $Dragble.top + (window.event.pageY - $Dragble.mouseStartY) + 'px';
    $Dragble.dom.style.left = $Dragble.left + (window.event.pageX - $Dragble.mouseStartX) + 'px';
    // 這兩行必須要有,爲了移動的時候重置中心點的座標
    centerPointX = $Dragble.dom.getBoundingClientRect().left + $Dragble.dom.getBoundingClientRect().width / 2;
    centerPointY = $Dragble.dom.getBoundingClientRect().top + $Dragble.dom.getBoundingClientRect().height / 2;
  },
  mouseup: function() {
    document.removeEventListener('mousemove', this.mousemove);
  },
  // 初始化數據
  intData: function(dom, type, maxLeft, maxTop) {
    this.dom = dom;
    this.isMove = true;
    this.positionType = type;
    this.dom.style.position = type;
    this.mouseStartX = window.event.pageX;
    this.mouseStartY = window.event.pageY;
    this.left = Number.parseFloat(this.dom.style.left);
    this.top = Number.parseFloat(this.dom.style.top);
    this.dom.style.left ? this.dom.style.left : this.dom.style.left = 0;
    this.dom.style.top ? this.dom.style.top : this.dom.style.top = 0;
  },
  mousedown: function(dom, type, maxLeft, maxTop) {
    this.intData(dom, type, maxLeft, maxTop);
    document.addEventListener('mousemove', this.mousemove, false);
    document.removeEventListener('mouseup', this.mousemove);
  }
};

 

html部分:

<!DOCTYPE html>
<html>
  <head>
    <link href="./css/Roate.css" rel="stylesheet" />
  </head>
  <body>
    <div 
      class="box"
      οnmοusedοwn="$Dragble.mousedown(this, 'relative')"
		  οnmοuseup="$Dragble.mouseup()"
      id="rotateBox"
      style="transform: rotate(0deg);left:0;top:0;"
    >
      正
      <!--img src="./img.png"/-->
      <div class="point" title="點擊旋轉"></div>
      <div class="lt-point" title="左上角"></div>
      <div class="rt-point" title="右上角"></div>
      <div class="rb-point" title="右下角"></div>
      <div class="lb-point" title="左下角"></div>
      <div class="ct-point" title="中上點"></div>
      <div class="cb-point" title="中下點"></div>
      <div class="cl-point" title="左中點"></div>
      <div class="cr-point" title="右中點"></div>
    </div>
    <script src="./js/Roate.js"></script>
    <script src="./js/Dragble.js"></script>
  </body>
</html>

CSS部分代碼:

#rotateBox {
  position:relative;
  height: 200px;
  width: 200px;
  background:red;
  font-size:45px;
  color:#fff;
  line-height:200px;
  text-align:center;
  user-select: none;
  border:4px solid #AED271;
}
#rotateBox .point{
  position:absolute;
  left: 50%;
  top:-50px;
  margin-left:-10px;
  height:20px;
  width:20px;
  border-radius:20px;
  background: url('../img/rotate-icon.jpg') no-repeat center;
  background-size: 100%;
}
#rotateBox .rb-point,
.lb-point,
.lt-point,
.rt-point,
.ct-point,
.cb-point,
.cl-point,
.cr-point{
  height:14px;
  width:14px;
  background: #AED271;
  border-radius:20px;
  position:absolute;
  right: -10px;
  bottom:-10px;
  cursor: nw-resize;
}
#rotateBox .lb-point{
  left: -10px;
  bottom:-10px;
  cursor: sw-resize;
}
#rotateBox .lt-point{
  left: -10px;
  top:-10px;
  cursor: nw-resize;
}
#rotateBox .rt-point{
  right: -10px;
  top:-10px;
  cursor: sw-resize;
}
#rotateBox img {
  position:absolute;
  left: 0;
  height:100%;
  width:100%;
}
#rotateBox .ct-point {
  left: 50%;
  top: -10px;
  margin-left:-5px;
  cursor: s-resize;
}
#rotateBox .cb-point {
  left: 50%;
  bottom: -10px;
  margin-left:-5px;
  cursor: s-resize;
}
#rotateBox .cl-point {
  top: 50%;
  left: -10px;
  margin-top:-5px;
  cursor: w-resize;
}
#rotateBox .cr-point {
  top: 50%;
  right: -10px;
  margin-top:-5px;
  cursor: w-resize;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章