Изменение размера div с помощью ручки перетаскивания при вращении

Я мог бы найти похожие вопросы, связанные с jQuery UI lib, или только css без ручка для перетаскивания, но ничего с чистой математикой.

То, что я пытаюсь выполнить, состоит в том, чтобы иметь изменяемый размер и поворот div. До сих пор так легко, и я мог это сделать.

Но при повороте он становится более сложным, ручка изменения размера выполняет расчет противоположным образом: он уменьшает размер вместо увеличения при перетаскивании от формы.

Помимо расчета, я хотел бы иметь возможность изменять курсор маркера изменения размера в соответствии с поворотом, чтобы всегда иметь смысл. Для этого я думал, чтобы определить, какой квадрант является обработчиком изменения размера, и применить класс для изменения курсора через css.

  1. Я не хочу изобретать колесо, но хочу иметь легкий код и простой пользовательский интерфейс. Поэтому мое требование – jQuery, но ничего больше. Нет jQuery UI.
  2. Я мог бы развиться до достижения этого, но сейчас он становится слишком математичным. Я совершенно застрял, поэтому мне нужна твоя помощь, чтобы определить, когда поворота достаточно, чтобы пересчитать пересчет.

В конце концов я ищу улучшения UX, если у кого-то есть идея или лучшие примеры, чтобы показать мне!

Вот мой код и Codepen, чтобы попробовать: 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> 

Спасибо за помощь!

Вот модификация вашего кода, которая обеспечивает то, что вы хотите:

 $(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)); }(); } 

Основные изменения заключаются в следующем:

В событии изменения размера положение мыши преобразуется в локальную систему координат на основе текущего вращения. Затем размер определяется положением мыши в локальной системе.

Событие поворота учитывает соотношение сторон окна (часть - Math.atan(self.w / self.h) ).

Если вы хотите изменить курсор на основе текущего вращения, проверьте угол ручки (т.е. self.currentRotation + Math.atan(self.w / self.h) * 180 / Math.PI ). Например, если у вас есть курсор на квадрант, просто проверьте, находится ли это значение между 0..90, 90..180 и так далее. Вы можете проверить документацию, если и когда отрицательные числа возвращаются atan2 .

Примечание: случайное мерцание вызвано тем, что поле не центрировано по вертикали.

Interesting Posts
Давайте будем гением компьютера.