Как я могу правильно настроить отображение n-resize?

Вот модифицированный код, изначально взятый из этот пост.

Изменение размера прямоугольника в правой средней, нижней средней и правой нижней контрольных точках — это нормально, так как мне не нужно менять координаты перевода, чтобы изменить размер. Теперь моя проблема, как вы можете видеть, заключается в том, что изменение размера в верхней средней части (то же самое для левой средней, левой нижней ...) моего прямоугольника, когда угол поворота отличается от 0, не работает, поскольку он визуально меняет положение, когда я изменить его размер.

Я действительно не знаю, как это изменить, поэтому любая помощь высоко ценится.

примечание: измените угол на 0 в поле ввода, и вы увидите, что код работает правильно. Вот ссылка JSFiddle.

var input = document.getElementById("rotate_input");
var rotate = document.getElementById("rotate");
var rightMiddle = document.getElementById("rm");
var topMiddle = document.getElementById("tm");
var translate = document.getElementById("trslt");
var scale = document.getElementById("scale");
var svg = document.getElementById("main");

var rotateString = rotate.getAttribute('transform');

var controlrm = false;
var controltm = false;

var origRectWidth = 100;
var origRectHeight = 100;
var updatedRectWidth = origRectWidth;
var updatedRectHeight = origRectHeight;

var xScale = 1;
var yScale = 1;

var translateX = 100;
var translateY = 100;

var relevantMouseMoveDist = 0;

var rotateAnleDeg = 30;
var rectangleAngle = parseInt(rotateString.slice(rotateString.indexOf("(") + 1)) * Math.PI / 180; // retrieve the angle from the DOM

var newMousePosn;
var oldMousePosn;

function resizeRightMiddle()
{
  updatedRectWidth += relevantMouseMoveDistCos;
  xScale = updatedRectWidth/origRectWidth;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
}

