Arrange DIV in circle and rotate them facing outwards - javascript

Basically I've managed to layout my DIV elements into a circle shape but I've not managed to work out how to calculate the deg of rotation need to have them face OUTWARD from the center of the circle.
$(document).ready(function(){
var elems = document.getElementsByClassName('test_box');
var increase = Math.PI * 2 / elems.length;
var x = 0, y = 0, angle = 0;
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
// modify to change the radius and position of a circle
x = 400 * Math.cos(angle) + 700;
y = 400 * Math.sin(angle) + 700;
elem.style.position = 'absolute';
elem.style.left = x + 'px';
elem.style.top = y + 'px';
//need to work this part out
var rot = 45;
elem.style['-moz-transform'] = "rotate("+rot+"deg)";
elem.style.MozTransform = "rotate("+rot+"deg)";
elem.style['-webkit-transform'] = "rotate("+rot+"deg)";
elem.style['-o-transform'] = "rotate("+rot+"deg)";
elem.style['-ms-transform'] = "rotate("+rot+"deg)";
angle += increase;
console.log(angle);
}
});
does anyone have to knowledge on how I can do this.
Cheers -C

Note that rot depends on angle, except angle is in radians.
DRY, so either convert from angle to rot:
// The -90 (degrees) makes the text face outwards.
var rot = angle * 180 / Math.PI - 90;
Or just use angle when setting the style (but use radians as a unit), and drop rot's declaration:
// The -0.5*Math.PI (radians) makes the text face outwards.
elem.style.MozTransform = "rotate("+(angle-0.5*Math.PI)+"rad)";

Try this:
var rot = 90 + (i * (360 / elems.length));
Demo at http://jsfiddle.net/gWZdd/
I've added the 90 degrees at the start there to ensure the baseline of the divs face towards the centre, however you can adjust this to suit your needs.

Related

Distribute points evenly on circle circumference in quadrants I and IV only

I want to distribute n points evenly on a circle circumference in quadrants I and IV only.
As parameters, I have the numbers of point n, the center of circle coordiantes cx and cy and the radius r.
I can distribute the points over the whole circumference like using this formula below, but I am looking for the formula to spread them only in quadrants I and IV
var n = 5;
var cx = 1;
var cy = 1;
var r = 2;
//I store each point's coordinates in this array below
var coordinates = [];
for (var i=0; i < n; i++) {
//defining point's angle with the center of the circle in radiant
//this angle distribute the points evenly over all 4 quadrants
var angle = ((360/n) * i) * (Math.PI/180);
//calculating the point's coordinates on the circle circumference
var pointX = cx + r * Math.cos(angle);
var pointY = cx + r * Math.sin(angle);
//storing the point's coordinates
coordinates.push([pointX, pointY]);
}
Here would be the steps I'd take to solve this:
find the angle betw. each point var incrementBy = 180 / n
start angle will be 270º and end angle will be 90º
iterate through via
code
var increment = 180 / n
var startAngle = 270
for (var i = 0; i < n; i++)
{
var angle = startAngle + increment * i
var rads = angle * Math.pi / 180
var tx = cx + r * Math.cos(rads)
var ty = cy + r * Math.sin(rads)
coords.push([tx, ty])
}
note
I didn't bother to convert for traditional quadrants (vs JS's y-axis moving downwards). If that is needed then, after your calculations, just invert the ty value. I also didn't bother to reduce the angle value when it exceeds 360º when you're incrementing back into Quad I.
like this?
var n = 5;
var r = 2;
var cx = 1;
var cy = 1;
var coordinates = [];
for(var i=0; i<n; ++i){
var a = (i+.5) / n * Math.PI;
coordinates.push([
cx + Math.sin(a) * r,
cy - Math.cos(a) * r
]);
}
Here is the way to equally distribute objects
var boxes = []
let count = 10;
for (let i = 0; i < count; i++) {
let size = 0.8;
let radius = 3;
let box = new THREE.Mesh(new THREE.BoxGeometry( size, size, size ),new THREE.MeshPhysicalMaterial(0x333333))
let gap = 0.5;
let angle = i * ((Math.PI * 2) / count);
let x = radius * Math.cos(angle);
let y = 0;
let z = radius * Math.sin(angle);
box.position.set(x,y,z);
boxes.push(box);`enter code here`
scene.add(box)
}
here is how it looks for 10 blocks
here is how it looks for 5 blocks
var n = 5;
var cx = 1;
var cy = 1;
var r = 2;
//I store each point's coordinates in this array below
var coordinates = [];
for (var i=0; i < n; i++) {
//defining the angle of the point with the center of the circle in radiant
var angle = ((360/n) * i) * (Math.PI/180);
//calculating the coordinates of the point on the circle circumference
var pointX = cx + r * Math.cos(angle);
var pointY = cx + r * Math.sin(angle);
// Here, we are going to use a boolean expression to determine if
// [pointX, pointY] is within quadrant 1 or 4.
// We can start with this boolean equation:
// (pointX >= cx && pointY >= cy) || (pointX >= cx && pointY <= cy)
// But this problem can be simplified to only pointX >= cx
if(pointX >= cx){
//storing the point's coordinates
coordinates.push([pointX, pointY]);
}
}

