首页 > 其他分享 >js图片随鼠标移动,旋转,缩放

js图片随鼠标移动,旋转,缩放

时间:2023-03-02 18:24:00浏览次数:58  
标签:box pointA pointB 鼠标 缩放 js var 旋转 Math

效果如图,图片可以跟随鼠标移动,旋转,拉伸,代码在谷歌浏览器和IE11验证了,其他浏览器没试过 本博客源码: https://github.com/shengbid/vue-demo 把这个功能放在vue项目里了, 这个项目里会把平时博客写的一些功能的代码都放在里面,有需要可以下载看看,有帮助的话点个star哈   我主要讲一下实现思路, 首先是移动,这个比较简单 这里我用的是鼠标事件的pageX,pageY,因为这个获取的是鼠标距文档左上角的坐标,不受滚动条影响

画一张图来演示 如图.绿色是鼠标移动位置,pageX,pageY是鼠标按下的位置,pageX1,pageY1是鼠标移动停止时的位置 pageX是由图片的left + 鼠标到图片左边的距离组成,也许还有其他的padding,margin之类的,但是不影响,统统都算成c pageX = left + c c = pageX - left 要求第二次的left值,只需要用pageX1 - c就可以 left1 = pageX1 - c
再把计算出的left1赋值给定位元素,top是同样的计算 因为我的图片是包在一个div元素里,定位给就这个div赋值   代码实现 复制代码

// 元素移动
  var moveMouse = false;
  $('.img').mousedown(function (e) {
    e.preventDefault()
    e.stopPropagation()
    moveMouse = true

    var dis = {
      X: e.pageX - $('.box').position().left,
      Y: e.pageY - $('.box').position().top
    }
    $(document).on('mousemove', function (event) {
      event.preventDefault()
      event.stopPropagation()
      if (moveMouse) {
        var end = {}
        end.X = event.pageX - dis.X
        end.Y = event.pageY - dis.Y
        $('.box').css({
          'left': end.X,
          'top': end.Y
        })
      }
    })
  })

  $(document).on('mouseup', function (e) {
    moveMouse = false
  });
复制代码

 

这样就实现移动功能了
  再来实现元素的旋转拉伸功能   拉伸可以通过改变元素的width和height实现,也可以通过transform的scale实现   这里涉及一个问题,旋转的时候以图片左上角为旋转点还是以图片中心点为旋转点,transform的rotate默认是以元素的中心点为旋转点.而width和height的改变是以元素左上角为基点,这里我们要做的功能是边旋转边改变图片大小,那么统一都以图片中心点为基点.这样的话用width和height来实现放大缩小功能就不方便了,所以还是使用scale来实现
  先看旋转的实现,以这张图说明,首先需要确定中心点,还有第一次鼠标按下的点pointB,以后每次旋转都是求BA,CA的夹角,也就是cosA  代码实现 复制代码
