旋转时使用拖动手柄调整div的大小 [英] Resize div with drag handle when rotated

查看:107
本文介绍了旋转时使用拖动手柄调整div的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以找到类似的问题,涉及jQuery UI lib,或者只有css没有拖曳的句柄,但是没有纯数学的东西.

我尝试执行的操作是具有可调整大小且可旋转的div.到目前为止很容易,我可以做到.

What I try to perform is to have a resizable and rotatable div. So far so easy and I could do it.

但是旋转时它变得更加复杂,调整大小手柄以相反的方式进行计算:减小大小而不是从形状中拖动时增加大小.

But it gets more complicate when rotated, the resize handle does calculation in opposite way: it decreases the size instead of increasing when dragging away from shape.

除了计算之外,我还希望能够根据旋转更改调整大小手柄的光标以使其始终有意义. 为此,我正在考虑检测调整大小手柄位于哪个象限,并应用一个类通过CSS更改光标.

Apart from the calculation, I would like to be able to change the cursor of the resize handle according to the rotation to always make sense. For that I was thinking to detect which quadrant is the resize handle in and apply a class to change cursor via css.

  1. 我不想重新发明轮子,但我想拥有一个轻量级的代码和简单的UI.所以我的要求是jQuery,但没有别的.没有jQuery UI.
  2. 我可以一直发展直到实现这一目标,但现在对我来说已经太数学了..我很困惑,这就是为什么我需要您的帮助来检测何时旋转足以使计算取反.
  1. I don't want to reinvent the wheel, but I want to have a lightweight code and simple UI. So my requirement is jQuery but nothing else. no jQuery UI.
  2. I could develop until achieving this but it's getting too mathematical for me now.. I am quite stuck that's why I need your help to detect when the rotation is enough to have the calculation reversed.

最终,如果有人有想法或更好的示例向我展示,我最终正在寻求UX的改进!

这是我的代码和可尝试使用的Codepen: http://codepen.io/anon/pen/rrAWJA

Here is my code and a Codepen to try: http://codepen.io/anon/pen/rrAWJA

<html>
<head>
    <style>
    html, body {height: 100%;}

    #square {
        width: 100px;
        height: 100px;
        margin: 20% auto;
        background: orange;
        position: relative;
    }
    .handle * {
        position: absolute;
        width: 20px;
        height: 20px;
        background: turquoise;
        border-radius: 20px;
    }
    .resize {
        bottom: -10px;
        right: -10px;
        cursor: nwse-resize;
    }
    .rotate {
        top: -10px;
        right: -10px;
        cursor: alias;
    }
    </style>
    <script type="text/javascript" src="js/jquery.js"></script>
    <script>
        $(document).ready(function()
        {
            new resizeRotate('#square');
        });

        var resizeRotate = function(targetElement)
        {
            var self = this;
            self.target = $(targetElement);
            self.handles = $('<div class="handle"><div class="resize" data-position="bottom-right"></div><div class="rotate"></div></div>');
            self.currentRotation = 0;
            self.positions = ['bottom-right', 'bottom-left', 'top-left', 'top-right'];

            self.bindEvents = function()
            {
                self.handles
                    //=============================== Resize ==============================//
                    .on('mousedown', '.resize', function(e)
                    {
                        // Attach mouse move event only when first clicked.
                        $(document).on('mousemove', function(e)
                        {
                            var topLeft = self.target.offset(),
                                bottomRight = {x: topLeft.left + self.target.width(), y: topLeft.top + self.target.height()},
                                delta = {x: e.pageX - bottomRight.x, y: e.pageY - bottomRight.y};

                            self.target.css({width: '+=' + delta.x, height: '+=' + delta.y});
                        })
                        .one('mouseup', function(e)
                        {
                            // When releasing handle, round up width and height values :)
                            self.target.css({width: parseInt(self.target.width()), height: parseInt(self.target.height())});
                            $(document).off('mousemove');
                        });
                    })
                    //============================== Rotate ===============================//
                    .on('mousedown', '.rotate', function(e)
                    {
                        // Attach mouse move event only when first clicked.
                        $(document).on('mousemove', function(e)
                        {
                            var topLeft = self.target.offset(),
                                center = {x: topLeft.left + self.target.width() / 2, y: topLeft.top + self.target.height() / 2},
                                rad = Math.atan2(e.pageX - center.x, e.pageY - center.y),
                                deg = (rad * (180 / Math.PI) * -1) + 135;

                            self.currentRotation = deg;
                            // console.log(rad, deg);
                            self.target.css({transform: 'rotate(' + (deg)+ 'deg)'});
                        })
                        .one('mouseup', function(e)
                        {
                            $(document).off('mousemove');
                            // console.log(self.positions[parseInt(self.currentRotation/90-45)]);
                            $('.handle.resize').attr('data-position', self.positions[parseInt(self.currentRotation/90-45)]);
                        });
                    });
            };
            self.init = function()
            {
                self.bindEvents();
                self.target.append(self.handles.clone(true));
            }();
        }
    </script>
