This question is a followup to the question: width/height after transform.
I am posting a new question because that question only solves the width and not the height.
The formula:
var x = $('#box').width()*Math.cos(rotationAngle)
+ $('#box').height()*Math.sin(rotationAngle);
works well for the width, what is the equivalent formula to calculate the height?
Thanks.
This is the best working formula I have come up with:
var h = $(obj).height() * Math.abs(Math.cos(deg)) + $(obj).width() * Math.abs(Math.sin(deg));
var w = $(obj).width() * Math.abs(Math.cos(deg)) + $(obj).height() * Math.abs(Math.sin(deg));
The below code will work out the bounding box for a rotated object in JavaScript.
var obj = document.getElementById("obj"); // Get object
var bx = obj.clientWidth; // Width of rectangle
var by = obj.clientHeight; // Height of rectangle
var t = /[0-9]+/.exec(obj.style.transform)[0] * Math.PI / 180; // Convert to radians
var x = Math.sin(t) * by + Math.cos(t) * bx; // The bounding box width
var y = Math.sin(t) * bx + Math.cos(t) * by; // The bounding box height
document.write(x.toFixed(2), " ", y.toFixed(2)); // The width and height of finished bounding box of item rounded to 2 decimal places
<div id="obj" style="width: 200px; height: 200px; transform: rotate(30deg); background: red;"></div>
The solution from #ChiMo will not work if the angle value is negative.
Fixed version:
var obj = document.getElementById("obj"); // Get object
var bx = obj.clientWidth; // Width of rectangle
var by = obj.clientHeight; // Height of rectangle
var t = /[0-9]+/.exec(obj.style.transform)[0] * Math.PI / 180; // Convert to radians
var x = Math.sin(t) * by + Math.cos(t) * bx; // The bounding box width
var y = Math.sin(t) * bx + Math.cos(t) * by; // The bounding box height
document.write(x.toFixed(2), " ", y.toFixed(2)); // The width and height of finished bounding box of item rounded to 2 decimal places
var wrapper = document.getElementById("wrapper"); // Get object
wrapper.style.width = Math.round(x) + 'px';
wrapper.style.height = Math.round(y) + 'px';
#obj {
width: 100px;
height: 100px;
background-color: red;
}
#wrapper {
border: 1px solid black;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: center;
}
<div id="wrapper">
<div id="obj" style="transform: rotate(-30deg)"></div>
</div>
Well, your previous question involved a square. Squares have the same dimensions all the way around. So, unless there's something funky going on, your height should be exactly the same as your width.
Related
I need to center an object in a canvas based on its rotation. I can't figure out the maths.
What information do I have?
x, and y coordinates of the top left corner (see red circle of image)
width and height of the object
the rotation value in degrees
What have i tried so far?
// center horizontally
if (curretElement === null) return;
curretElement.x((canvas.width() / 2) - ((curretElement.width() * curretElement.scaleX()) / 2));
canvas.draw();
// center vertically
curretElement.y((canvas.height() / 2) - ((curretElement.height() * curretElement.scaleY()) / 2));
canvas.draw();
This centers the image when it's not rotated.
currentElement is the selected object.
canvas is the room where the object should be centered in.
You can calculate the coordinates this way:
imagine that you have your object centered on the canvas
calculate the coordinates of the top left corner relative to the center of the canvas
rotate the object around the center of the canvas and calculate where the top left corner ends up relative to the center of the canvas
translate the relative coordinates of the top left corner back to absolute coordinates
Here is a function that does the calculation:
function calculateXY(canvasWidth, canvasHeight, width, height, angle) {
//calculate where the top left corner of the object would be relative to center of the canvas
//if the object had no rotation and was centered
const x = -width / 2;
const y = -height / 2;
//rotate relative x and y coordinates by angle degrees
const sinA = Math.sin(angle * Math.PI / 180);
const cosA = Math.cos(angle * Math.PI / 180);
const xRotated = x * cosA - y * sinA;
const yRotated = x * sinA + y * cosA;
//translate relative coordinates back to absolute
const canvasCenterX = canvasWidth / 2;
const canvasCenterY = canvasHeight / 2;
const finalX = xRotated + canvasCenterX;
const finalY = yRotated + canvasCenterY;
return { x: finalX, y: finalY };
}
UPDATE :first try is really bad so i update code. which actually work and keep your left corner in center of container, just fill angle input
i want to comment and ask more but i can't and this thing(bounty) is tempting
Not heavy depend on java script. may be it what you need second attempt.
Corner is container and content in before. Rotate but it remains there. does it help? comment it.
<!DOCTYPE html>
<html lang="en">
<body>
<style>
body{
margin:0;
}
#container{
display :flex;
position: absolute;
width:100%;
height:100%;
}
#ram{
display:flex;
background-color:black;
position:absolute;
margin:auto;
top:50%;
right:50%;
}
#ram::before{
content: "";
position:absolute;
height:40px;
width:400px;
background-color: #000;
}
</style>
<input type="number" id="a" onchange = "forf()">
<div id = "container">
<div id = "ram">
</div>
</div>
<script>
function forf(){
var a = document.getElementById("a").value;
document.getElementById("ram").style.transform = "rotate(" + a + "deg)";
}
</script>
</body>
</html>
I am trying to randomly place a div, but I am getting a type error. It says the element is undefined, but I thought that I was defining it with the const line of line 1. In my CSS file, the position of the div is absolute and there's a background image set. I can tell in the console.log that I am getting the random numbers that I want. I am just having a little trouble attaching those coordinates to the div.
const animal = document.querySelectorAll('.animal');
function getRandomPos(animal) {
var x = screen.width;
var y = screen.height;
var randomX = Math.floor(Math.random() * x);
var randomY = Math.floor(Math.random() * y);
console.log(randomX, randomY);
let rect = animal.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
animal.style.left = randomX;
animal.style.top = randomY;
}
One major issue was already addressed in the comments - querySelectorAll returns an HTMLCollection rather than a single element, so you'll need querySelector.
Also, you'll need to add "px" units to the lines where you're setting the element's style (see below).
UPDATE
Questioner mentioned having multiple randomly moving elements, so I've added an example that includes how that might be done using IDs as an argument to the setRandomPos function.
function setRandomPos(target) {
const element = document.getElementById(target);
// var x = screen.width;
var x = 400; // Just smaller numbers for the example
// var y = screen.height;
var y = 200;
var randomX = Math.floor(Math.random() * x);
var randomY = Math.floor(Math.random() * y);
// Remember to add px for units
element.style.left = randomX + 'px';
element.style.top = randomY + 'px';
}
.randMove {
position: fixed;
}
button {
font-size: 20px;
z-index: 1;
position: relative;
}
<div id="animal" class="randMove">
<img src="https://upload.wikimedia.org/wikipedia/en/thumb/e/e7/Animal_%28Muppet%29.jpg/220px-Animal_%28Muppet%29.jpg" alt="Animal">
</div>
<div id="grover" class="randMove">
<img src="https://vignette.wikia.nocookie.net/muppet/images/f/f7/GroverFullFigure2.png/revision/latest?cb=20190222025220" alt="Grover">
</div>
<button onClick="setRandomPos('animal')">Move Animal</button>
<button onClick="setRandomPos('grover')">Move Grover</button>
I am trying to get the rotation degree from div's I rotate to create a line pattern.
Only now I am running into a problem. I need the rotation(deg) from the div's to calculate where the next line needs to appear. But when I try to get the value from a div with style.transform and convert the matrix values I still get the wrong degrees.
In my testing case I have a div that is rotated 150deg, but I get 30 deg back and this will not work for me unfortunatly. Please help, how do I get the 150deg value back?
Here is the code:
HTML:
<div class="linesBox" id="linesBox">
<div class="line1 lines" id="line1" style="float: left;
margin: 200px 0 0 100px;
position: fixed;
border-top:0.5px solid black;
width: 100px;
transform: rotate(150deg);"></div>
<!-- <div class="line2 lines" id="line1" style="float: left;
margin: 174px 0 0 193.3px;
position: fixed;
border-top:0.5px solid black;
width:100px;
transform: rotate(0deg);"></div> -->
</div>
JavaScript:
const linesBox = document.getElementById('linesBox');
let lastLineWidth;
let angle;
let lineWidthCount;
let lineHeightCount;
function createLines(){
//Last line div in a var and a var to get the computated value
let lastLine = linesBox.lastElementChild;
var st = window.getComputedStyle(lastLine, null);
//Get the width and angle of the last line and place them in a var
lastLineWidth = parseFloat(lastLine.style.width);
lastLineXPos = parseFloat(lastLine.style.marginLeft);
lastLineYPos = parseFloat(lastLine.style.marginTop);
let lastLineAngle = st.getPropertyValue("transform");
console.log(lastLineWidth, lastLineXPos, lastLineYPos);
//Get and map the Matrix value from transform rotate() and set it to lastLineAngle
var values = lastLineAngle.split('(')[1],
values = values.split(')')[0],
values = values.split(',');
//Set each value of the matrix values to a var
let a = values[0];
let b = values[1];
let c = values[2];
let d = values[3];
//Take the correc value from the matrix values and place it in the formula and save the outcome in a var
angle = Math.round(Math.asin(b) * (180/Math.PI));
console.log(angle);
//Calculate margin left starting position for the next line
//Get sin en cos values by angle
let yChangeOne = lastLineWidth * Math.sin(angle / 180 * Math.PI) / 2;
let xChangeOne = parseFloat(lastLineWidth - lastLineWidth * Math.cos(angle / 180 * Math.PI)) / 2;
// let yChangeOne = lastLineWidth * sinOutcome / 2;
// let xChangeOne = lastLineWidth - lastLineWidth * cosOutcome;
console.log(yChangeOne, xChangeOne);
let newYPos;
let newXPos;
if( angle <= 89 && angle >= 1 ){
newYPos = lastLineYPos + yChangeOne;
} else if ( angle >= 91 && angle <= 179 ){
newYPos = lastLineYPos - yChangeOne;
}
console.log(newYPos);}
//Get the start position for the next line
createLines();
The angle should return 150deg not 30deg otherwise my if statement will not work. Please help :)
Both 30° and 150° have the same sine. You also need to take the cosine into account. Instead of Math.asin(b), use
Math.atan2(b, a)
Btw, if you are just calculating the angle to calculate its sine and cosine again, then spare this step (Math.sin(angle...)). You have sine and cosine right there, so just use them.
Need help understanding this code, which is used to make an image move in an elliptical shape. What I don't understand, is the formula for e, px and py variable. What exactly is the e variable defined the complex way it is? I know it uses some mathematical formulas but i don't know which ones.
var b = 125;
var h = 115;
var rx = 7;
var ry = 4;
var e = 0;
function update() {
setInterval(function() {
e = (e + Math.PI / 360) % (Math.PI * 2);
rotate(e);
}, 10);
var lyd = new Audio("Vedlegg/skoytelyd.mp3");
lyd.play();
}
function rotate(e) {
var px = b + rx * Math.cos(e)*b/2;
var py = h + ry * Math.sin(e)*h/2;
document.getElementById("punkt").style.left = px + "px";
document.getElementById("punkt").style.top = py + "px";
}
</script>
<style>
div {
position: fixed;
}
#sentrum {
background: black;
left: 100px;
top: 50px;
}
#skoyteloper {
position: absolute;
top: 190px;
left: 450px;
width: 60px;
height: 60px;
}
</style>
</head>
<body>
<div id="sentrum"></div>
<img src="Vedlegg/bane.jpg" id="imgBane"></img>
</div>
<div id="punkt">
<img src="Vedlegg/skoyteloper.png" id="skoyteloper"></img>
</div>
TILBAKE
</body>
Sinus and cosinus:
Think of a triangle with one 90° angle. 1 line is horizontal, another line is at the right side and is vertical, the third line goes from bottom-left to top-right.
The angle on the left we call e (yes,it is the e in your function)
sinus of e is defined as the vertical line on the right divided by the diagonal line; cosinus e = horizontal line (which is touching the angle e) / diagonal.
--
Now draw a circle with middle at angle e and radius = the length of the diagonal.
If you raise the angle e you will see the vertical line get bigger and the horizontal line get smaller (keep the length of the diagonal constant), until you reach 90°. Then of course you can go beyond 90°, then the vertical line can be on the left. Further than 180° the vertical line will point down (negative coordinate), ...
So that's one of the uses of sin and cos: if you set an angle they give you an y-value and a x-value, showing you 1 point on a circle. It's always a number between -1 and +1. example: sin(0) = 0 (no vertical component), cos(0) = 1
This code here below gives you a circle around center (0,0) and radius 100. Feed this function a bunch of values for e and you get as many points on a circle
function rotate(e) {
var px = 100 * Math.cos(e);
var py = 100 * Math.sin(e);
}
Now, if instead of 100 * cos(e) you put 200 * cos(e), then it's not a circle anymore. Every x coordinate will be twice as far (compared to the circle). A different rx and ry will result in an ellipse.
your variables b & h are for pushing the center of the ellipse to somewhere inside the image/div/canvas/... rather than in a corner (then you clip most of the ellipse).
Does this help?
I want to get actual height of element when rotated 3d on x axis. I'll try to explain with graphics below:
Element's normal height: 200px
Actual height is 118px when rotate 45 degree with 100px perpective:
Actual height is 138px when rotate 45 degree with 1000px perpective:
Normal formule for calculate this height value (without perpective):
x = h * sin(angle)
Height must 142px with this formule. But it's diffrent from this value. Probably perspective changes height. But I don't find any formule for calculate this height.
Does anyone have any idea?
I benefited from efe's comment and calculated real view height of rotated element.
There is technical explanation about solution on djjeck's answer.
You can view this question's answer with an example: http://jsfiddle.net/TqJJL/3/
Calculate real height with this code:
// initial coordinates
var A = 0;
var B = width; // default size of element
// new coordinates
A = calc(A, angle*Math.PI/180, p);
B = calc(B, angle*Math.PI/180, p);
// translate back
A += width/2;
B += width/2;
if(B < A) { var tmp = A; A = B; B = tmp; } // swap
var realHeight = B-A;
function calc(oldx, angle, p) {
var x = Math.cos(angle) * oldx;
var z = Math.sin(angle) * oldx;
return x * p / (p+z);
}