var pointA = { // 元素中心点 元素1/2自身宽高 + 元素的定位
    X: $('.box').width() / 2 + $('.box').offset().left,
    Y: $('.box').height() / 2 + $('.box').offset().top
  };
  console.log(pointA)

  var pointB = {};
  var pointC = {}; // A,B,C分别代表中心点,起始点,结束点坐标
  // 这里通过鼠标的移动获取起始点和结束点
  var typeMouse = false;

  var allA = 0; // 存放鼠标旋转总共的度数
  var count = 0;
  // 元素跟随鼠标移动旋转
  $(".rotate").on('mousedown', function (e) {
    e.preventDefault()
    e.stopPropagation()

    typeMouse = true; //获取起始点坐标
    if (count < 1) { // 以鼠标第一次落下的点为起点
      pointB.X = e.pageX;
      pointB.Y = e.pageY;
      count++
    }

    console.log(5, pointA, pointB)

    $(document).on('mousemove', function (e) {
      e.preventDefault()
      if (typeMouse) {
        pointC.X = e.pageX;
        pointC.Y = e.pageY; // 获取结束点坐标

        // 计算出旋转角度
        var AB = {};
        var AC = {};
        AB.X = (pointB.X - pointA.X);
        AB.Y = (pointB.Y - pointA.Y);
        AC.X = (pointC.X - pointA.X);
        AC.Y = (pointC.Y - pointA.Y); // 分别求出AB,AC的向量坐标表示
        var direct = (AB.X * AC.Y) - (AB.Y * AC.X); // AB与AC叉乘求出逆时针还是顺时针旋转
        var lengthAB = Math.sqrt(Math.pow(pointA.X - pointB.X, 2) +
            Math.pow(pointA.Y - pointB.Y, 2)),
          lengthAC = Math.sqrt(Math.pow(pointA.X - pointC.X, 2) +
            Math.pow(pointA.Y - pointC.Y, 2)),
          lengthBC = Math.sqrt(Math.pow(pointB.X - pointC.X, 2) +
            Math.pow(pointB.Y - pointC.Y, 2));
        var cosA = (Math.pow(lengthAB, 2) + Math.pow(lengthAC, 2) - Math.pow(lengthBC, 2)) /
          (2 * lengthAB * lengthAC); //   余弦定理求出旋转角
        var angleA = Math.round(Math.acos(cosA) * 180 / Math.PI);
        if (direct < 0) {
          allA = -angleA; //叉乘结果为负表示逆时针旋转, 逆时针旋转减度数
        } else {
          allA = angleA; //叉乘结果为正表示顺时针旋转,顺时针旋转加度数
        }

        // console.log(allA)
        $('.img-box').css('transform', 'rotate('+allA+'deg)')
      }
    });
  });

  $(document).on('mouseup', function (e) {
    typeMouse = false;
  });
复制代码

 

拉伸实现,如图,其实就是AC/AB的比例,AB和AC的长度可以百度搜索已知两点坐标求直线距离查看计算公式,这里就不展开了 代码实现 复制代码
// 元素跟随鼠标移动拉伸
  $(".rotate, .rotate1").on('mousedown', function (e) {
    e.preventDefault()
    e.stopPropagation()

    typeMouse = true; //获取起始点坐标
    if (count < 1) { // 以鼠标第一次落下的点为起点
      pointB.X = e.pageX;
      pointB.Y = e.pageY;
      count++
    }
    console.log(5, pointA, pointB)

    $(document).on('mousemove', function (e) {
      e.preventDefault()
      if (typeMouse) {
        pointC.X = e.pageX;
        pointC.Y = e.pageY; // 获取结束点坐标
        // 计算每次移动元素的半径变化,用作拉伸
        var scalX1 = pointB.X - pointA.X
        var scalY1 = pointB.Y - pointA.Y
        var scalX = pointC.X - pointA.X
        var scalY = pointC.Y - pointA.Y

        // 计算出拉伸比例
        var sa = Math.sqrt(scalX1 * scalX1 + scalY1 * scalY1)
        var ss = Math.sqrt(scalX * scalX + scalY * scalY)
        var sc = ss / sa
        // console.log(sc)
        $('.img-box').css('transform', 'scale('+sc+')')
      }
    });
  });
  
  $(document).on('mouseup', function (e) {
    typeMouse = false;
  });
复制代码

 

html代码

复制代码
  <div class="container">
    <div class="box">
      <div class="img-box">
        <div class="flat">翻转</div>
        <div class="rotate">旋转</div>
        <img src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1141259048,554497535&fm=26&gp=0.jpg" alt="" class="img">
      </div>
    </div>
  </div>
