'How to align elements around the perimeter of a circle?

I'm trying to align elements around a circle like this:

enter image description here

this is my code, I've added a drag function to rotate the wrapper box, I'm not very Math savy so I don't know where to go from here.

https://codepen.io/pedro_coelho/pen/GRQKWPW


const box = wrapper.getBoundingClientRect()
const xCenter = (box.left + box.right) / 2;
const yCenter = (box.top + box.bottom) / 2;

console.log(xCenter, yCenter);


wrapper.style.transformOrigin = `${xCenter}, ${yCenter}`;

//wrapper.style.transform = 'rotate(30deg)';

document.onmousedown = dragMouseDown;

let mouseX, mouseY, offsetX,offsetY;

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
     mouseX = e.clientX;
     mouseY = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    offsetX = mouseX - e.clientX;
    offsetY = mouseY - e.clientX;
    // rotate:
    wrapper.style.transform = `rotate(${offsetX/5}deg)`;
    
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
  }


Solution 1:[1]

Instead of doing the math yourself, CSS can help as it will rotate an element a given number of degrees.

If we create elements which have height the radius of the circle and some width (which you decide) and place them all top center of the container (.circle) element we can rotate the nth one about its bottom central point a number of degrees depending on its child position.

This could give us something like this for 10 elements with angle 36 degrees between them:

enter image description here

Within each of those elements (or however many you actually want to show) you can place your divs which have the image, and anything else you want, at the top of the element.

We then have to rotate the whole circle back an amount to get an equal number of elements either side of the vertical.

This snippet uses CSS variables to do the calculation and you can set the number of elements to be shown and the angle between them, CSS does the rest.

.circle {
  position: relative;
  --w: 50vmin;
  width: var(--w);
  height: var(--w);
  rdisplay: flex;
  --show: 5;
  /* put to the number you want to have */
  --angle: 36;
  /* put to the angle between them */
  --num: calc(360 / var(--angle));
  transform: rotate(calc(((var(--show) + 1) / 2 * var(--angle)) * -1deg));
}

.element {
  width: calc(var(--w) / 6);
  /* set to whatever width you want */
  height: 50%;
  top: 0;
  left: calc(50% - 1vw);
  transform-origin: center bottom;
  transform: rotate(calc(360deg * var(--n) / var(--num)));
  position: absolute;
}

.element>* {
  background-position: center center;
  background-size: contain;
  background-repeat: no-repeat;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 1 / 1.5;
  /* put this to what you want */
}

.element:nth-child(1) {
  --n: 1;
}

.element:nth-child(2) {
  --n: 2;
}

.element:nth-child(3) {
  --n: 3;
}

.element:nth-child(4) {
  --n: 4;
}

.element:nth-child(5) {
  --n: 5;
}

.element:nth-child(1)>* {
  background-image: url(https://picsum.photos/id/1015/200/200);
}

.element:nth-child(2)>* {
  background-image: url(https://picsum.photos/id/1015/200/200);
}

.element:nth-child(3)>* {
  background-image: url(https://picsum.photos/id/1015/200/200);
}

.element:nth-child(4)>* {
  background-image: url(https://picsum.photos/id/1015/200/200);
}

.element:nth-child(5)>* {
  background-image: url(https://picsum.photos/id/1015/200/200);
}
<meta name="viewport" content="width=device-width, initial-scale=1">
<div class="circle">
  <div class="element">
    <div></div>
  </div>
  <div class="element">
    <div></div>
  </div>
  <div class="element">
    <div></div>
  </div>
  <div class="element">
    <div></div>
  </div>
  <div class="element">
    <div></div>
  </div>
</div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 A Haworth