function resizeTopMiddle()
{
  updatedRectHeight -= relevantMouseMoveDistSin;
  yScale = updatedRectHeight/origRectHeight;
  //get the new Y position
  translateY = translateY + relevantMouseMoveDistSin;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

svg.addEventListener("mousemove", function(e){

  if (newMousePosn) {
  
    // the former mouse pos'n
    oldMousePosn = {x: newMousePosn.x, y: newMousePosn.y};
    
    // the new mouse pos'n
    newMousePosn = {x: e.clientX, y: e.clientY};
    
    // the change in the mouse pos'n coordinates since the last move event
    var deltaMouseMove = {
      x: newMousePosn.x - oldMousePosn.x,
      y: newMousePosn.y - oldMousePosn.y
    };
    
    // the dir'n of this movement
    var angleOfMouseMovement = Math.atan2(deltaMouseMove.y, deltaMouseMove.x);
    
    // the absolute distance the mouse has moved
    var mouseMoveDist = Math.sqrt(
      deltaMouseMove.x * deltaMouseMove.x +
      deltaMouseMove.y * deltaMouseMove.y
    );
     
    // the difference in direction between the mouse movement and orientation of the rectangle
    var angleDifference = angleOfMouseMovement - rectangleAngle;
    
    // the portion of the mouse movement that is in the direction of the rectangle's orientation
    relevantMouseMoveDistCos = mouseMoveDist * Math.cos(angleDifference);
    relevantMouseMoveDistSin = mouseMoveDist * Math.sin(angleDifference);
    
    // resize the rectangle if necessary
    if (controlrm)
      resizeRightMiddle();
    else if (controltm)
      resizeTopMiddle();
  } else {
  
    // establish the mouse pos'n during the first mousemove event
    newMousePosn = {x: e.clientX, y: e.clientY};
  }
  
});

svg.addEventListener("mouseup"  , function(e){
  controlrm = false;
  controltm = false;});

rightMiddle.addEventListener("mousedown", function(e){controlrm = true ;});

topMiddle.addEventListener("mousedown", function(e){controltm = true ;});

// Code for changing the rectangle in the input
input.addEventListener("change", function (){
  rotateAngleDeg = input.value;
  rotate.setAttribute("transform", "rotate(" + rotateAngleDeg + ")");
  rectangleAngle = rotateAngleDeg * Math.PI / 180;
})
svg {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<svg id="main" width="1000" height="250">
 <g id= "trslt" transform="translate(100, 100)">
  <g id="rotate" transform-origin="center" transform="rotate(30)">
   <g id="scale">
    <path fill="red" stroke="red" d="M 0 0 L 0 100 L 100 100 L 100 0Z" />
    <rect id="rm" fill="black" stroke="black" x=95 y=45 width=10 height=10 />
    <rect id="tm" fill="white" stroke="black" x=45 y=-5 width=10 height=10 />
   </g>
  </g>
 </g>
</svg>
<input id="rotate_input" type="text" placeholder="Change Angle"/>


person JSmith    schedule 26.06.2017    source источник


Ответы (2)


Там довольно много и довольно сложно объяснить шаги, но по существу:

  • Перемещено Translate после Rotate в пределах svg. Это упростило изменение размера объекта без необходимости учитывать направление, на которое повлияет вращение.
  • Я использовал 3 значения, чтобы применить поворот transform="rotate(0 0 0)". Вторые два дают центр вращения.
  • Изменил размеры блока, чтобы они были центрированы на 0. Не обязательно, но я предпочел думать о математике таким образом.

Я реализовал стороны и один угол, я оставлю это вам, чтобы следовать шаблону - для Верхнего левого это просто захват кода из Верхнего и кода от Слева и объединяя их, как я уже делал в Вверху справа

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

Внешняя демонстрация (такая же, как фрагмент стека ниже): https://jsfiddle.net/bcjopdqn/2/

var input = document.getElementById("rotate_input");
var rotate = document.getElementById("rotate");
var rightMiddle = document.getElementById("rm");
var leftMiddle = document.getElementById("lm");
var topMiddle = document.getElementById("tm");
var bottomMiddle = document.getElementById("bm");
var topRight = document.getElementById("tr");

var translate = document.getElementById("trslt");
var scale = document.getElementById("scale");

var rotateString = rotate.getAttribute('transform');

var controlrm = false;
var controllm = false;
var controltm = false;
var controlbm = false;
var controltr = false;

var origRectWidth = 100;
var origRectHeight = 100;
var updatedRectWidth = origRectWidth;
var updatedRectHeight = origRectHeight;

var xScale = 1;
var yScale = 1;

var translateX = 100;
var translateY = 100;

var relevantMouseMoveDist = 0;
var relevantMouseMoveDistXCos, relevantMouseMoveDistXSin;
var relevantMouseMoveDistYCos, relevantMouseMoveDistYSin;

var rotateAngleDeg = 0;
var rectangleAngle = parseInt(rotateString.slice(rotateString.indexOf("(") + 1)) * Math.PI / 180; // retrieve the angle from the DOM

var newMousePosn;
var oldMousePosn;

function resizeLeftMiddle() {
  updatedRectWidth -= relevantMouseMoveDistXCos + relevantMouseMoveDistXSin;
  translateX += relevantMouseMoveDistXCos / 2 + relevantMouseMoveDistXSin / 2;
  xScale = updatedRectWidth / origRectWidth;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeRightMiddle() {
  updatedRectWidth += relevantMouseMoveDistXCos + relevantMouseMoveDistXSin;
  translateX += relevantMouseMoveDistXCos / 2 + relevantMouseMoveDistXSin / 2;
  xScale = updatedRectWidth / origRectWidth;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeTopMiddle() {
  updatedRectHeight -= relevantMouseMoveDistYCos + relevantMouseMoveDistYSin;
  translateY += relevantMouseMoveDistYCos / 2 + relevantMouseMoveDistYSin / 2;
  yScale = updatedRectHeight / origRectHeight;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeBottomMiddle() {
  updatedRectHeight += relevantMouseMoveDistYCos + relevantMouseMoveDistYSin;
  translateY += relevantMouseMoveDistYCos / 2 + relevantMouseMoveDistYSin / 2;
  yScale = updatedRectHeight / origRectHeight;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

function resizeTopRight() {
  updatedRectWidth += relevantMouseMoveDistXCos + relevantMouseMoveDistXSin;
  updatedRectHeight -= relevantMouseMoveDistYCos + relevantMouseMoveDistYSin;
  translateX += relevantMouseMoveDistXCos / 2 + relevantMouseMoveDistXSin / 2;
  translateY += relevantMouseMoveDistYCos / 2 + relevantMouseMoveDistYSin / 2;
  xScale = updatedRectWidth / origRectWidth;
  yScale = updatedRectHeight / origRectHeight;
  scale.setAttribute('transform', 'scale(' + xScale + ',' + yScale + ')');
  translate.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')');
}

var svg = document.getElementById("main");

svg.addEventListener("mousemove", function(e) {

  if (newMousePosn) {

    // the former mouse pos'n
    oldMousePosn = {
      x: newMousePosn.x,
      y: newMousePosn.y
    };

    // the new mouse pos'n
    newMousePosn = {
      x: e.clientX,
      y: e.clientY
    };

    // the change in the mouse pos'n coordinates since the last move event
    var deltaMouseMove = {
      x: newMousePosn.x - oldMousePosn.x,
      y: newMousePosn.y - oldMousePosn.y
    };

    // the dir'n of this movement
    //var angleOfMouseMovement = Math.atan2(deltaMouseMove.y, deltaMouseMove.x);

    // the absolute distance the mouse has moved
    var mouseMoveDist = Math.sqrt(
      deltaMouseMove.x * deltaMouseMove.x +
      deltaMouseMove.y * deltaMouseMove.y
    );

    // the difference in direction between the mouse movement and orientation of the rectangle
    //var angleDifference = angleOfMouseMovement - rectangleAngle;

    // the portion of the mouse movement that is in the direction of the rectangle's +X and +Y orientation
    relevantMouseMoveDistXCos = deltaMouseMove.x * Math.cos(rectangleAngle);
    relevantMouseMoveDistXSin = deltaMouseMove.y * Math.sin(rectangleAngle);

    relevantMouseMoveDistYCos = deltaMouseMove.x * Math.cos(rectangleAngle + Math.PI / 2);
    relevantMouseMoveDistYSin = deltaMouseMove.y * Math.sin(rectangleAngle + Math.PI / 2);

    // resize the rectangle if necessary
    if (controlrm)
      resizeRightMiddle();
    else if (controllm)
      resizeLeftMiddle();
    else if (controltm)
      resizeTopMiddle();
    else if (controlbm)
      resizeBottomMiddle();
    else if (controltr)
      resizeTopRight();
  } else {

    // establish the mouse pos'n during the first mousemove event
    newMousePosn = {
      x: e.clientX,
      y: e.clientY
    };
  }

});

svg.addEventListener("mouseup", function(e) {
  controlrm = false;
  controllm = false;
  controltm = false;
  controlbm = false;
  controltr = false;
});

rightMiddle.addEventListener("mousedown", function(e) {
  controlrm = true;
});
leftMiddle.addEventListener("mousedown", function(e) {
  controllm = true;
});
topMiddle.addEventListener("mousedown", function(e) {
  controltm = true;
});
bottomMiddle.addEventListener("mousedown", function(e) {
  controlbm = true;
});
topRight.addEventListener("mousedown", function(e) {
  controltr = true;
});

// Code for changing the rectangle in the input
input.addEventListener("change", function() {

  rotateAngleDeg = input.value;

  var translation = (translateX + " " + translateY);
  var rotation = "rotate(" + rotateAngleDeg + " " + translation + ")";

  rotate.setAttribute("transform", rotation);
  //console.log(rotation);

  rectangleAngle = rotateAngleDeg * Math.PI / 180;
})
svg {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<div>
  <svg id="main" width="1000" height="250">
    <g id="rotate" transform-origin="0 0" transform="rotate(0 0 0)">
      <g id="trslt" transform="translate(100, 100)">
        <g id="scale">
          <path fill="red" stroke="red" d="M -50 -50 L -50 50 L 50 50 L 50 -50Z" />
          <rect id="rm" fill="black" stroke="black" x=45 y=-5 width=10 height=10 />
          <rect id="lm" fill="yellow" stroke="black" x=-55 y=-5 width=10 height=10 />
          <rect id="tm" fill="white" stroke="black" x=-5 y=-55 width=10 height=10 />
          <rect id="bm" fill="orange" stroke="black" x=-5 y=45 width=10 height=10 />
          <rect id="tr" fill="blue" stroke="black" x=45 y=-55 width=10 height=10 />
        </g>
      </g>
    </g>
  </svg>
</div>
<input id="rotate_input" type="text" placeholder="Change Angle" />

person K Scandrett    schedule 29.06.2017
comment
Спасибо за ответ, но я нашел решение без инвертирования поворота и перевода. - person JSmith; 30.06.2017
comment
Мне потребовалось несколько часов, чтобы разобраться, поэтому я ценю, что вы приняли мой ответ, даже если он вам не нужен. Рад, что в итоге добился результата - person K Scandrett; 30.06.2017
comment
Нет проблем, я не упомянул все ограничения в своем вопросе. Дело в том, что когда я инвертирую вращение и перемещаю, я поворачиваю все свои координаты, когда перетаскиваю объект, так что это дополнительная проблема. Но большое спасибо за ваше время. - person JSmith; 30.06.2017

Не на 100% работает, но, надеюсь, это должно помочь вам упростить и указать правильное направление. Проверьте эту функцию, которая использует матрицу преобразования SVG.
https://codepen.io/anon/pen/xrpPBy

Вы можете обновить свою функцию следующим образом:

function resizeTopMiddle()
{
  updatedRectHeight -= relevantMouseMoveDistSin;
  yScale = updatedRectHeight/origRectHeight;

  generalTX(xScale, yScale, rotateAnleDeg )
}

Вот пример вашего варианта использования: https://codepen.io/RTakes/pen/xrpLEe

Надеюсь, это поможет.

person RickTakes    schedule 28.06.2017
comment
Я посмотрю, спасибо за эту помощь, легко ли реализовать остальные контрольные точки? - person JSmith; 28.06.2017
comment
Думаю, я понимаю, что вы сделали, и это был не первоначальный вопрос. Я не хочу инвертировать контрольную точку. Я уже легко запрограммировал нижнюю среднюю контрольную точку, и интересна именно верхняя средняя, ​​поскольку она изменяет положение (перемещает) моего прямоугольника. Спасибо в любом случае - person JSmith; 28.06.2017
comment
Извините, я не до конца понял вопрос. Я обновляю пример и отвечаю. - person RickTakes; 28.06.2017
comment
Спасибо. Представьте, что в конце у меня будет 8 контрольных точек. - person JSmith; 28.06.2017