circle packing

by michae1

HTML

<div class="field">
  <div class="target"></div>
</div>

CSS

.field {
  position: relative;
  width: 300px;
  height: 300px;
  box-sizing: border-box;
  border: 1px solid #dbdbdb;
  background-color: white;
  overflow: auto;
}
.target {
  position: absolute;
  top: 50%;
  left: 50%;
}
.avatar {
  position: absolute;
  border-radius: 50%;
  border: 1px solid;
  overflow: hidden;
  box-sizing: border-box;
  padding: 10px;
  text-align: center;
  transition: all .2s ease-out;
}
.avatar:hover {
  background-color: #dbdbdb;
  width: 80px !important;
  height: 80px !important;
  z-index: 2;
  box-shadow: 2px 2px 2px rgba(0,0,0,.3);
}

JavaScript

var target = document.querySelector('.target');
var circles = [];
function addCircle(radius) {
	radius = radius || Math.floor(Math.random() * 5 + 20);
	var coordss = findPosition(radius);
  circles.push({
  	coords: {
    	x: coordss.x,
      y: coordss.y
    },
    radius: radius
  });
  var avatar = document.createElement('div');
  avatar.style.width = radius * 2 + 'px';
  avatar.style.height = radius * 2 + 'px';
  avatar.style.top = coordss.y - radius + 'px';
  avatar.style.left = coordss.x - radius + 'px';
  avatar.className = 'avatar';
  avatar.innerHTML = circles.length;
  target.appendChild(avatar);
}

function isCollision (newCircle) {
	var currentCircle;
  var deltaX;
  var deltaY;
  var distance;
	for (var i = 0, len = circles.length; i < len; i ++) {
  	currentCircle = circles[i];
    deltaX = newCircle.coords.x - currentCircle.coords.x;
    deltaY = newCircle.coords.y - currentCircle.coords.y;
    distance = Math.sqrt(deltaX*deltaX + deltaY*deltaY)
    if (distance < newCircle.radius + currentCircle.radius) {
    	return true;
    }
  }
  return false;
}

function findPosition (radius) {
	var minDistance;
  var deltaAngle = 1;
  var distance = 0;
  var x, y;
  for (var angle = 0; angle < 360; angle += deltaAngle) {
  	distance = 0
  	x = Math.cos(angle) * distance;
  	y = Math.sin(angle) * distance;
    while (isCollision({
      coords: {
        x: x,
        y: y
      },
      radius: radius
    })) {
      distance++;
      x = Math.cos(angle) * distance;
      y = Math.sin(angle) * distance;
    };
    if (angle === 0 || distance < minDistance.distance) {
      minDistance = {
        distance: distance,
        coords: {
          x: x,
          y: y
        }
      }
    }
  }
  return {
    x: minDistance.coords.x,
    y: minDistance.coords.y
  }
}

function init () {
	addCircle(10);
  for (var i = 0; i < 7; i++) {
  	addCircle();
  }
}
init();