Rotating a square towards a certain point - javascript

I'm trying to make the shooter0 rotate towards the character (which will be moving around constantly). I tried to using the atan() and then converting that to an angle but the shooter0 won't rotate.
var shooter0 = document.getElementById('shooter0');
var character = document.getElementById('character');
var tracker0 = shooter0.getContext('2d');
// The cordinates for the character and shooter0
var characterLeft = 530;
var characterTop = 180;
var shooter0Left = 960;
var shooter0Top = 470;
while (characterLeft >= 700){
setInterval(startShooter, 1000);
}
function startShooter(){
//Getting all the variable to be able to calculate the angle of the hypotenuse
var dX = characterLeft - tracker0Left;
var dY = characterTop - tracker0Top;
var arcTan = Math.atan(dX/dY)* 180/Math.PI;
var cx = shooter0.width/2;
var cy = shooter0.height/2;
tracker0.save();
tracker0.translate(cx, cy); // pivot point
//rotating the square towards the character
tracker0.rotate(arcTan * Math.PI/180);
//Drawing the square
tracker0.fillRect(400, 300, 100, 100);
tracker0.restore();
}
HTML:
<canvas id="character" height="50px;" width="50px;"></canvas>
<canvas id="shooter0" height="100px;" width="100px;"></canvas>
And CSS:
#character{
position: absolute;
top: 180px;
left: 530px;
border: 3px solid black;
background-color: orange;
}
#shooter0{
position: absolute;
left: 960px;
top: 470px;
border: 2px solid black;
background-color: #B40404;
}
Sorry if you find the code rather messy. Here's a fiddle with all of my code if you find that useful. https://jsfiddle.net/Snubben/tc0j4psz/3/
Please don't use any JQuery.

I couldn't get your fiddle to work for some reason, so I created a little example.
The thing I notice in your code:
var arcTan = Math.atan(dX/dY)* 180/Math.PI; : Math.atan returns an angle in radians. And you convert it to degrees by 180/Math.PI
Only to convert it back to radians here again:
tracker0.rotate(arcTan * Math.PI/180);
Then, for calculating angles (in radians), I think Math.atan2 is the most easy to use: Math.atan2 - MDN
The usage of Math.atan2 to calculate an angle between two points is:
Math.atan2(point2.y - point1.y, point2.x - point1.x)
With that information, I think you can get very far.
demo fiddle

Related

Calculate 45 degree to point to left top corner of the page

Im trying to point the red div towards the corner of the window using transform rotate.
The Yellow is 45deg fixed, just for reference.
The Blue points to the left top corner using the innerHeight and innerWidth as points.
And the Red trys to mimic the Blue by calculating 45 + some offset, it must aways have the same rotation as the Blue but without using innerHeight and innerWidth as points.
This is the closest i got of makeing it work was using this code:
window.onresize = () => calcAngle()
var calcAngle = () => {
console.clear()
var x1 = 0, y1 = 0;
var x2 = window.innerWidth, y2 = window.innerHeight;
var a = (Math.atan2((y2 - x1), (x2 - y1)) * (180 / Math.PI));
document.querySelectorAll(".pointer")[1].style.transform = "translate(50%, -50%) rotate("+a+"deg)"
var of = x2/y2;
var ang = 45;
var calc = ang - (ang*of-ang)
document.querySelectorAll(".pointer")[2].style.transform = "translate(50%, -50%) rotate("+(calc)+"deg)"
console.log(a, calc)
}
calcAngle();
body {
overflow: hidden;
}
.pointer {
width: 200px;
height: 20px;
opacity: .7;
background: blue;
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, -50%);
clip-path: polygon(100% 0%, 100% 100%, 0% 50%);
}
.pointer:nth-child(1){
background: yellow;
transform: translate(50%, -50%) rotate(45deg);
}
.pointer:nth-child(3){
background: red;
}
<div class="pointer"></div>
<div class="pointer"></div>
<div class="pointer"></div>
Using the code as example, calc must always have the same value of a but using 45 deg as reference.
Of course as you show in your question, the simplest approach is to use the atan(y/x) * 180 / PI to get the entire angle. This is reflected below as refAngle.
Since your condition requires that it be an offset of 45 degrees, this requires more advanced math, using the law of sines in addition to basic trigonometry. We have enough information based on the ratio of width/height of the screen to find the information, but it ends up being a very complex formula. This is reflected below in two steps, first sinOff to get the sine of the offset angle relative to 45 degrees, and then off once we've done the asin and conversion from radians to degrees.
This snippet demonstrates that the two angles agree, no matter how the browser window is resized.
const x = window.innerWidth;
const y = window.innerHeight;
const { sin, atan, asin, sqrt, PI } = Math;
const sinOff = sin(atan(y/x)) / (sqrt(2)*y) * (x-y);
const off = asin(sinOff) * 180 / PI;
const angle = 45 - off;
const refAngle = atan(y/x) * 180 / PI;
console.log(angle, refAngle);
Note, since the formula is so complex, I'm using destructuring to reduce the Math. clutter.

How do I get the correct degress from style.transform rotate after I converted the matrix values?

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 mathematical formula for ellipse in JavaScript

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?

Create an Arc and a Pie using DIV DOM element

