用戶登錄拖動驗證碼實現原理詳解。

我們經常看到登錄一些網站或者平臺的時候會出現一些需要拖動驗證碼,實現驗證功能,如鬥魚TV所示,於是就想了下這個要怎麼實現,自己看了下他的html結構,是兩個canvas,然後實現對接,原理應該是一個canvas作爲背景然後,另一個canvas在原來的背景canvas裏面扣一張圖,然後拖動元素,當元素面積接近一個百分比的時候就認爲兩個元素重合了,驗證通過了。大概就是這樣的原理~!

於是自己想了下如果要自己去實現要怎麼去實現這樣一個效果,其實他這個劃片是左右移動的,也只要移動的元素左邊的距離left值達到一定數值的時候就可以表示重合了,這樣就不需要計算重合面積了,但是自己如果是需求要求可以上下左右移動,那麼又要怎麼實現呢?

這個應該就屬於數學問題了,就是兩個正方形相交,相交面積怎麼計算。

1、這個計算過程也不算難,首先可以getBoundingClientRect方法獲取到元素距離窗口的left-top的值,就相當於計算出元素四個頂點的座標值。

2、計算出座標值之後再計算不動的那個元素X座標的範圍,Y座標的範圍。然後拖動元素的過程中判斷拖動元素的哪個點在這個範圍內,那麼就可以知道圖形相交的樣子,就可以計算出相交的面積了。

3、計算面積去除總的面積就可以得出相交面積重合比例。

具體代碼如下:


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <!--<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">-->
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-cache" />
    <title>--TITLE--</title>
    <style>
      .box1, .box2 {
        height:200px;
        width:200px;
        background:red;
        text-align:center;
        line-height:200px;
        font-size:30px;
        user-select: none;
      }
      #MoveBox{
        position:absolute;
        background:blue;
      }
      .out-box {
        position:relative;
        height: 600px;
        width: 1000px;
        margin:200px auto;
      }
    </style>
  </head>
  <body>
    <div class="out-box">
      <div class="box1" id="staticBox">相對盒子</div>
      <div class="box2" id="MoveBox" style="left: 30px; top: 30px;">拖動盒子</div>
    </div>
    <script>
      // 求出兩個元素是否相交 selem ,melem 分別爲靜止的盒子和移動的盒子
      const elemIntersect = (selem, melem) => {
        let msg = selem.getBoundingClientRect();
        let sArea = (msg.width * msg.height); // 靜止盒子的面積
        let minX = msg.left;  // 靜止元素左邊最小
        let maxX = msg.left + msg.width;  // 靜止元素右邊最大
        let minY = msg.top; // 靜止元素頂部最小
        let maxY = msg.top + msg.height;  // 靜止元素頂部最大
        let mPoint = getPoint(melem); // 獲取移動點四點的值
        // 左上點移入標識
        let flagLt = (mPoint.ltX >= minX && mPoint.ltX <= maxX) && (mPoint.ltY >= minY && mPoint.ltY <= maxY);
        // 左下點移入標識
        let flagLb = (mPoint.lbX >= minX && mPoint.lbX <= maxX) && (mPoint.lbY >= minY && mPoint.lbY <= maxY);
        // 右上點移入標識
        let flagRt = (mPoint.rtX >= minX && mPoint.rtX <= maxX) && (mPoint.rtY >= minY && mPoint.rtY <= maxY);
        // 右下點移入標識
        let flagRb = (mPoint.rbX >= minX && mPoint.rbX <= maxX) && (mPoint.rbY >= minY && mPoint.rbY <= maxY);

        if (flagLt) {
          console.log('左上點進去了');
          // 移動box的左上點減去靜止盒子的右下點就爲長和寬
          let boxArea = (getPoint(selem).rbX - getPoint(melem).ltX) * (getPoint(selem).rbY - getPoint(melem).ltY);
          console.log('相交部分的面積:' + boxArea);
          console.log('相交部分的面積佔比:' + (boxArea / sArea) * 100 + '%');
        } else if (flagLb) {
          console.log('左下點進去了');
          // 靜止box的右上點減去移動盒子的左下點就爲長和寬
          let boxArea = (getPoint(selem).rtX - getPoint(melem).lbX) * (getPoint(melem).lbY - getPoint(selem).rtY);
          console.log('相交部分的面積:' + boxArea);
          console.log('相交部分的面積佔比:' + (boxArea / sArea) * 100 + '%');
        } else if (flagRt) {
          console.log('右上點進去了');
          let boxArea = (getPoint(melem).rtX - getPoint(selem).lbX) * (getPoint(selem).lbY - getPoint(melem).rtY);
          console.log('相交部分的面積:' + boxArea);
          console.log('相交部分的面積佔比:' + (boxArea / sArea) * 100 + '%');
        } else if (flagRb) {
          console.log('右下點進去了');
          let boxArea = (getPoint(melem).rbX - getPoint(selem).ltX) * (getPoint(melem).rbY - getPoint(selem).ltY);
          console.log('相交部分的面積:' + boxArea);
          console.log('相交部分的面積佔比:' + (boxArea / sArea) * 100 + '%');
        } else {
          console.log('沒有相交部分');
        }
      };
      // 獲取元素四個點的座標 
      const getPoint = (dom) => {
        let msg = dom.getBoundingClientRect();
        return {
          // 左上
          ltX: msg.left,
          ltY: msg.top,
          // 左下
          lbX: msg.left,
          lbY: msg.top + msg.height,
          // 右上
          rtX: msg.left + msg.width,
          rtY: msg.top,
          // 右下
          rbX: msg.left + msg.width,
          rbY: msg.top + msg.height,
        };
      };
      // 求出相交的面積
      const getRecArea = (id) => {
        let staticBox = document.querySelector('#staticBox'); // 靜止的box
        let MoveBox = document.querySelector('#MoveBox'); // 移動的box
        let startX = null;
        let startY = null;
        let endX = null;
        let endY = null;
        let originX = null;
        let originY = null;
        let flag = false; // 鼠標按下標識
        // 鼠標點擊移動box
        MoveBox.addEventListener('mousedown', function(e){
          flag = true;
          originX = parseFloat(MoveBox.style.left);
          originY = parseFloat(MoveBox.style.top);
          startX = e.clientX;
          startY = e.clientY;
          console.log(originX, originY, startX, startY)
        }, false);
        // 鼠標移動的時候
        document.addEventListener('mousemove', function(e){
          if (flag) {
            MoveBox.style.left = originX + (e.clientX - startX) + 'px';
            MoveBox.style.top = originY + (e.clientY - startY) + 'px';
            elemIntersect(staticBox, MoveBox);  // 求出相交部分的面積
          }
          // console.log(e);
        }, false);
        // 鼠標鬆開移動box
        MoveBox.addEventListener('mouseup', function(e){
          flag = false;
          console.log(e);
        }, false);
      };
      getRecArea();
    </script>
  </body>
</html>

運行結果如下:

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