Rotate a div towards the direction of the mouse using atan2() - javascript

I would like the mouse to align with the top of the div and the div should rotate when the mouse moves with the top part of the div aligned with the mouse. I want to use atan2. It should look something like this.
Javascript:
$(function() {
var stick = $(".stick"), sHeight = stick.outerHeight(),
sWidth = stick.outerWidth(), atan,
sTop = stick.offset().top, sLeft = stick.offset().left;
$(document).on("mousemove", function(e) {
// console.log(e.pageX, " ", e.pageY)
atan = Math.atan2(e.pageY - sTop , e.pageX - sLeft )
console.log(atan)
stick.css({"transform" : "rotate(" + atan + "rad)"} )
})
})
css:
.wrapper{
width: 500px;
height: 400px;
position: relative;
border:1px solid green;
}
.stick{
width: 3px;
height: 200px;
position: absolute;
left: 50%;
top: 50%;
background: green;
transform: rotate(90deg);
}
HTML:
<div class="wrapper">
<div class="stick"></div>
</div>

I made something that works here.
It seems you're not centring properly - you need to take into account the width of the div and the centre point of the container
div.$(function(){
var stick = $(".stick"), sHeight = stick.outerHeight(),
sWidth = stick.outerWidth(), atan,
sTop = stick.offset().top, sLeft = stick.offset().left;
$(document).on("mousemove", function(e){
atan = Math.atan2(e.pageY - 200 , e.pageX - 250) + Math.PI/2;
console.log(atan);
stick.css({"transform" : "rotate(" + atan + "rad)"} );
});
});
(I also removed the rotation in the css, and positioned the stick in the centre.)

The problem is that the angle computation phi=atan2(y,x) assumes a "normal" Cartesian coordinate system where the y axis points upwards. In screen coordinates, it points downwards. Thus you should use phi=atan2(-y,x).
But to be sure you should try out and report where the bar points to when using rotations 0deg and 90deg. With your code the rotation center is the middle of the bar, so orientation is difficult to determine, but it seems that 0deg points upwards and angles are applied clockwise. Thus for the inner coordinate system, where 0° is the X axis and 90° the Y axis, X = centery-y and Y=x-centerx, thus
angle = atan2(x-centerx, centery-y)

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 to find out if an object is touching another object in JS