Animating canvas shape to center from any position

So I am a bit confused on how I can make a shape animate to the center of a canvas. I can get the center value:
width = canvas.width = window.innerWidth,
height = canvas.height = window.innerHeight,
centerX = width / 2,
centerY = height / 2;
and a simple decrement or increment depending on whether the initial position is positive or negative can be done as well:
var x = 100;
var y = 100;
function fn (){
ctx.beginPath();
ctx.arc(x, y, 50, 0, 2 * Math.PI, false);
ctx.fillStyle = '#444';
ctx.fill();
ctx.closePath();
x -= 1;
y -= 1;
}
The animation would be done using:
requestAnimationFrame(fn)
Problem with all this is. I need to manually adjust the x and y everytime. How can I better simply make the x and y values random for the shape and make it animate to the center, no matter from what direction and if the initial position is negative or positive. I was thinking of atang2 but honestly im not entirely sure.
You're basically on the right track. Use Math.sqrt for the distance and Math.atan2 to find the direction. Then its just the matter of how fast (velocity) you want the object to move to the target (centre of the canvas).
var tx = centerX - x,
tx = centerY - y,
distance = Math.sqrt(tx * tx + ty * ty),
radius = Math.atan2(ty, tx),
angle = (radius / Math.PI) * 180;
// Ensure we don't divide by zero if distance is 0
if (distance !== 0)
{
velX = (tx / distance) * velocity;
velY = (ty / distance) * velocity;
x += velX;
y += velY;
}
The answer given is flawed as there is no check for divide by zero. This error can easily be overlooked and then crop up in production code making it very hard to find out what has gone wrong.
Should be
var tx = centre.x - x;
var ty = centre.y - y;
var dist = Math.sqrt(tx * tx + ty * ty);
// or
var dist = Math.sqrt(Math.pow(tx, 2) + Math.pow(ty, 2));
if(dist !== 0){ // must have this test or when the coords get to the centre
// you will get a divide by zero
tx /= dist; // Normalise direction vector
ty /= dist;
}
tx *= speed; // set the magnitude to required speed;
ty *= speed; // Note that if at the centre this will be zero
x += tx;
y += ty;

Spiral Animation JavaScript

I am studying JavaScript and I discovered the following article: http://www.html5code.nl/tutorial-canvas-animation-spiral-movement/
Could you tell me how does the function spiralMotion1() works?
I would like to customize speed and distance.
edit: breaking it down to specifics: why use cos. and sin.? why use rotationRadius? how does the setAngle function influence the result? where does the degrees variable come into play?
the code:
function spiralMotion1(){
var degrees = 0;
var Angle;
var rotationRadius=2;
var rotationRadiusIncrease = 1;
var ballRadius=20
var centerX;
var centerY;
var x;
var y;
var animate=true;
var breadcrumbs = new Array();
var crumbRadius=1;
var canvas = jQuery("#spiral_motion1");
var context = canvas.get(0).getContext("2d");
//function Ball(x,y,radius,color,strokeColor,lineWidth) in ball.js
var ball_3 = new Ball(-10,-10,20,'#f00','#000',7);
var parentWidth=jQuery(canvas).parent().width();
var canvasWidth=context.canvas.width = parentWidth;
var canvasHeight=context.canvas.height= 288;
if (!checkForCanvasSupport) {
return;
}
(function drawFrame() {
window.requestAnimationFrame(drawFrame, canvas);
if(animate){
context.clearRect(0,0,canvasWidth,canvasHeight); // clear canvas
//Make the Canvas element responsive for desktop, tablet and smartphone.
centerX = canvasWidth/2;
centerY = canvasHeight/2
Angle = degrees * (Math.PI / 180);
degrees = degrees + 1;
ball_3.x=rotationRadius * Math.cos(setAngle()) + centerX;
ball_3.y=rotationRadius * Math.sin(setAngle()) + centerY;
ball_3.draw(context);
//add a breadcrumb to the breadcrumbs array
breadcrumbs.push({x:ball_3.x,y:ball_3.y});
//draw the breadcrumbs that shows the track of the movement
context.globalCompositeOperation = "destination-over";
showBreadcrumbs(breadcrumbs);
rotationRadius += rotationRadiusIncrease/5
if ((ball_3.y + ballRadius+4) > canvas.height()){
animate=false;
}
}
}());//end drawFrame
function setAngle(){
Angle = degrees * (Math.PI / 180);
degrees = degrees + 2;
return Angle;
}//end setAngl()
function showBreadcrumbs(breadcrumbs){
for (var i = 0; i< breadcrumbs.length; i++) {
context.beginPath();
context.arc(breadcrumbs[i].x,breadcrumbs[i].y,crumbRadius,0, 2*Math.PI,false);
context.closePath();
context.fillStyle="#999";
context.fill();
}
}//end showBreadcrumbs()
}//end spiralMotion1()
It boils down to basic geometry. If you think of a body orbiting a point in 2D, it's movement can be characterised by a radius (distance from the orbited point), and an angle which is a function of time. If you know the radius and the angle, then you can calculate the body position with the cos and sin function.
]1
By changing the radius over time, you obtain a spiral instead of a simple circle.