I have a created an ellipse using div DOM element.
var body = document.querySelector('body');
var div = document.createElement('div');
div.style.borderRadius = '50%';
div.style.border = '1px solid red';
div.style.left = '60px';
div.style.top = '60px';
div.style.width = '100px';
div.style.height = '100px';
body.appendChild(div);
It looks like the image below:
I want also to create an arc and a pie.
In the second image above, the user will just input the starting angle and the end angle of the arc. In our case, the starting angle is 180 degrees and the ending angle is 360 degrees.
I want also to create a pie, wherein the user must input the inside radius of the circle/ellipse, starting angle and ending angle.
In the third picture, the inside radius is 50% of the width of the circle/ellipse, the starting angle is 90 degrees and the ending angle is 360 also.
Is it possible?
P.S: I don't want to draw it in the canvas or use svg.
As i said canvas is very good solution to draw this kind of things.however since you don't want to use canvas you can use border styles to draw arcs but angle of arc should be 90deg multiples like 0 90 180 270 360.however start angle can be any angle 0,5,10,7...
here is an example.
to get the effect of 2nd arc you given, enter start angle as 0 and end angle as 180. because stranded angle system is : see following picture
run this code
var border = ['border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color'];
var circle;
var standeredRotation = 135;
function getinput() {
circle = document.getElementById("circle");
var startAngle = document.getElementById("startangle").value;
var endAngle = document.getElementById("endtangle").value;
var angle = endAngle - startAngle;
if (angle % 90 != 0) {
alert("plz enter 90's multiples");
} else {
var parts = angle / 90;
draw(parts, startAngle);
}
}
function draw(parts, startAngle) {
var style = "";
for (var i = 0; i < parts; i++) {
style += border[i] + ": #FF4E4E;";
}
circle.setAttribute("style", style);
totalAngle = standeredRotation + parseInt(startAngle);
circle.style.transform = 'rotate(' + totalAngle + 'deg)';
}
#circle {
border-radius: 50%;
border: 10px solid transparent;
height: 100px;
width: 100px;
margin: 10px auto;
}
<body>
<div class="user-input">
<label>start angle</label>
<input type="text" id="startangle" value="0" />
<label>end angle</label>
<input type="text" id="endtangle" value="180" />
<button onclick="getinput()">draw</button>
</div>
<div id="circle">
</div>
</body>
for your last circle[2 overlap circles] angles are 0 and 270.to close circles you can position 2 divs and rotate them.

Javascript Image Pan / Zoom

By combining some CSS and Jquery UI / draggable I have created the ability to pan an image and with a little extra JS you can now zoom the image.
The problem I am having is that, if you zoom in the image's top left corner is fixed, as you would expect. What I would like is for the image to stay central (based on the current pan) so that the middle of the image stays in the middle of the container whilst getting larger.
I have written some code for this but doesn't work, I expect my maths is wrong. Could anyone help?
I want it to work like this does. When you scroll into an image it keeps the image centered based on the current pan rather than zooming out from the corner.
HTML:
<div id="creator_container" style="position: relative; width: 300px; height: 400px; overflow: hidden;">
<img src="/images/test.gif" class="user_image" width="300" style="cursor: move; position: absolute; left: 0; top: 0;">
</div>
Javascript:
$("#_popup_creator .user_image").bind('mousewheel', function(event, delta) {
zoomPercentage += delta;
$(this).css('width',zoomPercentage+'%');
$(this).css('height',zoomPercentage+'%');
var widthOffset = (($(this).width() - $(this).parent().width()) / 2);
$(this).css('left', $(this).position().left - widthOffset);
});
Long story short, you need to make a transform matrix to scale by the same amount as the image and then transform the image's position using that matrix. If that explanation is complete greek to you, look up "image transforms" and "matrix math".
The beginning of this page is a pretty good resource to start with even though it's a different programming language:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/geom/Matrix.html
Anyway, I've implemented those methods in some projects of my own. Here's the zoom in function from something I wrote that functions the way you want:
function zoomIn(event) {
var prevS = scale;
scale += .1;
$(map).css({width: (baseSizeHor * scale) + "px", height: (baseSizeVer * scale) + "px"});
//scale from middle of screen
var point = new Vector.create([posX - $(viewer).width() / 2, posY - $(viewer).height() / 2, 1]);
var mat = Matrix.I(3);
mat = scaleMatrix(mat, scale / prevS, scale / prevS);
point = transformPoint(mat, point);
//http://stackoverflow.com/questions/1248081/get-the-browser-viewport-dimensions-with-javascript
posX = point.e(1) + $(viewer).width() / 2;
posY = point.e(2) + $(viewer).height() / 2;
$(map).css({left: posX, top: posY});
return false;//prevent drag image out of browser
}
Note the commands "new Vector.create()" and "Matrix.I(3)". Those come from the JavaScript vector/matrix math library http://sylvester.jcoglan.com/
Then note "transformPoint()". That's one of the functions from that ActionScript link (plus hints on http://wxs.ca/js3d/) that I implemented using sylvester.js
For the full set of functions I wrote:
function translateMatrix(mat, dx, dy) {
var m = Matrix.create([
[1,0,dx],
[0,1,dy],
[0,0,1]
]);
return m.multiply(mat);
}
function rotateMatrix(mat, rad) {
var c = Math.cos(rad);
var s = Math.sin(rad);
var m = Matrix.create([
[c,-s,0],
[s,c,0],
[0,0,1]
]);
return m.multiply(mat);
}
function scaleMatrix(mat, sx, sy) {
var m = Matrix.create([
[sx,0,0],
[0,sy,0],
[0,0,1]
]);
return m.multiply(mat);
}
function transformPoint(mat, vec) {
return mat.multiply(vec);
}

Categories