(excuse my bad english, I am 13 years old)
alright, even though i just joined stackoverflow today, I have been coding for a while. I'm trying to make a simple game (and may make it something bigger later) and I want the hammer (the player sprite) not be able to go through the box toward the middle of the screen, but I don't know how. here is what I have:
var sq = document.getElementById("box");
var posX = 0;
var posY = 0;
var rot = "rotate(0deg)";
var id = null;
function move(object, pixels, xa){
if(xa == true) {
posX+=pixels;
object.style.left = posX + 'px';
}else{
posY+=pixels;
object.style.top = posY + 'px';
}
}
OBJect.style.left = "200px";
OBJect.style.top = "200px";
document.addEventListener('keydown', logKey);
function logKey(e) {
if (`${e.code}` == "ArrowRight") {
rot = "rotate(90deg)";
sq.style.transform = rot;
move(sq, 5, true);
if(posX > 470){
posX = 5;
}
}
if (`${e.code}` == "ArrowLeft") {
rot = "rotate(270deg)";
sq.style.transform = rot;
move(sq, -5, true);
if(posX < 0){
posX = 465;
}
}
if (`${e.code}` == "ArrowDown") {
rot = "rotate(180deg)";
sq.style.transform = rot;
move(sq, 5, false);
if(posY > 465){
posY = 5;
}
}
if (`${e.code}` == "ArrowUp") {
rot = "rotate(0deg)";
sq.style.transform = rot;
move(sq, -5, false);
if(posY < 0){
posY = 470;
}
}
}
setInterval(function(){
xaxis.innerHTML = "x: " + posX;
yaxis.innerHTML = "y: " + posY;
rotate.innerHTML = rot;
},1);
#myContainer {
width: 500px;
height: 500px;
position: relative;
background: black;
outline: red solid 10px;
}
#box {
width: 30px;
height: 30px;
position: absolute;
background-color: gray;
}
#OBJect {
width: 30px;
height: 30px;
position: absolute;
background-color: gray;
}
<!DOCTYPE html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<style>
/*style would go here/*
</style>
<body>
<div id="myContainer">
<img src="https://cdn.glitch.com/7f9c2ae2-9b45-42a1-a387-380de7f5d3bd%2Fhammer.png?v=1615308683807" alt="hammer" id="box">
<div id="OBJect"></div>
</div>
<br><br>
<div id="xaxis"></div>
<div id="yaxis"></div>
<div id="rotate"></div>
<script>
//script would go here
</script>
</body>
</html>
yeah, yeah, I know. I could definetly improve, but I only know basic things,and some of these from either Stackoverflow or w3schools, and yes, I know there is a lot of solved answers with this problem, but I get confused by them because they are too complicated for me. I just request easy, simple code to understand (if it isn't, please label things so I know).
sorry if this is too much, I just need help :/
so to do this you need to know the 4 corners of each element then you need to check if the other object is within the players bounds
they're both rectangles and to be touching 1 of these statements have to be true
the top left corner of the square is to the right of the top left corner of the player and the top left corner of the square is to the left of the top right corner of the player while the top left corner of the square is less than the y of the top side and higher than the y of the bottom side
the top right corner of the square is to the left of the top right corner of the player and the top right corner of the square is to the right of the top left corner of the player while the top right corner of the square is less than the y of the top side and higher than the y of the bottom side
same as 1 & 2 but with the bottom left and right corners
if one of the corners has the same x and y as a corner on the other object or if the position of one object is the same as the other
a second way to do this is using Pythagoras theorem to get the distance between two points
a^2 + b^2 = c^2
how that would look in code
let c = Math.sqrt(Math.pow(Math.abs(x1 - x2), 2) + Math.pow(Math.abs(x2, y2), 2))
this is a little tricky but the distance between two points is a triangle in a sense so the distance on x and y form the two legs then to get the actual distance we need the hypotenuse which is what Pythagoras theorem gets us. So to get a and b we need to get the absolute value of the first minus second x and y to get the distance on x and y then we square them with Math.pow() and add them but that gives us c^2 and we just want c so we get the square root with Math.sqrt() which gives us the distance then the one other thing we have to do is get the center of the objects to use as a and b. Since you're working with javascript on a webpage the X and Y values are for the top left corner so you need to add half the width and height to x and y appropriately to get the center of the object, then you can use the distance formula. the only problem with this approach is that it works best for circles because every point around the edge is equally distant from the center which isn't true for a square.
So personally I would use the first method, you can get the other corners by using width and height to add to the position of the top left corner to get the other positions. it's more code but more precise than distance because you're checking the bounds of each object rather than checking distance from center
I also joined today and I am 12. since the hammer is an img, you can use css:
I think your question was that you want to move the hammer, if yes:
var left = 0; /*left and top can be edited in your code but*/
var top = 0;/*you have to reset them using the code below*/
var hammer = document.querySelector('#hammer');
hammer.style.left = left + 'px';
hammer.style.top = top + 'px';
#hammer {
position: absolute;
left: 0px;
right: 0px;
}/*set left and right via js*/
<!--just add an id like #hammer to the hammer-->

How to detect objects on the canvas with click event

