Как мне правильно настроить отображение 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"/>
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" />
Не на 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
Надеюсь, это поможет.