Positioning Divs in a Circle Using JavaScript

Positioning divs in a circle using JavaScript

First of all, the equation for a co-ordinate on a circle is simply:

(x, y) = (r * cos(θ), r * sin(θ))

where, r is the radius of a circle and θ is the angle in radians.


The reason why your code is creating an eccentric ellipse is because when you assign the .top and .left CSS values, you are not considering that it will actually take the top-left corner as its reference. I've fixed your code and now it creates a perfect circle.

Changes made to your code:

  1. Added an array theta that holds all the angles.

    var theta = [0, Math.PI / 6, Math.PI / 4, Math.PI / 3, Math.PI / 2, 2 * (Math.PI / 3), 3 * (Math.PI / 4), 5 * (Math.PI / 6), Math.PI, 7 * (Math.PI / 6), 5 * (Math.PI / 4), 4 * (Math.PI / 3), 3 * (Math.PI / 2), 5 * (Math.PI / 3), 7 * (Math.PI / 4), 11 * (Math.PI / 6)];

    The image below shows all the angles I've used.

    Sample Image

  2. Added an array colors that holds different colors.

    var colors = ['red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'DarkSlateBlue'];
  3. Made changes to your trigonometric equations.

    circleArray[i].posx = Math.round(radius * (Math.cos(theta[i]))) + 'px';
    circleArray[i].posy = Math.round(radius * (Math.sin(theta[i]))) + 'px';
  4. Changed the way .top and .left are assigned.

    circleArray[i].style.top = ((mainHeight / 2) - parseInt(circleArray[i].posy.slice(0, -2))) + 'px';
    circleArray[i].style.left = ((mainHeight / 2) + parseInt(circleArray[i].posx.slice(0, -2))) + 'px';

    where mainHeight is the height of the #main div.


[1] 16 divs

Demo on Fiddle

var setup = function() {  var radius = 150;  var main = document.getElementById('main');  var mainHeight = parseInt(window.getComputedStyle(main).height.slice(0, -2));  var theta = [0, Math.PI / 6, Math.PI / 4, Math.PI / 3, Math.PI / 2, 2 * (Math.PI / 3), 3 * (Math.PI / 4), 5 * (Math.PI / 6), Math.PI, 7 * (Math.PI / 6), 5 * (Math.PI / 4), 4 * (Math.PI / 3), 3 * (Math.PI / 2), 5 * (Math.PI / 3), 7 * (Math.PI / 4), 11 * (Math.PI / 6)];  var circleArray = [];  var colors = ['red', 'green', 'purple', 'black', 'orange', 'yellow', 'maroon', 'grey', 'lightblue', 'tomato', 'pink', 'maroon', 'cyan', 'magenta', 'blue', 'chocolate', 'DarkSlateBlue'];  for (var i = 0; i < 16; i++) {    var circle = document.createElement('div');    circle.className = 'circle number' + i;    circleArray.push(circle);    circleArray[i].posx = Math.round(radius * (Math.cos(theta[i]))) + 'px';    circleArray[i].posy = Math.round(radius * (Math.sin(theta[i]))) + 'px';    circleArray[i].style.position = "absolute";    circleArray[i].style.backgroundColor = colors[i];    circleArray[i].style.top = ((mainHeight / 2) - parseInt(circleArray[i].posy.slice(0, -2))) + 'px';    circleArray[i].style.left = ((mainHeight / 2) + parseInt(circleArray[i].posx.slice(0, -2))) + 'px';    main.appendChild(circleArray[i]);  }};setup();
div#main {  height: 300px;  width: 300px;  position: absolute;  margin: 0 auto;  transform: translate(-50%, -50%);  top: 50%;  left: 50%;}div.circle {  position: absolute;  width: 20px;  height: 20px;  border: 2px solid black;  border-radius: 50%;}body {  margin: 0 auto;  background: papayawhip;}
<div id="main"></div>

Divs around a circular Div

You can set the position of the small circles as position: absolute; and then play with top, left, right or bottom for placing them on the desired place.

I recommend you to use % for setting the position so it will be responsive, but in the case the big circle size is static you can just set the position with px.

.main{ border: 2px dotted #000000; border-radius: 50%; width: 500px; height: 500px;}.cirlce1{  position: absolute; height: 50px; width: 50px; border: 2px dotted #000000; border-radius: 50%; top: 50%;}.cirlce2{  position: absolute; height: 50px; width: 50px; border: 2px dotted #000000; border-radius: 50%;  left: 50%;}
<div class="main"> <div class="cirlce1"></div> <div class="cirlce2"></div></div>

Placing divs around a circle with starting and ending angles

changed your createNodes function

var createNodes = function (numNodes, radius,start,end) {
var nodes = [],
width = (radius * 2) + 50,
height = (radius * 2) + 50,
inc=(end-start)/(numNodes - 1),
angle,
x,
y,
i;

for (i=0; i<numNodes; i++) {
angle = start + i*inc;
x = (radius * Math.cos(angle)) + (width/2); // Calculate the x position of the element.
y = (radius * Math.sin(angle)) + (width/2); // Calculate the y position of the element.
nodes.push({'id': i, 'x': x, 'y': y});
}
return nodes;
}

added the start and end angles to the function parms.

To make the start and end angles more explicit

  var startAngle = -1.25 * Math.PI; // same as 0.75 * Math.PI i.e adding 2*PI (360 deg)
var endAngle = 0.25 * Math.PI; // same as 2.25 * Math.PI
// or if you would like it in degrees
var startAngle=135/180 * Math.PI; // same as -225/180 i.e subtracting 360
var endAngle=405/180 * Math.PI; // same as 45/180

Hope this answers your question

Position multiple div elements around the circle like clock

Ok…

I removed the multiple .shapeX classes in the JS and CSS to only use one (.shapes), as well as the shapeType variable. This was only meant to make the snippet easier.

You may want to add them back.

… Then, I played a little with your code and ended up with this:

(See comments in my code for details)

var numberOfElement = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];var initialRender = numberOfElement.slice(0, 17); // TAKIT: Modified to test
function renderAngle(data) { var angles = [120]; data.forEach(function(item, index) { angles.push((angles[index] + 20) % 360); // TAKIT: Added modulo }) return angles;}
function generateHtml() { var html = ''; var angles = renderAngle(initialRender); angles.forEach(function(item, index) { // TAKIT: Added use of a CSS var here, so all the CSS is in the CSS! html += '<div class="shapes' + '" style="--deg:' + item + 'deg;">' + item + '</div>'; }); document.querySelector('.circle').innerHTML = html; // TAKIT: Moved it here, after the loop}
generateHtml();
.main {  display: flex;  justify-content: center;  align-items: center;  height: 200px; /* TAKIT: reduced only for snippet */}
.circle { background: red; height: 150px; width: 150px; border-radius: 50%; position: relative;}
.shapes { position: absolute; top: calc(50% - 25px); /* TAKIT: position at center, 25px is half the height */ left: calc(50% - 3px); /* TAKIT: position at center, 3px is half the width */ width: 6px; height: 50px; background: green; /* TAKIT: Using CSS var is cool for the rotation Using translate here to shift it from the center */ transform: rotate(var(--deg)) translate(-50%, 104px); /* TAKIT: 104px in translate means 4px of margin between circle and shapes */}
<div class="main">  <div class="circle">  </div></div>

Distribute divs in a circle with appropriate angle

You can use index in forEach and fields.length to get to a fraction of 360 degrees, or a full circle.

var rotationBase = -90;
var rotation = rotationBase + 360 / fields.length * index;
element.style.transform = 'rotate(' + rotation + 'deg)';

Full working example

var content = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen'];

var container = document.getElementById("container");var size = window.innerWidth > window.innerHeight ? window.innerHeight : window.innerWidth;container.style.height = size + 'px';container.style.width = size + 'px';
function createFields() { for (var i = 0; i < content.length; i++) { var div = document.createElement('div'); div.className = "field"; div.innerHTML = content[i]; container.appendChild(div); }}
function distributeFields() { var myNodeList = document.querySelectorAll('.field'); var fields = Array.from(myNodeList); var width = size / 2; var height = size / 2; var angle = 0; var step = 2 * Math.PI / fields.length; var radius = 0.7 * width;
var angle = -90 * Math.PI / 180;
fields.forEach(function (element, index) { var x = Math.round(width + radius * Math.cos(angle)); var y = Math.round(height + radius * Math.sin(angle)); element.style.right = x + 'px'; element.style.top = y + 'px'; var rotationBase = -90; var rotation = rotationBase + 360 / fields.length * index; element.style.transform = 'rotate(' + rotation + 'deg)'; angle = angle - step; });}
window.onload = function () { createFields(); distributeFields();};
html, body { height: 100%; margin: 0; border:0; }#container { background-color: DarkSeaGreen; box-sizing: border-box; position: relative; margin: auto; overflow: hidden !important; }.field { width: 60px; height: 20px; position: absolute; color: #fff; background-color:indigo;}
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Circle</title></head><body><div id="container"></div></body></html>

Position DIV elements in circle

You'll almost certainly need CSS to position the divs with that kind of precision.

The general formula you're looking for is that for any given radian position on the circle (there are 2π radians in a circle), the x and y are:

x = originX + (Math.cos(radians) * radius);
y = originY + (Math.sin(radians) * radius);

Example: Live Copy | Live Source

CSS (you could use inline styles, I suppose):

#target {
position: absolute;
border: 1px solid black;
width: 1px;
height: 1px;
}

HTML:

<input type="button" id="theButton" value="Start/Stop">
<div id="target"></div>

JavaScript:

(function() {
var radians, maxRadians, target, radius, originX, originY, inc, timer;

radius = 50;
originX = 100;
originY = 100;

radians = 0;
maxRadians = 2 * Math.PI;
inc = 10 / 360;
target = document.getElementById("target");
positionTarget();

function positionTarget() {
var x, y;

x = originX + (Math.cos(radians) * radius);
y = originY + (Math.sin(radians) * radius);
console.log(x + "," + y);
target.style.left = x + "px";
target.style.top = y + "px";
radians += inc;
if (radians > maxRadians) {
radians -= maxRadians;
}
timer = setTimeout(positionTarget, 30);
}

document.getElementById("theButton").onclick = function() {
if (timer) {
clearTimeout(timer);
timer = 0;
}
else {
timer = setTimeout(positionTarget, 30);
}
};
})();

How can i show the position of a circle following mouse in other divs in Javascript

This script adjusts the position and size of the elements and listens when the blue circle will fall in these areas. When it leaves the area, the color style returns to its original state.

Example when the blue dot is in the region:
After resizing the "Run code snippet" screen, it may not work correctly. Please copy the code and try it.

var pos = 5;  //<-- Circle position
var csz = 15; //<-- Circle size
var c = document.getElementById('circle');

window.onload = window.onresize = elPositions;

function elPositions() {
blc = document.getElementById('blackShape');
blcH = blc.offsetHeight;
blcW = blc.offsetWidth;
blcT = blc.offsetTop;
blcL = blc.offsetLeft;

red = document.getElementById('redShape');
redH = red.offsetHeight;
redW = red.offsetWidth;
redT = red.offsetTop;
redL = red.offsetLeft;
}

function changeColor(y, x) {
if (redT - pos < y && redT + redH - pos - csz > y && redL - pos < x && redL + redW - pos - csz > x) {
c.style.backgroundColor = 'black';
}
else if (blcT - pos < y && blcT + blcH - pos - csz > y && blcL - pos < x && blcL + blcW - pos - csz > x) {
c.style.backgroundColor = 'red';
}
else {
c.style.backgroundColor = '';
}
}

////////////////////////////////////////////////

window.addEventListener("mousemove", function (e) {
let x = e.clientX;
let y = e.clientY;
let mouse = "Mouse : " + x + " " + y;
document.getElementById("mouseText").innerText = mouse;

let circle = document.getElementById("circleText");
let newX = e.clientX + pos;
let newY = e.clientY + pos;
let newCircle = "circle : " + newX + " " + newY;
document.getElementById("circleText").innerText = newCircle;

let circle2 = document.getElementById("circle");

circle2.style.marginTop = newY + 'px';

circle2.style.marginLeft = newX + 'px';

changeColor(newY, newX); //<-- New Line
});

function onMousemove(e) {
var m_posx = 0,
m_posy = 0,
e_posx = 0,
e_posy = 0,
obj = this;

//get mouse position on document crossbrowser
if (!e) {
e = window.event;
}

if (e.pageX || e.pageY) {
m_posx = e.pageX;
m_posy = e.pageY;
}

else if (e.clientX || e.clientY) {
m_posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
m_posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}

//get parent element position in document
if (obj.offsetParent) {
do {
e_posx += obj.offsetLeft;
e_posy += obj.offsetTop;
}

while ((obj = obj.offsetParent));
}

// mouse position minus elm position is mouseposition relative to element:
dbg.innerHTML = " X Position: " + (m_posx - e_posx) + " Y Position: " + (m_posy - e_posy);
}
html {
position: relative;
}

#circle {
width: 15px;
height: 15px;
background-color: blue;
border-radius: 50px;
position: absolute;
z-index: 1; /*<-- New Line*/
}

#row {
display: flex;
margin: 0 200px;
}

#blackShape {
position: relative;
width: 250px;
height: 250px;
background-color: black;
margin-top: 125px;
margin-left: 300px;
right: 180px;
}

#redCircle {
position: absolute;
width: 25px;
height: 25px;
background-color: red;
border-radius: 50px;
top: 50%;
left: 45%;
}

#redShape {
position: relative;
width: 250px;
height: 250px;
background-color: red;
margin-top: 125px;
margin-right: 150px;
}

#blackCircle {
position: absolute;
width: 25px;
height: 25px;
background-color: black;
border-radius: 50px;
top: 50%;
left: 45%;
}
<div id="mouseText"></div>
<div id="circleText"></div>
<div id="circle"></div>
<div id="dbg"></div>
<div id="row">
<div id="blackShape">
<div id="redCircle"></div>
</div>
<div id="redShape">
<div id="blackCircle"></div>
</div>
</div>