Hi I am using a hashmap that allows me to efficiently detect objects in the given coordinates. However it is working perfectly , the problem lies with using the mouse to gather the position of the mouse within the canvas down to the pixel. I have been using the offsetX and offsetY methods for the event to gather some offset but it seems there is an offset I am unaware of and may have something to do with either:
1.using scaling on the canvas , Note: ive tried to fix this by division of the renderscale, this works with everything else so should be fine here.
mouseoffset is not accounting for parts of the page or is missing pixels at a low level (maybe 20) but divided by the render scale thats massive.
3.I am using a cartesian coordinate system to simplify things for the future , so the game map is in cartesian and may have to do with the problem.
I will not be supplying all the code because it is allot of work to go through it all so i will supply the following :
the html/css canvas code
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Game</title>
</head>
<body onload="jsEngine = new JsEngine(24, 24, .1); " >
<div class ="wrapper">
<canvas id="canvas" width="1920" height="1080"></canvas>
</div>
<style>
.wrapper {
position: relative;
width: auto;
height: 900px;
}
.wrapper canvas {
position: absolute;
left: 90px;
top: 50px;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 90%;
height: 90%;}
.GUI{
top: -315px;
left: -302px;
position: absolute;
width: 300px;
height: 300px;
background-color: cadetblue;
opacity: .5;
word-wrap: break-word;}
img{
image-rendering: optimize-contrast;
}
</style>
<div id = GUI class = "GUI"></div>
<!-- Libraries -->
<script src="../myapi/JSONE.js"></script>
<script src="../myapi/engine/SpacialHash.js"></script>
</body>
</html>
2.the javascript click function
//Click on objects
let onClick = function(event){
let canvas_ctx = document.getElementById("canvas").getContext("2d");
let canvasOffsetX = canvas_ctx.canvas.width/2;
let canvasOffsetY = canvas_ctx.canvas.height/2;
let mousePosX = event.clientX;
let mousePosY = event.clientY;
let mouseX =jsEngine.cameraFocus.x-canvasOffsetX/jsEngine.renderScale+(mousePosX)/jsEngine.renderScale;
let mouseY = jsEngine.cameraFocus.y+(canvasOffsetY)/jsEngine.renderScale+((-mousePosY)/jsEngine.renderScale);
console.log("sum to",mouseX,mouseY);
//My hashMap to place the mouse coordinates on the game map
let clickPosition = hm.find({x:mouseX,y:mouseY,width:1,height:1});
if(clickPosition.length===1){
let gameObject = jsEngine.gameObjects[clickPosition[0].range.id];
//console.log(gameObject.transform.x,gameObject.transform.y,mouseX,mouseY);
let clickBox = {};
let picture = gameObject.texture;
guiCreateClickBox(clickBox,gameObject.id,1200,500,picture);
}else if(clickPosition.length>1) {
for (let i = 0; i < clickPosition.length; i++) {
let gameObject = jsEngine.gameObjects[clickPosition[i].range.id];
if (gameObject instanceof PlayerShip|| gameObject instanceof Bullet)
continue;
let clickBox = {};
let picture = gameObject.texture;
guiCreateClickBox(clickBox,gameObject.id,1200,500,picture);
//console.log(gameObject.transform.x,gameObject.transform.y,mouseX,mouseY)
}
}
};
// Listeners
//Click on objects
document.getElementById("canvas").addEventListener("click", onClick);
the making of the map and scale :Note: this is done via onPreRender
function drawBackground(canvas_ctx, renderScale, imageResource) {
let img = imageResource.mapBackground;
let mapWidth = 1000000;
let mapHeight= 1000000;
let zoom = 1;
mapWidth *= renderScale / zoom;
mapHeight *= renderScale / zoom;
// Render the Background
canvas_ctx.fillStyle = canvas_ctx.createPattern(img, 'repeat');
canvas_ctx.scale(zoom, zoom);
canvas_ctx.fillRect(-mapWidth / 2, - mapHeight / 2, mapWidth, mapHeight);
//if (jsEngine.cameraFocus.x > 1000000) {}
canvas_ctx.scale(1/zoom, 1/zoom);
}
The rendering method used for playership
renderGameObject(gameObject) {
let x = gameObject.transform.x * this.renderScale;
let y = -(gameObject.transform.y * this.renderScale);
let rotation = Math.radians(gameObject.transform.rotation);
let width = gameObject.transform.width;
width *= this.renderScale;
let height = gameObject.texture.height;
height *= this.renderScale;
// Render the gameObject
this.canvas_ctx.translate(x, y);
this.canvas_ctx.rotate(rotation);
this.canvas_ctx.drawImage(gameObject.texture, 0, 0, width / this.renderScale, height / this.renderScale, // Make sure the image is not cropped
-width/2 , // X
-height/2 , // Y
width, height); // width and height
this.canvas_ctx.rotate(-rotation);
this.canvas_ctx.translate(-x, -y);
}
the issue to solve is to make it so that when you click on any given quadrant of the canvas it will return -+ for top left, -- bottom left , -+ topright, +- bottomright, as well as being applied to the render scale which at the moment is .1 so just divide your mouse and canvas coords like shown above and you should be able to get the same results.
Things to keep in mind :
the jsEngine.cameraFocus is set to the playerships x and y coordinates(which are set to the 0,0 posiiton on the map) (which are also in the middle of the ship)
the top left of the canvas is still 0,0 and ++ is still toward the bottom right so theoretically minusing half the canvas width/height then adding the offsets X and Y. this should be working but at my map coordinate -4000,-4000 i get ~-3620,-3295 and at +4000,+4000 I get 3500,3500. (The reason why the canvas 0,0 is not where the ship is , is to make the ship in the middle of the screen)
If you have questions about anything based on code that needs to be supplied please ask via comment . Please note if you have problems with the format of the code supplied I have nothing to say about it . all I need is the click function working on the canvas model i set up in cartesian format.
ps: jQuery is not a solution its a problem please use vanilla js.
I found out why it was off , my canvas has a offset of 90 px and 50 px as well as the main problem that the canvas is only 90% of its origonal size (also in css). If anyone can give me help for how to adjust to these issues please reply in comment . until then I beleieve I have solved my own issue .

Smoothing movement effect that follows mouse position

I want to create a very simple effect moving a background image when the mouse moves. For that Im recording the mouse position and using it to modify a css property:
$('#landing-content').mousemove(function(e){
var amountMovedX = (e.pageX * -1 / 6);
var amountMovedY = (e.pageY * -1 / 6);
$(this).css('background-position', amountMovedX + 'px ' + amountMovedY + 'px');
});
http://jsfiddle.net/X7UwG/580/
I want to make the background movements less aggressive, at first i though well, lets just increase the divider factor in the equation in order to make larger mouse positions lower:
http://jsfiddle.net/X7UwG/581/
The main problem with this approach is that the background is indeed moving slower BUT also very choppy (move the mouse slowly). Since we are now dividing by 100 instead of 6, the non decimal part of the result change after several pixels of movement (open console and see the result). Since background position only takes non decimal values as correct, the movement is not fluid.
I guess I have two ways of solving this, smoothing the transitions between the movements or have a different equation that transforms mouse position into background diferential position, but i cant figure out how to fix it.
The second part of the problem is to prevent the background movement to surpass the background size:
Would something like this work for you?
I simply reduced the divisor by half and increased the size of the background image to account for the movement and applied margin:0 on the body to hide the whitespace that was present in the fiddle
http://jsfiddle.net/X7UwG/582/
$('#landing-content').mousemove(function(e){
var amountMovedX = (e.pageX * -1 / 50);
var amountMovedY = (e.pageY * -1 / 50);
$(this).css('background-position', amountMovedX + 'px ' + amountMovedY + 'px');
console.log(amountMovedX);
});
body {
margin:0px;
}
#landing-content {
overflow: hidden;
background-image: url(http://i.imgur.com/F2FPRMd.jpg);
width: 100%;
background-size: 115%;
background-repeat: no-repeat;
max-height: 500px;
border-bottom: solid;
border-bottom-color: #628027;
border-bottom-width: 5px;
padding:0px;
}

How get real positions of element in javascript