</head>
<body>
    <div id="all">
        <div id="square"></div>
    </div>
</body>
</html>

感谢您的帮助!

推荐答案

这是对代码的修改,可以实现所需的功能:

Here is a modification of your code that achieves what you want:

$(document).ready(function() {
  new resizeRotate('#square');
});

var resizeRotate = function(targetElement) {
  var self = this;
  self.target = $(targetElement);
  self.handles = $('<div class="handle"><div class="resize" data-position="bottom-right"></div><div class="rotate"></div></div>');
  self.currentRotation = 0;
  self.w = parseInt(self.target.width());
  self.h = parseInt(self.target.height());
  self.positions = ['bottom-right', 'bottom-left', 'top-left', 'top-right'];

  self.bindEvents = function() {
    self.handles
      //=============================== Resize ==============================//
      .on('mousedown', '.resize', function(e) {
        // Attach mouse move event only when first clicked.
        $(document).on('mousemove', function(e) {
            var topLeft = self.target.offset();           

            var centerX = topLeft.left + self.target.width() / 2;
            var centerY = topLeft.top + self.target.height() / 2;

            var mouseRelativeX = e.pageX - centerX;
            var mouseRelativeY = e.pageY - centerY;

            //reverse rotation
            var rad = self.currentRotation * Math.PI / 180;
            var s = Math.sin(rad);
            var c = Math.cos(rad);
            var mouseLocalX = c * mouseRelativeX + s * mouseRelativeY;
            var mouseLocalY = -s * mouseRelativeX + c * mouseRelativeY;

            self.w = 2 * mouseLocalX;
            self.h = 2 * mouseLocalY;
            self.target.css({
              width: self.w,
              height: self.h
            });
          })
          .one('mouseup', function(e) {
                $(document).off('mousemove');
          });
      })
      //============================== Rotate ===============================//
      .on('mousedown', '.rotate', function(e) {
        // Attach mouse move event only when first clicked.
        $(document).on('mousemove', function(e) {
            var topLeft = self.target.offset(),
              center = {
                x: topLeft.left + self.target.width() / 2,
                y: topLeft.top + self.target.height() / 2
              },
              rad = Math.atan2(e.pageX - center.x, center.y - e.pageY) - Math.atan(self.w / self.h),
              deg = rad * 180 / Math.PI;

            self.currentRotation = deg;
            self.target.css({
              transform: 'rotate(' + (deg) + 'deg)'
            });
          })
          .one('mouseup', function(e) {
            $(document).off('mousemove');
            $('.handle.resize').attr('data-position', self.positions[parseInt(self.currentRotation / 90 - 45)]);
          });
      });
  };
  self.init = function() {
    self.bindEvents();
    self.target.append(self.handles.clone(true));
  }();
}

主要变化如下:

在调整大小事件中,鼠标位置将基于当前旋转被转换为局部坐标系.然后根据鼠标在本地系统中的位置确定大小.

In the resize event, the mouse position is transformed to the local coordinate system based on the current rotation. The size is then determined by the position of the mouse in the local system.

旋转事件说明了框的长宽比(- Math.atan(self.w / self.h)部分).

The rotate event accounts for the aspect ratio of the box (the - Math.atan(self.w / self.h) part).

如果要基于当前旋转更改光标,请检查手柄的角度(即self.currentRotation + Math.atan(self.w / self.h) * 180 / Math.PI).例如.如果每个象限都有一个光标,则只需检查该值是否在0..90、90..180等之间即可.您可能要检查文档,atan2是否以及何时返回负数.

If you want to change the cursor based on the current rotation, check the angle of the handle (i.e. self.currentRotation + Math.atan(self.w / self.h) * 180 / Math.PI). E.g. if you have a cursor per quadrant, just check if this value is between 0..90, 90..180 and so on. You may want to check the documentation if and when negative numbers are returned by atan2.

注意:偶尔闪烁是由于框未垂直居中.

Note: the occasional flickering is caused by the box not being vertically centered.

这篇关于旋转时使用拖动手柄调整div的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