复制代码   HTML元素的关系,图片需要包三层父级div. img-box包图片,旋转的时候旋转img-box.因为旋转之后left和top值会改变, 所以需要在包一层box,移动的时候改变left和top就改变box的值. 最外层的container主要是一个定位,里面的元素都是绝对定位,需要一个相对定位的父元素     然后,这三个功能都实现了,把他们组合在一起,需要注意一点问题   移动的时候,图片的中心点也改变了,所以每次移动后需要重新计算图片的中心点,对应的pointB点也需要对应的改变     最后,如果你需要四个角都可以旋转,需要计算出不同旋转角之间的角度差   如图,如果第一次以旋转区域1为起点,点击旋转区域2时就需要加上旋转区域1与旋转区域2直角的夹角,也就是2倍tanA   如果第二次旋转选的是旋转区域3,那么就需要加上180°.这是顺时针方向,如果反过来逆时针方向就是减去度数差   完整代码   复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  html, body {
    margin: 0;
    font-size: 14px;
  }
  .container {
    /* padding: 20px;
    border: 1px solid sienna; */
    position: relative;
  }
  .box {
    position: absolute;
    left: 200px;
    top: 100px;
    width: 400px;
    height: 400px;
    color: #fff;
    /*  */
  }
  .img-box {
    position: absolute;
    /* left: 30px;
    top: 30px; */
    width: 400px;
    height: 400px;
    background-color: sandybrown;
  }
  .flat {
    position: absolute;
    right: -20px;
    top: -20px;
    width: 40px;
    height: 40px;
    background-color: seagreen;
    z-index: 3;
    line-height: 40px;
    text-align: center;
    cursor: default;
  }
  .rotate, .rotate1 {
    position: absolute;
    right: -20px;
    bottom: -20px;
    width: 40px;
    height: 40px;
    background-color: royalblue;
    z-index: 3;
    cursor: se-resize;
    line-height: 40px;
    text-align: center;
  }
  .rotate1 {
    left: -20px;
    right: auto;
  }
  .img {
    width: 100%;
    height: 100%;
    cursor: move;
  }
  .header {
    height: 50px;
  }
</style>
<body>
  <div class="header">
    <h1>图形编辑</h1>
  </div>
  <div class="container">
    <div class="box">
      <div class="img-box">
        <div class="flat">翻转</div>
        <div class="rotate">旋转</div>
        <div class="rotate1">旋转</div>
        <img src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1141259048,554497535&fm=26&gp=0.jpg" alt="" class="img">
      </div>
    </div>
  </div>
</body>
<!-- <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script> -->
<script src="./jquery-3.1.1.min.js"></script>
<script src="./common-validate/index.js"></script>
<script>

