S.Tominoff

Frontend / Backend developer

Расставляем элементы по кругу с помощью jQuery и геометрии

Все началось с одной маленькой идеи. Впрочем как всегда.

Что получилось:

Как это сделать?

Для начала, хочу сразу предупредить, что для реализации подобных вещей не помешают базовые знания тригонометрии.

 

 

Концептуально, показанный на скриншоте выше зодиакальный круг — это просто сетка ссылок в контейнере.

 

Что–то вроде:

 

<div class="signs">
  <a href="#" class="signs__item">Лев</a>
  <a href="#" class="signs__item">Овен</a>
  <!-- ... -->
</div>

 

 

Если отключить в браузере JavaScript, то вместо круга мы увидим самую обычную сетку (прим. я не привожу здесь css для сетки, поскольку в проекте использовал kube.css).

 

 

Для того, чтобы оживить эту сетку, и превратить в кольцо, нужно сообщить каждой ссылке определенные координаты относительно блока-монитора.

 

 

Итак, у нас есть 12 элементов, которые мы должны равномерно распределить на окружности (360 o), т.е. получается 12 секторов с углами в 30o.

 

Обратимся к базовой тригонометрии и вспомним, что y — это синус угла, а x это его косинус.

 

Математические функции в Javascript работают с радианами, поэтому перед вычислениями нужно перевести градусы в радианы по формуле:

 

RAD = DEG * (PI / 180)

 

RAD - угол в радианах, 
DEG - угол в градусах

 

Отобразим эту формулу в виде простейшей функции–конвертёра:

 

function toRad(deg) {
    return deg * (Math.PI / 180);
}

 

Теперь нам нужно определить центр координат, а также смещение контейнера, в котором будет строиться наш круг:

 

// root - элемент-контейнер в котором будет выстраиваться круг

// для вычисления смещения используем стандартные функции jQuery
var x = root.position().left,
var y = root.position().top;

// определяем - требуется ли использовать смещение в расчётах
// если нет - просто обнуляем x и y
if(root.css('position') == 'relative')
  x = y = 0;

// вычисляем наш центр координат
// для этого складываем смещение и ширину/высоту и просто делим на 2
var cx = Math.round((root[0].offsetWidth + x) / 2),
    cy = Math.round((root[0].offsetHeight + y) / 2);

 

Смещение нужно, только в том случае, если позиционирование root не является относительным (css position: relative).

 

В обратном случае все элементы внутри и без этого будут позиционироваться относительно родительского элемента благодаря CSS.

 

Итак, фундамент готов - осталось только дописать вычисление позиции каждого отдельного элемента:

 

/*
  Вычисляем угол поворота одного сектора в радианах
*/
var sectorAngle = toRad(360 / sectorsCount);

/*
  radius - радиус окружности которую мы строим
  cx - центр по оси X
  radius * cos - получаем абсциссу
  sectorAngle * iter - получаем угол поворота для текущего элемента
*/
var toLeft = Math.round(cx + (options.radius * Math.cos(sectorAngle * iter))));

 

iter - индекс обрабатываемого элемента, с помощью которого делается угловой сдвиг,

radius - радиус окружности заданный в опциях виджета,

cx - вычисленный ранее центр оси координат Ox.

 

Таким образом мы получили координату x. Таким же нехитрым способом определяется и y:

 

// ордината
var toTop = Math.round(cy + (options.radius * Math.cos(sectorAngle * iter))));

 

Ну, а зная требуемые координаты элемента, нам остаётся лишь позиционировать элементы.

 

Для этого мы можем использовать jQuery метод css, либо, для более эффектной, плавной расстановки элементов методом animate:

 

/*
  Чтобы всё расставлялось плавно - используем jquery метод animate
*/
$elem.animate({
    left : toLeft, 
    top : toTop,
    opacity : 1
},options.animationSpeed);

 

Код целиком: