Reputation: 39
I am aware of plenty of articles on this topic on the Internet, but I have not managed to solve my problem. I think me trigonometry calculations are correct, but perhaps I am messing something up within JavaScript.
My goals is to calculate the point on circle (x,y) so that I can move my sliderHead
to that position. For this I need to calculate the angle between the pressed / clicked points on my circle - I use atan2
for that. Next I use simple trigonometry to calculate the actually X and Y:
let y = -Math.ceil(radius * Math.cos(deg));
let x = Math.ceil(radius * Math.sin(deg));
I understand that I need to invert the cosine
and sine
, because my starting position is actually at 90 degrees and not 0 and I turn CLOCKWISE and not COUNTERCLOCKWISE, which maths suggests.
The starting values are 0, becuse the initial value of the sliderHead
is at center of the Circle. The starting value is not actual 0, 0px, but center of the parent div.
As you will see on below picture, I am not doing it correct, the sliderHead is behind the bar.
Here is the code where I calculate the point x,y:
testCalc(event) {
let deg = Math.atan2(event.pageY - this.centerY, event.pageX - this.centerX);
console.log(deg);
let radius = this.options.radius;
let y = -Math.ceil(radius * Math.cos(deg));
let x = Math.ceil(radius * Math.sin(deg));
return {
"x": x + "px",
"y": y + "px"
};
}
And here is the positioning of the sliderHead element within my HTML:
Here is how I translate the sliderHead
:
moveSliderHeadPosition(point) {
this.sliderHead.style.transform = "translate(" + point["x"] + "," + point["y"] + ")";
}
As said, I exhausted all of my options with trying to solve this.
Upvotes: 1
Views: 763
Reputation: 168
Nice on the use of atan2! Looking at your code it looks right to me, though maybe it's as simple as needing to subtract half the size of the sliderHead?
Here's an example that I put together to test it:
function showCoords(event) {
var x = event.clientX;
var y = event.clientY;
var xn = x / window.innerWidth;
var yn = y / window.innerHeight;
var result = Math.atan2(x, y);
var coor = `X: ${x}, Y: ${y} > X1: ${xn.toFixed(2)}, Y1: ${yn.toFixed(
2
)} ~ ${result.toFixed(
2)}`;
document.getElementById("demo").innerHTML = coor;
}
function moveGrabber(event) {
// get our grabber and track as well as their bounding rectangles
var grabber = document.querySelector(".grabber");
var grabberRect = grabber.getBoundingClientRect();
var track = document.querySelector(".track");
var trackRect = track.getBoundingClientRect();
var trackRadius = trackRect.width / 2;
// get our window center
var windowCenterX = window.innerWidth / 2;
var windowCenterY = window.innerHeight / 2;
// get the angle around the window center
var x = event.clientX;
var y = event.clientY;
var angle = Math.atan2(x - windowCenterX, y - windowCenterY);
// get the point on the circle
var circleX = Math.sin(angle) * trackRadius + windowCenterX;
var circleY = Math.cos(angle) * trackRadius + windowCenterY;
// subtract half the size of the grabber so that it is centered on the track
var posX = circleX - grabberRect.width / 2;
var posY = circleY - grabberRect.height / 2;
grabber.style.left = `${posX}px`;
grabber.style.top = `${posY}px`;
}
function moveGrabberWithX(event) {
// get our grabber and track as well as their bounding rectangles
var grabber = document.querySelector(".grabber");
var grabberRect = grabber.getBoundingClientRect();
var track = document.querySelector(".track");
var trackRect = track.getBoundingClientRect();
var trackRadius = trackRect.width / 2;
// get the mouse position and the normalized version in the range of [0,1]
var x = event.clientX;
var xn = x / window.innerWidth;
// get the center of the window
var windowCenterX = window.innerWidth / 2;
var windowCenterY = window.innerHeight / 2;
// get the point on the circle
// this uses the normalized x position of the mouse [0,1]
// and multiplies it by 2PI which gives you a circle
var circleX = Math.sin(xn * Math.PI * 2) * trackRadius + windowCenterX;
var circleY = Math.cos(xn * Math.PI * 2) * trackRadius + windowCenterY;
// subtract half the size of the grabber so that it is centered on the track
var posX = circleX - grabberRect.width / 2;
var posY = circleY - grabberRect.height / 2;
grabber.style.left = `${posX}px`;
grabber.style.top = `${posY}px`;
}
html,
body {
margin: 0px;
padding: 0px;
}
.center {
position: absolute;
top: 0px;
left: 0px;
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
background: gray;
}
.track {
width: 300px;
height: 300px;
background: rgb(13, 88, 134);
border-radius: 50%;
}
.grabber {
position: absolute;
top: 0px;
left: 0px;
width: 25px;
height: 25px;
background: coral;
border-radius: 50%;
}
.label {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
/* display: flex; */
}
p {
background: darkgray;
font-family: "Courier New", Courier, monospace;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
<link rel="stylesheet" href="styles.css" />
<script src="script.js"></script>
</head>
<body>
<div class="center" onmousemove="moveGrabber(event); showCoords(event);">
<div class="track" />
<div class="grabber" />
</div>
<div class="label">
<p id="demo" />
</div>
</body>
</html>
Upvotes: 2
Reputation: 3067
Try multiplying or dividing the calculated angle by 57.2957795
(a conversion between degrees and radians).
Upvotes: 0