Position different size circles around a circular path with no gaps

I'm creating a Canvas animation, and have managed to position x number of circles in a circular path. Here's a simplified version of the code I'm using:
var total = circles.length,
i = 0,
radius = 500,
angle = 0,
step = (2*Math.PI) / total;
for( i; i < total; i++ ) {
var circle = circles[i].children[0],
cRadius = circle[i].r,
x = Math.round(winWidth/2 + radius * Math.cos( angle ) - cRadius),
y = Math.round(winHeight/2 + radius * Math.sin( angle ) - cRadius);
circle.x = x;
circle.y = y;
angle += step;
}
Which results in this:
What I am trying to achieve is for all the circles to be next to each other with no gap between them (except the first and last). The circles sizes (radius) are generated randomly and shouldn't adjust to fit the circular path:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
I expect there to be a gap between the first and last circle.
I'm struggling to get my head around this so any help would be much appreciated :)
Cheers!
Main creation loop :
• take a current radius
• compute the angles it cover ( = atan2(smallRadius/bigRadius) )
• move base angle by this latest angle.
http://jsfiddle.net/dj2v7mbw/9/
function CircledCircle(x, y, radius, margin, subCircleCount, subRadiusMin, subRadiusMax) {
this.x = x;
this.y = y;
this.radius = radius;
this.subCircleCount = subCircleCount;
var circles = this.circles = [];
// build top sub-circles
var halfCount = Math.floor(subCircleCount / 2);
var totalAngle = addCircles(halfCount);
// re-center top circles
var correction = totalAngle / 2 + Math.PI / 2;
for (var i = 0; i < halfCount; i++) this.circles[i].angle -= correction;
// build bottom sub-circles
totalAngle = addCircles(subCircleCount - halfCount);
// re-center bottom circles
var correction = totalAngle / 2 - Math.PI / 2;
for (var i = halfCount; i < subCircleCount; i++) this.circles[i].angle -= correction;
// -- draw this C
this.draw = function (angleShift) {
for (var i = 0; i < this.circles.length; i++) drawDistantCircle(this.circles[i], angleShift);
}
//
function drawDistantCircle(c, angleShift) {
angleShift = angleShift || 0;
var thisX = x + radius * Math.cos(c.angle + angleShift);
var thisY = y + radius * Math.sin(c.angle + angleShift);
ctx.beginPath();
ctx.arc(thisX, thisY, c.r, 0, 2 * Math.PI);
ctx.fillStyle = 'hsl(' + (c.index * 15) + ',75%, 75%)';
ctx.fill();
ctx.stroke();
}
//
function addCircles(cnt) {
var currAngle = 0;
for (var i = 0; i < cnt; i++) {
var thisRadius = getRandomInt(subRadiusMin, subRadiusMax);
var thisAngle = Math.atan2(2 * thisRadius + margin, radius);
var thisCircle = new subCircle(thisRadius, currAngle + thisAngle / 2, i);
currAngle += thisAngle;
circles.push(thisCircle);
}
return currAngle;
}
}
with
function subCircle(radius, angle, index) {
this.r = radius;
this.angle = angle;
this.index = index;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
use with
var myCircles = new CircledCircle(winWidth / 2, winHeight / 2, 350, 2, 24, 5, 50);
myCircles.draw();
animate with :
var angleShift = 0;
function draw() {
requestAnimationFrame(draw);
ctx.clearRect(0, 0, winWidth, winHeight);
myCircles.draw(angleShift);
angleShift += 0.010;
}
draw();
It's something like this, but you're gonna have to figure out the last circle's size:
http://jsfiddle.net/rudiedirkx/ufvf62yf/2/
The main logic:
var firstStep = 0, rad = 0, step = 0;
firstStep = step = stepSize();
for ( var i=0; i<30; i++ ) {
draw.radCircle(rad, step);
rad += step;
step = stepSize();
rad += step;
}
stepSize() creates a random rad between Math.PI/48 and Math.PI/48 + Math.PI/36 (no special reason, but it looked good). You can fix that to be the right sizes.
draw.radCircle(rad, step) creates a circle at position rad of size step (also in rad).
step is added twice per iteration: once to step from current circle's center to its edge and once to find the next circle's center
firstStep is important because you have to know where to stop drawing (because the first circle crosses into negative angle)
I haven't figured out how to make the last circle the perfect size yet =)
There's also a bit of magic in draw.radCircle():
var r = rRad * Math.PI/3 * 200 * .95;
The 200 is obviously the big circle's radius
The 95% is because the circle's edge length is slightly longer than the (straight) radius of every circle
I have no idea why Math.PI/3 is that... I figured it had to be Math.PI/2, which is 1 rad, but that didn't work at all. 1/3 for some reason does..... Explain that!
If you want to animate these circle sizes and keep them aligned, you'll have a hard time. They're all random now. In an animation, only the very first iteration can be random, and the rest is a big mess of cache and math =)