js hard to position divs around a circle

Your square tbltype is set to 0

Position icons into circle

2020 solution

Here's a more modern solution I use these days.

I start off by generating the HTML starting from an array of images. Whether the HTML is generated using PHP, JS, some HTML preprocessor, whatever... this matters less as the basic idea behind is the same.

Here's the Pug code that would do this:

//- start with an array of images, described by url and alt text
- let imgs = [
- {
- src: 'image_url.jpg',
- alt: 'image alt text'
- } /* and so on, add more images here */
- ];
- let n_imgs = imgs.length;
- let has_mid = 1; /* 0 if there's no item in the middle, 1 otherwise */
- let m = n_imgs - has_mid; /* how many are ON the circle */
- let tan = Math.tan(Math.PI/m); /* tangent of half the base angle */

.container(style=`--m: ${m}; --tan: ${+tan.toFixed(2)}`)
- for(let i = 0; i < n_imgs; i++)
a(href='#' style=i - has_mid >= 0 ? `--i: ${i}` : null)
img(src=imgs[i].src alt=imgs[i].alt)

The generated HTML looks as follows (and yes, you can write the HTML manually too, but it's going to be a pain to make changes afterwards):

<div class="container" style="--m: 8; --tan: 0.41">
<a href='#'>
<img src="image_mid.jpg" alt="alt text"/>
</a>
<a style="--i: 1">
<img src="first_img_on_circle.jpg" alt="alt text"/>
</a>
<!-- the rest of those placed on the circle -->
</div>

In the CSS, we decide on a size for the images, let's say 8em. The --m items are positioned on a circle and it's if they're in the middle of the edges of a polygon of --m edges, all of which are tangent to the circle.

If you have a hard time picturing that, you can play with this interactive demo which constructs the incircle and circumcircle for various polygons whose number of edges you pick by dragging the slider.

incircle and circumcircle of a hexagon

This tells us that the size of the container must be twice the radius of the circle plus twice half the size of the images.

We don't yet know the radius, but we can compute it if we know the number of edges (and therefore the tangent of half the base angle, precomputed and set as a custom property --tan) and the polygon edge. We probably want the polygon edge to be a least the size of the images, but how much we leave on the sides is arbitrary. Let's say we have half the image size on each side, so the polygon edge is twice the image size. This gives us the following CSS:

.container {
--d: 6.5em; /* image size */
--rel: 1; /* how much extra space we want between images, 1 = one image size */
--r: calc(.5*(1 + var(--rel))*var(--d)/var(--tan)); /* circle radius */
--s: calc(2*var(--r) + var(--d)); /* container size */
position: relative;
width: var(--s); height: var(--s);
background: silver /* to show images perfectly fit in container */
}

.container a {
position: absolute;
top: 50%; left: 50%;
margin: calc(-.5*var(--d));
width: var(--d); height: var(--d);
--az: calc(var(--i)*1turn/var(--m));
transform:
rotate(var(--az))
translate(var(--r))
rotate(calc(-1*var(--az)))
}

img { max-width: 100% }

See the old solution for an explanation of how the transform chain works.

This way, adding or removing an image from the array of images automatically arranges the new number of images on a circle such that they're equally spaced out and also adjusts the size of the container. You can test this in this demo.



OLD solution (preserved for historical reasons)

Yes, it is very much possible and very simple using just CSS. You just need to have clear in mind the angles at which you want the links with the images (I've added a piece of code at the end just for showing the angles whenever you hover one of them).

You first need a wrapper. I set its diameter to be 24em (width: 24em; height: 24em; does that), you can set it to whatever you want. You give it position: relative;.

You then position your links with the images in the center of that wrapper, both horizontally and vertically. You do that by setting position: absolute; and then top: 50%; left: 50%; and margin: -2em; (where 2em is half the width of the link with the image, which I've set to be 4em - again, you can change it to whatever you wish, but don't forget to change the margin in that case).

You then decide on the angles at which you want to have your links with the images and you add a class deg{desired_angle} (for example deg0 or deg45 or whatever). Then for each such class you apply chained CSS transforms, like this:

.deg{desired_angle} {
transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}

where you replace {desired_angle} with 0, 45, and so on...

The first rotate transform rotates the object and its axes, the translate transform translates the object along the rotated X axis and the second rotate transform brings back the object into position.

The advantage of this method is that it is flexible. You can add new images at different angles without altering the current structure.

CODE SNIPPET

    .circle-container {
position: relative;
width: 24em;
height: 24em;
padding: 2.8em;
/*2.8em = 2em*1.4 (2em = half the width of a link with img, 1.4 = sqrt(2))*/
border: dashed 1px;
border-radius: 50%;
margin: 1.75em auto 0;
}
.circle-container a {
display: block;
position: absolute;
top: 50%; left: 50%;
width: 4em; height: 4em;
margin: -2em;
}
.circle-container img { display: block; width: 100%; }
.deg0 { transform: translate(12em); } /* 12em = half the width of the wrapper */
.deg45 { transform: rotate(45deg) translate(12em) rotate(-45deg); }
.deg135 { transform: rotate(135deg) translate(12em) rotate(-135deg); }
.deg180 { transform: translate(-12em); }
.deg225 { transform: rotate(225deg) translate(12em) rotate(-225deg); }
.deg315 { transform: rotate(315deg) translate(12em) rotate(-315deg); }
    <div class='circle-container'>
<a href='#' class='center'><img src='image.jpg'></a>
<a href='#' class='deg0'><img src='image.jpg'></a>
<a href='#' class='deg45'><img src='image.jpg'></a>
<a href='#' class='deg135'><img src='image.jpg'></a>
<a href='#' class='deg180'><img src='image.jpg'></a>
<a href='#' class='deg225'><img src='image.jpg'></a>
<a href='#' class='deg315'><img src='image.jpg'></a>
</div>

positioning elements randomly in a circle

Basically you're looking at two circles, one with the radius of your pizza, and one with the radius of your topping. So you'd do something like this.

var pizzaRadius = 200,
toppingRadii = {
mushroom: 40,
pepperoni: 50,
onions: 25
};

function getToppingPosition(toppingRadius){
var posX, posY;
do {
posX = Math.floor(Math.random() * ((pizzaRadius * 2) - 1));
posY = Math.floor(Math.random() * ((pizzaRadius * 2) - 1));
} while(Math.sqrt(Math.pow(pizzaRadius - posX, 2) + Math.pow(pizzaRadius - posY, 2)) > pizzaRadius - toppingRadius)

return { x: posX, y: posY }
}

Basically what that function does is gets a random number within the bounds of the pizza and makes sure that the position + the size of the topping is on the pizza (so there's no toppings hanging over the edge. After that you'd just plug that function into your loop

$('.custom').click(function(e) {

var backgroung = $(this).attr('id')+'.png',
topping = 'mushroom';

for( i = 0 ; i < 40 ; i++ )
{
var pos = getToppingPosition(toppingRadii[topping])

var add = '<div style="top:'+pos.x+'px ; left:'+pos.y+'px ; width:100;height:100px;background-image:url("'+background+'");" ></div>';
$('#pitza').append(add);
}

});

Here's a fiddle http://jsfiddle.net/19h242yc/



Related Topics



Leave a reply



Submit