console.log(commonValidate)
  var flat = -1
  // 镜像翻转
  $(".flat").click(function() {
    $(".img").css("transform", "scaleX("+flat+")")
    flat = -flat
  })

  var pointA = { // 元素中心点 元素1/2自身宽高 + 元素的定位
    X: $('.box').width() / 2 + $('.box').offset().left,
    Y: $('.box').height() / 2 + $('.box').offset().top
  };
  console.log(pointA, $('.box').position())

  var pointB = {};
  var pointC = {}; // A,B,C分别代表中心点,起始点,结束点坐标
  // 这里通过鼠标的移动获取起始点和结束点
  var typeMouse = false;
  var moveMouse = false;
  var allA = 0; // 存放鼠标旋转总共的度数
  var count = 0;
  var mPointB = {} // 移动的B点距离
  var init = {
    count: 0
  }
  var oldTarget = {
    target: null,
    angle: 0
  }

  // 元素跟随鼠标移动旋转拉伸
  $(".rotate, .rotate1").on('mousedown', function (e) {
    e.preventDefault()
    e.stopPropagation()
    // 计算两个旋转方块之间的角度
    var tanA = $('.box').width() / $('.box').height()
    var d = Math.round(Math.atan(tanA) * 180 / Math.PI)

    if (oldTarget.target && oldTarget.target != e.currentTarget) {
      if (e.currentTarget == $('.rotate')[0]) {
        oldTarget.angle = 2 * d
      } else {
        oldTarget.angle = -2 * d
      }
    } else {
      oldTarget.angle = 0
    }

    typeMouse = true; //获取起始点坐标
    if (count < 1) { // 以鼠标第一次落下的点为起点
      pointB.X = e.pageX;
      pointB.Y = e.pageY;
      init.count = 0
      oldTarget.target = e.currentTarget
      count++
    }
    if (mPointB.flag) { // 如果移动后,元素的B点也需要加上平移的距离
      pointB.X += mPointB.X
      pointB.Y += mPointB.Y
      mPointB.flag = false
      init.count = 0
    }
    console.log('pointA', pointA, 'pointB', pointB)

    $(document).on('mousemove', function (e) {
      e.preventDefault()
      if (typeMouse) {
        pointC.X = e.pageX;
        pointC.Y = e.pageY; // 获取结束点坐标
        // 计算每次移动元素的半径变化,用作拉伸
        var scalX1 = pointB.X - pointA.X
        var scalY1 = pointB.Y - pointA.Y
        var scalX = pointC.X - pointA.X
        var scalY = pointC.Y - pointA.Y

        // 计算出旋转角度
        var AB = {};
        var AC = {};
        AB.X = (pointB.X - pointA.X);
        AB.Y = (pointB.Y - pointA.Y);
        AC.X = (pointC.X - pointA.X);
        AC.Y = (pointC.Y - pointA.Y); // 分别求出AB,AC的向量坐标表示
        var direct = (AB.X * AC.Y) - (AB.Y * AC.X); // AB与AC叉乘求出逆时针还是顺时针旋转
        var lengthAB = Math.sqrt(Math.pow(pointA.X - pointB.X, 2) +
            Math.pow(pointA.Y - pointB.Y, 2)),
          lengthAC = Math.sqrt(Math.pow(pointA.X - pointC.X, 2) +
            Math.pow(pointA.Y - pointC.Y, 2)),
          lengthBC = Math.sqrt(Math.pow(pointB.X - pointC.X, 2) +
            Math.pow(pointB.Y - pointC.Y, 2));
        var cosA = (Math.pow(lengthAB, 2) + Math.pow(lengthAC, 2) - Math.pow(lengthBC, 2)) /
          (2 * lengthAB * lengthAC); //   余弦定理求出旋转角
        var angleA = Math.round(Math.acos(cosA) * 180 / Math.PI);
        if (direct < 0) {
          allA = -angleA; //叉乘结果为负表示逆时针旋转, 逆时针旋转减度数
        } else {
          allA = angleA; //叉乘结果为正表示顺时针旋转,顺时针旋转加度数
        }

        allA += oldTarget.angle
        // $('.img-box').css('transform', 'rotate('+allA+'deg)')

        // 计算出拉伸比例
        var sa = Math.sqrt(scalX1 * scalX1 + scalY1 * scalY1)
        var ss = Math.sqrt(scalX * scalX + scalY * scalY)
        var sc = ss / sa
        // console.log(sa, ss, sc)
        $('.img-box').css('transform', 'rotate('+allA+'deg) scale('+sc+')')
        // $('.img-box').css('transform', 'scale('+sc+')')
      }
    });
  });

  // 元素移动
  $('.img').mousedown(function (e) {
    e.preventDefault()
    e.stopPropagation()
    moveMouse = true
    if (init.count < 1) {
      init = {
        // X: e.pageX,
        // Y: e.pageY,
        X: pointA.X,
        Y: pointA.Y,
        count: 1
      }
    }
    var dis = {
      X: e.pageX - $('.box').position().left,
      Y: e.pageY - $('.box').position().top
    }
    $(document).on('mousemove', function (event) {
      event.preventDefault()
      event.stopPropagation()
      if (moveMouse) {
        var end = {}
        end.X = event.pageX - dis.X
        end.Y = event.pageY - dis.Y

        $('.box').css({
          'left': end.X,
          'top': end.Y
        })
        // console.log($('.box').offset(), $('.box').position(), end, dis)

        pointA = { // 移动后,重新计算元素中心点 元素1/2自身宽高 + 元素的定位
          X: $('.box').width() / 2 + $('.box').offset().left,
          Y: $('.box').height() / 2 + $('.box').offset().top
        };
        if (count > 0) { // 每次移动按下的点不一致,有误差,使用中心点来计算
          // mPointB.X = event.pageX - init.X
          // mPointB.Y = event.pageY - init.Y
          mPointB.X = pointA.X - init.X
          mPointB.Y = pointA.Y - init.Y
          mPointB.flag = true
        }
        // console.log(pointA, mPointB)
      }
    })
  })
  $(document).on('mouseup', function (e) {
    typeMouse = false;
    moveMouse = false
  });

</script>

</html>
复制代码

 

 

补充内容:

感谢博友提出问题,在平移时,由于每次鼠标按下的位置不一样,我是用最后一次鼠标移动的位置减去第一次鼠标按下的位置, 如果多次移动,伸缩计算就会有误差

而元素的中心点是一直保持在元素中心,每次移动后都会改变,所以改成使用最后一次移动的元素中心点减去第一次移动时的中心点,能消除误差

代码里红色的是修改后的

 

这个方法中pointB的计算有些麻烦,特别是四个角都以旋转时. 之后又试了一种方法,比较简单一些.第二种实现方法可以看这篇https://www.cnblogs.com/steamed-twisted-roll/p/14292478.html

转载:https://www.cnblogs.com/steamed-twisted-roll/p/13408245.html

标签:box,pointA,pointB,鼠标,缩放,js,var,旋转,Math
From: https://www.cnblogs.com/wolf-shuai/p/17172911.html

相关文章

  • JSP上传文件夹的三种解决方案
    ​ 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。先说下要求:PC端全平台支持,要求支持Windows,Mac,Linux......
  • Viewer.js实现移动端图片预览,旋转
    1、安装npminstallv-viewer--save2、main.js中引入importViewerfrom'v-viewer'import'viewerjs/dist/viewer.css'//如果需要修改viewer的css可以创建一个css......
  • 【MongoDB】连接池理解及测试 NodeJS
    更新于2021-05-15最近对MongoDB连接池如何正确使用不是特别清楚,于是做了一些测试也查找了相关资料,终于知道了MongoDB的连接池是怎么工作的了。首先,在nodejsweb应用......
  • 【NodeJS】【pm2】加参数运行
    nodeindex.jsarg1arg2pm2startindex.js--arg1arg2上面两个等价 获取参数process.argv返回一个数组如下:['/usr/bin/node','/usr/lib/node_mod......
  • 【NodeJS】CommonJS原理
    (function(modules){varinstalledModules={};function__webpack_require__(moduleId){if(installedModules[moduleId]){return......
  • 【NodeJS】最小服务器
    consthttp=require('http');constfs=require('fs');http.createServer((req,res)=>{leturl=req.url;console.log(url);switch(req.me......
  • Excel 数据转二维数组 JSON
    问题描述:偶尔会遇到读取Excel数据的场景如果是在网页中,可以上传文件然后处理(可借助js-xlsx等插件)如果有node服务,也可以使用类似的操作不过如果是在应用外,只是临......
  • c# DevExpress GridView实现鼠标移动到单元格文字内容上后变手形,并触发RowCellClick
    我们都知道,在.net自带的Winform控件DataGridView控件有一个CellContentClick事件,该事件是在点击单元格内容的时候触发,很好用那么在DevExpress中的GridView中是否有类......
  • js中图片二进制和base64的互转
    <html><head><metacharset="UTF-8"><title></title></head><body><p>正常图片</p><p></p><imgsrc="132......
  • 纯js实现图片无缝循环走马灯效果支持拖拽和惯性滑动
    要求实现一个无缝循环的图片滚动公告,支持上下,左右模式。要求1,不可有卡顿图片无缝轮播     2,手指拖拽暂停轮播,用户可左右(或上下)拖拽,快速滑动有惯性效果。 ......