Calculating evenly spaced points on the perimeter of a circle

The math behind this question has been asked numerous times, so that's not specifically what I'm after. Rather, I'm trying to program the equation for determining these points into a loop in JavaScript, so that I can display points the evenly around the circle.
So with the equations for the X and Y positions of the points:
pointX = r * cos(theta) + centerX
pointY = r * sin(theta) + centerY
I should be able to calculate it with this:
var centerX = 300;
var centerY = 175;
var radius = 100;
var numberOfPoints = 8;
var theta = 360/numberOfPoints;
for ( var i = 1; i <= numberOfPoints; i++ ) {
pointX = ( radius * Math.cos(theta * i) + centerX );
pointY = ( radius * Math.sin(theta * i) + centerY );
// Draw point ( pointX , pointY )
}
And it should give me the x,y coordinates along the perimeter for 8 points, spread 45° from each other. But this doesn't work, and I'm not understanding why.
This is the output that I get (using the HTML5 Canvas element). The points should reside on the innermost red circle, as that one has a
Incorrect:
When it "should" look like this (although this is with just 1 point, placed manually):
Correct:
Could someone help me out? It's been years since I took trig, but even with looking at other examples (from various languages), I don't see why this isn't working.
Update: Figured it out!
I didn't need to add the centerX and centerY to each calculation, because in my code, those points were already relative to the center of the circle. So, while the canvas center was at point (300, 175), all points were relative to the circle that I created (the stroke line that they need to be placed on), and so the center for them was at (0, 0). I removed this from the code, and split the theta and angle calculations into two variables for better readability, and voila!
totalPoints = 8;
for (var i = 1; i <= totalPoints ; i++) {
drawPoint(100, i, totalPoints);
}
function drawPoint(r, currentPoint, totalPoints) {
var theta = ((Math.PI*2) / totalPoints);
var angle = (theta * currentPoint);
electron.pivot.x = (r * Math.cos(angle));
electron.pivot.y = (r * Math.sin(angle));
return electron;
}
Correct:
cos and sin in Javascript accept an argument in radians, not degrees. You can change your theta calculation to
var theta = (Math.PI*2)/numberOfPoints;
See the Math.cos documentation for details
#Emmett J. Butler's solution should work. The following is a complete working example
// canvas and mousedown related variables
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas.scrollLeft();
var scrollY = $canvas.scrollTop();
// save canvas size to vars b/ they're used often
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var centerX = 150;
var centerY = 175;
var radius = 100;
var numberOfPoints = 8;
var theta = 2.0*Math.PI/numberOfPoints;
ctx.beginPath();
for ( var i = 1; i <= numberOfPoints; i++ ) {
pointX = ( radius * Math.cos(theta * i) + centerX );
pointY = ( radius * Math.sin(theta * i) + centerY );
ctx.fillStyle = "Red";
ctx.fillRect(pointX-5,pointY-5,10,10);
ctx.fillStyle = "Green";
}
ctx.stroke();

Categories