I want to get real X and Y position of my styled elements in javascript ( or jquery short code).
var offset = obj.offset();
ox=offset['left'];
oy=offset['top'];
px=parseInt(obj.css('padding-left')); // padding left
py=parseInt(obj.css('padding-top')); // padding top
bx=parseInt(obj.css('border-width') ); // stroke value
ox=ox+px+bx;
oy=oy+py+bx;
But this codes sometimes not work..
when scrool top or scroll left change im not get real position :(
please help me..
You don't have to use offsets. Use the modern getBoundingClientRect function:
function getPosition( element ) {
var rect = element.getBoundingClientRect();
return {
x: rect.left,
y: rect.top
};
}
You could then use the above function like this:
var element = document.getElementById( 'myElement' );
var pos = getPosition( el );
// Alert position in X axis
alert( pos.x );
// Alert position in Y axis
alert( pos.y );
Works in all browsers 🙂
EDIT: If you want the position of the element with respect to page scroll, just add document.body.scrollTop to Y position and document.body.scrollLeft to X position.
You'll want the offset from the element relative to the document. You have to keep in mind that styles like padding, margin and border can greatly affect the result of the offset. You might want to calculate those on or off the offset.
Finally you need to check if you are using box-sizing, which pushing padding and borders to the inside (with the most common version box-sizing: border-box;);
document.getElementById('cloud').offsetLeft; //offsetTop
Just debug with the other styles (adding/subtracting) until you get the real offset. I mostly test if the offset is correct by making a screenshot (or using the OS X selective-screenshot function) to see if the offset is correctly calculated (counting pixels) with the other styles.
Here's a little example:
CSS
#cloud {
height: 500px;
width: 500px;
margin: 20px auto;
border: 1px dotted #CCC;
}
HTML
<body>
<div id="cloud">
<div id="centerBox"></div>
</div>
</body>
JavaScript
'use strict';
console.log(document.getElementById('cloud').offsetLeft);
console.log(document.getElementById('cloud').offsetTop);
Ouput
main.js: 1 >>> 372
main.js: 2 >>> 20
Funny thing here, you can easily test if the offsetLeft works because of the margin: 20px auto;. If you resize the window it will also have a different offsetLeft.
This function gives you the exact position of an element without padding or margin or border:
function getElementRec(element) {
let rec = { x: 0, y: 0, width: 0, height: 0 };
let computedStyle = getComputedStyle(element);
rec.width = element.clientWidth;
rec.width -= parseFloat(computedStyle.paddingLeft);
rec.width -= parseFloat(computedStyle.paddingRight);
rec.height = element.clientHeight;
rec.height -= parseFloat(computedStyle.paddingTop);
rec.height -= parseFloat(computedStyle.paddingBottom);
let boundingRect = element.getBoundingClientRect();
rec.x = boundingRect.left;
rec.x += parseFloat(computedStyle.paddingLeft);
rec.x += parseFloat(computedStyle.borderLeft);
rec.y = boundingRect.top;
rec.y += parseFloat(computedStyle.paddingTop);
rec.y += parseFloat(computedStyle.borderTop);
return rec;
}
var offset = obj.offset();
ox=offset['left']; = document.getElementById('Mypicture').offsetLeft;
oy=offset['top']; = document.getElementById('Mypicture').offsetTop;
px=parseInt(obj.css('padding-left')); // padding left
py=parseInt(obj.css('padding-top')); // padding top
bx=parseInt(obj.css('border-width') ); // stroke value
ox=ox+px+bx;
oy=oy+py+bx;
//Two codes get equal value; But Not Real clientX ClientY positions..
// My html:
<div id="container">
<img id="Mypicture" src="myimage.jpg" alt="The source image for paint"/>
</div>
//My css :
#Mypicture{
margin:100px;
padding:20px;
border: 20px solid #cacaca;
}
#container {
display:block;
background:#ffaaff;
width: 550px;
padding:50px;
margin-left:300px;
}
// I want to get realx and realY value of Mypicture,on Document.
// All codes work Realx ( ox ) return true value But RealY (oy) nearly 10px false;

Categories