Here is modified code originally tooken from this post.
Resizing the rectangle on the Right middle, bottom middle and right bottom control point is fine as I don't need to change the translate coordinates in order to make the resize work. Now my problem as you can see is that my resizing on the top middle (same for the left middle, left bottom...) of my rectangle when the rotate angle is different from 0 doesn't work as it visually changes position when I resize it.
I really don't know how to change that so any help is highly appreciated.
note: change angle to 0 in the input field and you'll see the code working properly here's the JSFiddle link.
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"/>
Not 100% working, but this should hopefully help you simplify and point you in the right direction. Checkout this function which uses the SVG transform matrix.
https://codepen.io/anon/pen/xrpPBy
You can update your function as so:
Here is an example with your use case: https://codepen.io/RTakes/pen/xrpLEe
Hope that helps.
There's quite a bit to it and rather difficult to explain the steps, but essentially:
Translate
to afterRotate
within thesvg
. That made it easier to resize the object without needing to take into account the direction that would be affected by the rotation.transform="rotate(0 0 0)"
. The second two give the rotation's centre.I've implemented the sides and one corner, I'll leave it with you to follow the pattern - for the Top Left it's just grabbing code from the Top and the code from the Left and combining them like I've done already within Top Right
I see the rotation doesn't always happen around the box's current centre point, so that's something that I presume you'll want to look at correcting.
External demo (same as Stack Snippet below): https://jsfiddle.net/bcjopdqn/2/