How to position these numbers around a clock? - javascript

Evidentially my trig is a bit rusty. How can I get the minutes to wrap around the clock?
codepen [update: forgot codepen isn't versioned like jsfiddle; this 'pen' is a work in progress and no longer represents the problem I had at the time of this question]
Javascript:
var r = $('.face').width()/2;
var j = r-18;
for(var min=0; min<60; min += 5) {
var str = min < 10 ? '0'+min : String(min);
var x = j*Math.sin(Math.PI*2*(min/60));
var y = j*Math.cos(Math.PI*2*(min/60));
console.log(x);
$('<div>',{'class':'time'})
.text(str)
.css({
marginLeft: (x+r-12)+'px',
marginTop: (-y+r-12)+'px'
})
.appendTo('.face');
}

All your .time divs are below one another. Give the .time class absolute positioning.

Assuming min is between 0-60, and bearing in mind that there are 360 degrees in a circle:
var degToMin = 360/60; // 6
var minDeg = min * degToMin; // this will tell us how many degrees around the circle the minutes are
var minRad = minDeg * (Math.PI/180); // convert to radians
var x = j*Math.cos(minRad); // cos is the x coord, while sin is the y coord
var y = j*Math.sin(minRad);

Going from 0 to 360 degrees (0 to 2 pi radians) normally starts at 3 o'clock, and goes counterclockwise.
So we need to reverse the direction so that it goes clockwise, and rotate it counterclockwise 90 degrees (pi/2 radians) so that it starts at 12 o'clock.
Each hour runs through pi/6 radians, so the position at hour h would be:
x = x_c + r cos (-h*pi/6 + pi/2)
y = y_c + r sin (-h*pi/6 + pi/2)
where the center of your clock is (x_c, y_c) and the radius of your clock is r.

Related

Calculate new circle offset based on angle of rotation?

I have a multiplayer Javascript game where the player is a circle, and is able shoot/"eject" circle bullets in the direction that the player is rotated. My code is working perfectly, except it shoots from the middle of the player. I would like it so that the circles are shot from the top right position of the player, where the gun is located. The issue is that when the players rotation changes, you cannot simply add (1, -1) to the position of the player.
Here is my code:
GameServer.prototype.ejectMass = function(client) {
for (var i = 0; i < client.cells.length; i++) {
var cell = client.cells[i]; // the player
var angle = this.toRad(client.rotation); // rotation of the player
var d = new Vec2(Math.sin(angle), Math.cos(-angle)).scale(-180);
var sq = (~~d.sqDist(d));
d.x = sq > 1 ? d.x / sq : 1;
d.y = sq > 1 ? d.y / sq : 0;
// cell.position is the players position
var pos = new Vec2(
cell.position.x + d.x * cell._size,
cell.position.y + d.y * cell._size
);
var ejected = 0;
// Create cell and add it to node list
ejected = new Entity.EjectedMass(this, null, pos, this.config.ejectSize * cell.ejectSize); // the bullet being shot
ejected.setBoostDefault(-this.config.ejectVelocity * cell.ejectSpeed, angle);
ejected.ejectedOwner = cell; // set the person who shot the bullet
this.addNode(ejected); // add the bullet into the game
if (typeof ejected !== 'undefined') {
setTimeout(this.removeNode.bind(this, ejected), 1000); // remove the ejected bullet after 1 second
}
}
};
And here is an illustration of the current way it is working:
Assuming that the player (circle) is at its own local origin then the position of the gun is relative to the player's origin. Assuming the coordinate system is that of the canvas with forward along the x axis from left to right, and clockwise 90deg (left of player) is the Y axis going down.
Image: C is local circle origin (0,0) with Forward along the red arrow from C, Gx and Gy are the local coordinates of the gun from the circle center C. Top left shows the canvas coordinate (world) system origin. In code below, The player position is relative to that world origin. The final gunPos is also give relative to the world coordinates. B vec is the bullets bullet.delta vector
const bulletSpeed = 10;
var gunPos = {x : 10, Y : 10} // ten units forward ten units left of circle center
var player = {rotation : ?, x : ?, y : ?} // unknown player position and rotation
// get the unit vector of the rotated x axis. Along player forward
var xAx = Math.cos(player.rotation);
var xAy = Math.sin(player.rotation);
// transform the gunpos to absolute position (world coordinates) of rotated player
var rotatedGunPos = {};
rotatedGunPos.x = gunPos.x * xAx - gunPos.y * xAy + player.x;
rotatedGunPos.y = gunPos.x * xAy + gunPos.y * xAx + player.y;
// and fire the bullet from
var bullet = {}
bullet.x = rotatedGunPos.x;
bullet.y = rotatedGunPos.y;
// bullet vector is
bullet.deltaX = xAx * BULLET_SPEED;
bullet.deltaY = xAy * BULLET_SPEED;
You didn't provide enough details about your layout such as what are orientations of X- and Y-axis? Where is 0 angle? Is angle clockwise or counterclockwise? Still the basic idea is the same. Let's assume that X-axis is to the right and Y-axis is down as it looks like from your attached image and adding (1, -1) to get top-right corner. Also assume that angle = 0 for X-axis and angle is clockwise i.e. angle = Pi/2 is aligned with positive direction of Y-axis = down. When the gun is pointed Up i.e. angle = -Pi/2 your starting point is (1, -1) which is at distance sqrt(2) and additionally rotated to Pi/4 corresponding to gun orientation. This is all you need to know.
var angle = this.toRad(client.rotation); // rotation of the player
var gunStartAngle = angle + Math.PI/4;
var sqrt2 = Math.sqrt(2);
// cell.position is the players position
var pos = new Vec2(
cell.position.x + cell._size * sqrt2 * Math.cos(gunStartAngle),
cell.position.y + cell._size * sqrt2 * Math.sin(gunStartAngle)
);
Obviously if your layout is different, you should fix the details of the math but the idea remains the same.

Need to find a (x,y) coordinate based on an angle

So I'm stumped. I didn't know trigonometry before this, and I've been learning but nothing seems to be working.
So a few things to note: In html, cartesian origin(0,0) is the top left corner of the screen. DIVS natural rotation is 0deg or ---->this way.
I need to find the x,y point noted by the ? mark in the problem.
$('#wrapper').on('click', function(e){
mouseX = e.pageX;
mouseY= e.pageY;
var angle = getAngle(mouseX,Rocket.centerX,mouseY,Rocket.centerY);
var angleDistance = Math.sqrt((Math.pow((mouseX - (Rocket.left+Rocket.halfX)),2)) + (Math.pow((mouseY-(Rocket.top+Rocket.halfY)),2)));
var cp2Angle = -90 +(angle*2);
var invCP2Angle = 90+ angle;
var cp2Distance = angleDistance*.5;
//Red Line
$(this).append('<div class="line" style="transform-origin:left center;width:'+(Math.round(angleDistance))+'px;top:'+(Rocket.top+Rocket.halfY)+'px;left:'+(Rocket.left+Rocket.halfX)+'px;transform:rotate('+(Math.round(angle))+'deg);"></div>');
//Blue Line
$(this).append('<div class="line" style="background:#0000FF;transform-origin:left center;width:'+Math.round(cp2Distance)+'px;top:'+(mouseY)+'px;left:'+(mouseX)+'px;transform:rotate('+(Math.round(cp2Angle))+'deg);"></div>');
}
function getAngle(x2,x1,y2,y1){
var angle = Math.degrees(Math.atan2(y2-y1,x2-x1));
return angle;
}
Math.degrees = function(radians) {
return (radians * 180) / Math.PI;
};
So this might be confusing. Basically when I click on the page, i calculate the angle between my custom origin and the mouse points using Math.atan2(); I also calculate the distance using Math.sqrt((Math.pow((x2 - x1),2)) + (Math.pow((y2-y1),2)));
The blue line length is half the length of the red line, but the angle changes, based on the angle of the red line.
When the red line angle = 0deg(a flat line), the blue line angle will be -90(or straight up, at red line -45 deg, the blue line will be -180(or flat), and at Red Line -90, the blue line will be -270 deg(or straight down). The formula is -90 +(angle*2)
I need to know the other end point of the blue line. The lines only exist to debug, but the point is needed because I have an animation where I animate a rocket on a bezier curve, and I need to change the control point based on the angle of the mouse click, if there's abetter way to calculate that without trigonometry, then let me know.
I read that the angle is the same as the slope of the line and to find it by using Math.tan(angle in radians). Sometimes the triangle will be a right triangle for instance if the first angle is 0 deg, sometimes it won't be a triangle at all, but a straight line down, for instance if they click -90.
I've also tried polar coordinates thought I wasn't sure which angle to use:
var polarX = mouseX-(cp2Distance * Math.cos(Math.radians(invCP2Angle)));
var polarY = mouseY- (cp2Distance * Math.sin(Math.radians(invCP2Angle)));
I do not know javascript well, so instead of giving you code, I'll just give you the formulae. On the figure below, I give you the conventions used.
x3 = x2 + cos(brownAngle + greenAngle) * d2
y3 = y2 + sin(brownAngle + greenAngle) * d2
If I understand you correctly, you have already d2 = 0.5 * d1, d1, (x2, y2) as well as the angles. This should then just be a matter of plugging these values into the above formulae.
Let A, B and C be the three points.
AB = ( cos(angle1), sin(angle1) ) * length1
B = A + B
BC = ( cos(angle1+angle2), sin(angle1+angle2) ) * length2
C = B + BC
In your case,
A = ( 0, 0 )
angle1 = 31°
length1 = 655
angle2 = 152°
length2 = 328
Then,
C = ( Math.cos(31*Math.PI/180), Math.sin(31*Math.PI/180) ) * 655 +
( Math.cos(152*Math.PI/180), Math.sin(152*Math.PI/180) ) * 328
= ( Math.cos(31*Math.PI/180) * 655 + Math.cos(183*Math.PI/180) * 328,
Math.sin(31*Math.PI/180) * 655 + Math.sin(183*Math.PI/180) * 328 )
= ( 233.8940945603834, 320.1837454184)

For the point inside circle, find in which quarter it is?

I researched google but couldn't find the keywords for search. So I ask here if my algorithm and code is efficient?
http://sketchtoy.com/66429941 (algorithm)
The algoritm is: I have four points which are: north, east, south and west of circle. I check 4 distances (distanceToNorth, distanceToEast, distanceToSouth, distanceToWest). And I find minimum of them so that is the quarter.
Here is the code but it does not seem efficient for me.
(firstQuarter is North, secondQuarter is East and so on..
note: assume that mousemove is inside the circle.
var firstQuarterX = centerX;
var firstQuarterY = centerY - radius;
var secondQuarterX = centerX + radius;
var secondQuarterY = centerY;
var thirdQuarterX = centerX;
var thirdQuarterY = centerY + radius;
var fourthQuarterX = centerX - radius;
var fourthQuarterY = centerY;
var distanceToFirst = Math.sqrt(Math.pow(x-firstQuarterX, 2) + Math.pow(y-firstQuarterY, 2));
var distanceToSecond = Math.sqrt(Math.pow(x-secondQuarterX, 2) + Math.pow(y-secondQuarterY, 2));
var distanceToThird = Math.sqrt(Math.pow(x-thirdQuarterX, 2) + Math.pow(y-thirdQuarterY, 2));
var distanceToFourth = Math.sqrt(Math.pow(x-fourthQuarterX, 2) + Math.pow(y-fourthQuarterY, 2));
var min = Math.min(distanceToFirst, distanceToSecond, distanceToThird, distanceToFourth);
var numbers = [distanceToFirst, distanceToSecond, distanceToThird, distanceToFourth];
var index = numbers.indexOf(min); // it will give 0 or 1 or 2 or 3
var quarter = index + 1;
Observe that the boundaries between your quarters lie along the lines with equations y = x and y = -x, relative to an origin at the center of the circle. You can use those to evaluate which quarter each point falls in.
If your point is (x, y), then its coordinates relative to the center of the circle are xRelative = x - centerX and yRelative = y - centerY. Then
your point is in the first (south in your code) quarter if yRelative < 0 and Math.abs(xRelative) < -yRelative
your point is in the second (east) quarter if xRelative > 0 and Math.abs(yRelative) < xRelative
your point is in the third (north) quarter if yRelative > 0 and Math.abs(xRelative) < yRelative
your point is in the fourth (west) quarter if xRelative < 0 and Math.abs(yRelative) < -xRelative
I leave it to you to determine to which quarter to assign points that fall exactly on a boundary. Also, you can implement a little decision tree based on those criteria if you prefer; that should be a little more efficient then testing each criterion in turn.
Not so sure but I think this might work. Math.atan2(CenterY - y, CenterX - x) * 180 / Math.PI gives the apparent angle between the points. Do the remaining math to figure out the quarter.
What about something like:
return x>centerX?(y>centerY?"Quad 2":"Quad 1"):(y>centerY?"Quad 3":"Quad 4");
Less graceful, more slim.
For more efficient algorithm, you can compute the quadrant just by analyzing the signs of dx + dy and dx - dy quantities (dx, dy being x, y minus centerX, centerY respectively) (I presume that as your animation shows, your quadrants are rotated by 45 degrees against 'standard' quadrants.

Rotating a clock hand in javascript

I am learning to make a clock using raphael js,
I am using this tutorial to get me started http://www.tuttoaster.com/creating-a-clock-animation-without-css3/
When this is diplayed the second hand doesnt move one second per second. I know one second is 6 degrees, it moves around 45 degrees though!
If someone could please explain what he has done wrong and how to make the hands rotate at appropriate angles that would be great. I am a beginner so plain english please :)
The code is as follows.
window.onload = function(){
var canvas = Raphael("pane",0,0,500,500);
canvas.circle(200,150,100).attr("stroke-width",2);
canvas.circle(200,150,3).attr("fill","#000");
var angleplus = 360,rad = Math.PI / 180,
cx = 200,cy =150 ,r = 90,
startangle = -90,angle=30,x,y, endangle;
for(i=1;i<13;i++)
{
endangle = startangle + angle ;
x = cx + r * Math.cos(endangle * rad);
y = cy + r * Math.sin(endangle * rad);
canvas.text(x,y,i+"");
startangle = endangle;
}
var hand = canvas.path("M200 70L200 150").attr("stroke-width",1);
var minute_hand = canvas.path("M200 100L200 150").attr("stroke-width",2);
var hour_hand = canvas.path("M200 110L200 150").attr("stroke-width",3);
var time = new Date();
angle = time.getSeconds() * 6;
minute_hand.rotate(6 * time.getMinutes(),200,150);
var hr = time.getHours();
if(hr>12)
hr = hr -11;
hour_hand.rotate(30 * hr,200,150);
var minute_angle= 6 + time.getMinutes()*6,hour_angle=0.5+
time.getMinutes()*30;
setInterval(function(){
angle = angle + 6;
if(angle>=360)
{
angle=0;
minute_hand.rotate(minute_angle,200,150);
minute_angle = minute_angle + 6;
hour_hand.rotate(hour_angle,200,150);
hour_angle = hour_angle + 0.5;
}
if(minute_angle>=360)
{
minute_angle=0;
}
hand.rotate(angle,200,150);
},1000);
hand.rotate(6,200,150);
Bernard, you don't need to rotate by the variable angle since you're simply rotating by 6 degrees every second regardless of how many seconds have elapsed.
http://jsbin.com/domoqojipe/1/
So you want to speed up the clock speed by twenty?
It's a long shot, but try changing the 1000 at the bottom to 50. Because 1000 divided by 20 equals 50.
Try that and see if it works...

Get points over the tangent circle(or oval) and balance poker chips on

I try to display some chips for a free poker game (HTML/Javascript client, python server) game.
There are seats around the center of the table.
for each seats, i know cosinus, sinus, radius (distance from the center of the table), and the values/counts chips array.
I try to display each chips aligned and balanced on the tangent at the seat point
In image: (i can't create image so : http://i.stack.imgur.com/a4Obw.png )
for now, i wrote this code :
function balanced_stack( chips, cos, sin, radius )
{
var html = ''
// I receive a chips array like [ [ 100, 8 ], [ 200, 10 ], [ 500, 7 ] ]
// so 8 chips of 100$, 10 chips of 200$ .. etc
for(var i in chips)
{
var value = chips[i][0]; // the token value
var count = chips[i][1]; // the token count
var m = 0; // margin for a single stack
var left = i * 20 * sin + cos * radius;
var top = -i * 20 * cos + sin * radius;
for( var j=1; j<= count; j++ )
{
html += '<img style="z-index:'+( parseInt(top) + 9999)+'; left:'+left+'px; top: '+top+'px; margin-top:'+( -2*m )+'px;" \
src="/images/chips/'+value+'.png" />'
m ++;
}
return html
}
}
but it's not right balanced and not good looking.
add : the cosinus and sinus can be greater than 1 and less than -1 because table may be oval
If you ellipse is defined by {a*cos(x),b*sin(x)}, the tangent is {-a*sin(x),b*cos(x)}. Using a definition that combines the ellipse's axes with the sine/cosine of the angle around the table does not allow you extract that easily. Besides, it seems a bad idea to call that quantity sin/cos since they are restricted to the domain -1 to +1 by their mathematical definition...
I think i solved the problem of the tangent with the equation of SEngstrom.
All chips are aligned on the right tangent. You can see here :
function( chips, cos, sin, radius )
{
var html = ''
// Considering the equation for the tangent {a*cos(x),b*cos(x)}+d*{-a*sin(x),b*cos(x)}
var a = 1.6; // x coefficient for the ellipse
var b = 1; // y coefficient for the ellipse
// I receive a chips array like [ [ 100, 8 ], [ 200, 10 ], [ 500, 7 ] ], so 8 chips of 100$, 10 chips of 200$ .. etc
for(var i in chips)
{
var value = chips[i][0]; // the token value
var count = chips[i][1]; // the token count
var m = 0; // margin for a single stack
var left = i * 20 * sin * a + cos * radius * a;
var top = -i * 20 * cos * b + sin * radius * b;
for( var j=1; j<= count; j++ )
{
html += '<img style="z-index:'+( parseInt(top) + 9999)+'; left:'+left+'px; top: '+top+'px; margin-top:'+( -2*m )+'px;" \
class="chip chip_'+value+'" src="/images/chips/'+CHIPS.COLORS[ value ]+'.png" />'
m ++;
}
}
return html
}
But as you can see, there is a blank space between each single stack, because a chip have width of 20px, with a regular cos/sin it's ok but here, the distance between each single stack is amplified by the ellipse coefficient (i * 20 * sin * a)
Think about it this way: the second term for (left,top) in your code finds the center of the stack. To that you want to add stacks along the tangent. Since your stacks are defined by a pixel width, the form of the term to add to the center point can have the convenient form of i*pxwidth*{nx,ny}, where nx and ny are the (x,y) components of the normalized tangent vector, 'i' is an integer counting up the individual stacks, and pxwidth is the desired pixel width. If sin and cos are true sine/cosines, (-sin,cos) is already a normalized vector since sin^2+cos^2=1.
What I don't understand in your code is the ((20*a)-20) which equals 20*(a-1). Some sort of correction factor for a>1. It is not symmetric for b, but then it would be zero for b=1...
I tried solutions a bit blindly, and I wrote: (that seems to work)
var left = (i * ((20*a) - 20) * sin * a) + (cos * radius * a);
var top = -(i * ((20*a) - 20) * cos * b) + (sin * radius * b);
Can you explain me why that works? I'm mathematically weak.
with 20 fake players around the ellipse table (a=1.6, b=1):

Categories