Модуль Special Visually для Joomla 3

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

Сейчас очень популярны горизонтальные и вертикальные слайдеры и карусели элементов. Существует большое количество готовых библиотек, для реализации каруселей. Но, не так давно, наткнулся на один сайт, где элементы были расположены и переключались по кругу. Для создания круговых каруселей есть готовые 3D библиотеки каруселей, но, они не позволяли реализовать именно то, что хотелось мне, при этом контроль над элементами был практически нулевой, сложно было исправить функционал "под себя".

Как итог, я решил самостоятельно разобраться и сделать подобную карусель элементов. Демонстрацию карусели Вы можете найти по ссылке в конце статьи.

Функционал простой. Заранее предупрежу, что все элементы придется просчитывать и размещать (позиционировать) вручную для каждого размера контента. В качестве еще одного минуса, отмечу, что из-за ручного расчета позиционирования элементов не получится реализовать динамическое изменение количества элементов в карусели.

Как это работает:

Итак, предлагаю разобраться, из чего вообще будет состоять карусель.

Во-первых, Вам необходимо подобрать изображение, которое будет служить основой круговой карусели.

Далее делаем следующую разметку:

<div class="circle-carousel">
	<div class="container">
		<div class="wraper">
			<ul class="circle-container">
				<li class="circle-item selected">
					<img class="circle-item-image" src="/images/thumb-001.jpg" alt="">
					<div class="circle-item-content">
						<div class="circle-item-title">Цельнометаллический алхимик новые серии</div>
						<div class="circle-item-desc">Будь в рядах первых, кто увидит новые серии.</div>
						<div class="circle-item-link">#</div>
					</div>
				</li>
				<li class="circle-item">
					<img class="circle-item-image" src="/images/thumb-002.jpg" alt="">
					<div class="circle-item-content">
						<div class="circle-item-title">Обои на рабочий стол</div>
						<div class="circle-item-desc">Скачай обои из аниме Цельнометаллический алхимик</div>
						<div class="circle-item-link">#</div>
					</div>
				</li>
				<li class="circle-item">
					<img class="circle-item-image" src="/images/thumb-003.jpg" alt="">
					<div class="circle-item-content">
						<div class="circle-item-title">Познай мир Цельнометаллического алхимика</div>
						<div class="circle-item-desc">Изучи историю и героев любимого аниме</div>
						<div class="circle-item-link">#</div>
					</div>
				</li>
				<li class="circle-item">
					<img class="circle-item-image" src="/images/thumb-004.jpg" alt="">
					<div class="circle-item-content">
						<div class="circle-item-title">Цельнометаллический алхимик - Студия аниме</div>
						<div class="circle-item-desc">Всё о процессе создания аниме</div>
						<div class="circle-item-link">#</div>
					</div>
				</li>
				<li class="circle-item">
					<img class="circle-item-image" src="/images/thumb-005.jpg" alt="">
					<div class="circle-item-content">
						<div class="circle-item-title">Цельнометаллический алхимик - Аксессуары</div>
						<div class="circle-item-desc">Магазин игрушек и аксессуаров по аниме</div>
						<div class="circle-item-link">#</div>
					</div>
				</li>
				<li class="circle-item">
					<img class="circle-item-image" src="/images/thumb-003.jpg" alt="">
					<div class="circle-item-content">
						<div class="circle-item-title">Хочешь быть в рядах первых?</div>
						<div class="circle-item-desc">Подписывайся на новости и оповещения</div>
						<div class="circle-item-link">#</div>
					</div>
				</li>
			</ul>
			<div class="circle-content">
				<div class="circle-content-teaser">
					<div class="circle-content-teaser-title"></div>
					<div class="circle-content-teaser-desc"></div>
				</div>
				<a href="#" class="circle-content-readmore">Смотреть подробнее</a>
			</div>
			<div class="circle-nav">
				<div class="circle-nav-prev">
					<a href="#">&larr;</a>
				</div>
				<div class="circle-nav-next">
					<a href="#">&rarr;</a>
				</div>
			</div>
		</div>
	</div>
</div>

Здесь хочу акцентировать внимание на блок <ul class="circle-container">...</ul> В нем будут перечисляться наши элементы, их может быть сколько Вам угодно. Этот блок естественно можно сделать через цикл, если Ваши данные берутся из базы или находятся в массиве.

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

Не обращаем внимание на блоки с классом .circle-item-content, в них мы будем хранить заголовки, описания и ссылки на элементы, они никак не будут отображаться, мы их скроем, но, сами значения будем брать для отображения в момент выбора.

Также у нас присутствует блок навигации <div class="circle-nav">...</div> - стрелки прокрутки назад и вперед, их можно будет убрать, если они Вам будут не нужны.

И соответственно блок <div class="circle-content">...</div> в который мы будем помещать заголовок, описание и ссылку выбранного элемента для отображения, т.е. как раз из блока с классом .circle-item-content каждого элемента.

Структура готова. Теперь необходимо оформить всё содержимое:

.circle-carousel {
	
}

.circle-carousel .container {
	
}

.circle-carousel .container .wraper {
	position: relative;
	overflow: hidden;
	margin-left: auto;
	margin-right: auto;
	width: 1000px;
	height: 1000px;
}

.circle-container {
	padding: 0;
	margin: 0;
	position: absolute;
	list-style: none;
	padding: 0;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	margin-left: auto;
	margin-right: auto;
	background: url('/../images/circle-background.png') no-repeat center 0;
	background-size: cover;
	transition: all 1.5s ease-in;
	-webkit-transform: rotate(0deg);
	-moz-transform: rotate(0deg);
	-ms-transform: rotate(0deg);
	-o-transform: rotate(0deg);
	transform: rotate(0deg);
}

.circle-item {
	display: block;
	position: absolute;
	width: 250px;
	height: 250px;
}

.circle-item.selected {
	
}

.circle-item:nth-of-type(1){
	top: 50px;
	left: 375px;
	-webkit-transform: rotate(0deg);
	transform: rotate(0deg);
}

.circle-item:nth-of-type(2){
	top: 210px;
	left: 655px;
	-webkit-transform: rotate(60deg);
	transform: rotate(60deg);
}

.circle-item:nth-of-type(3){
	top: 540px;
	left: 655px;
	-webkit-transform: rotate(120deg);
	transform: rotate(120deg);
}

.circle-item:nth-of-type(4){
	top: 700px;
	left: 375px;
	-webkit-transform: rotate(180deg);
	transform: rotate(180deg);
}

.circle-item:nth-of-type(5){
	top: 540px;
	left: 95px;
	-webkit-transform: rotate(240deg);
	transform: rotate(240deg);
}

.circle-item:nth-of-type(6){
	top: 210px;
	left: 95px;
	-webkit-transform: rotate(300deg);
	transform: rotate(300deg);
}

.circle-item .circle-item-image {
	border-radius: 50%;
	border: #ff0000 1px solid;
	margin: 3px;
	max-width: 100%;
	max-height: 100%;
	width: 100%;
	height: 100%;
	opacity: 0.5;
	filter: alpha(opacity=50);
	-webkit-transition: opacity 1s linear;
	transition: opacity 1s linear;
}

.circle-item.selected .circle-item-image, .circle-item .circle-item-image:hover{
	opacity: 1;
	filter: alpha(opacity=100);
	cursor: pointer;
}

.circle-item-content {
	display: none;
}

.circle-content {
	font-family: Franklin Gothic Medium,Franklin Gothic,ITC Franklin Gothic,Arial,sans-serif;
	text-shadow: 2px 2px 8px #535353;
	text-align: center;
	position: absolute;
	left: 0;
	right: 0;
	margin-left: 0;
	margin-right: 0;
	top: 490px;
	padding-right: 30px;
	padding-left: 30px;
	pointer-events: none;
}

.circle-content-teaser {
	text-align: center;
}

.circle-content-teaser-title {
	padding: 5px 15px;
	display: table;
	margin-top: 30px;
	color: #fff;
	font-size: 2.25rem;
	margin: 0 auto;
	padding: 0;
	line-height: normal;
	text-decoration: none;
}

.circle-content-teaser-desc {
	color: #a1a1a1;
	font-size: 1.25rem;
}

.circle-content-readmore {
	margin-top: 20px;
	margin-bottom: 20px;
	color: #fff;
	pointer-events: auto;
}

.circle-nav {
	
}

.circle-nav .circle-nav-prev, .circle-nav .circle-nav-next {
	position: absolute;
	z-index: 1;
	font-size: 2.5rem;
	top: 220px;
	display: block;
}

.circle-nav .circle-nav-prev {
	left: 350px;
}

.circle-nav .circle-nav-next {
	right: 350px;
}

.circle-nav .circle-nav-prev a, .circle-nav .circle-nav-next a {
	color: #999;
	text-decoration: none;
}

.circle-nav .circle-nav-prev a:hover, .circle-nav .circle-nav-next a:hover {
	color: #fff;
	cursor: pointer;
}

Здесь обратите внимание на оформление класса .circle-container, в нем мы как раз указываем изображение, которое будет нашей основой. Изображение желательно иметь равным или больше, чем размер самого блока карусели. Размер блока мы задаем классе .circle-carousel .container .wraper, у меня размер равен 1000х1000 пикселей (карусель у нас круглая, поэтому блок должен быть по равным по ширине и высоте).

Самое важное в наших стилях, это оформление элементов, поэтому уделите особое внимание оформлению стилей .circle-item:nth-of-type(номер)

Именно здесь Вам необходимо рассчитать и задать позиции для каждого элемента в нашей окружности. У меня 6 элементов, поэтому я также каждый из них поворачиваю на +60 градусов относительно друг друга, это необходимо для того, чтобы выбранный в конечном итоге при повороте встал на нужный градус. По сути, позиционирование элементов самое сложное во всём процессе создания круговой карусели.

Все остальные стили, это просто оформление, Вы можете крутить их как Вам будет угодно. Я не специалист в оформлении, поэтому у меня всё просто.

Итак, теперь добавим скрипты, которые будут обрабатывать нашу карусель:

jQuery(function($) {
	function appendContent(elem) {
		$('.circle-content .circle-content-teaser-title').html(elem.find('.circle-item-title').text());
		$('.circle-content .circle-content-teaser-desc').html(elem.find('.circle-item-desc').text());
		$('.cricle-content .circle-content-readmore').attr('href', elem.find('.circle-item-link').text());
	}
	
	var degree = 0;
	
	function rotateElem(elem) {
		var indexCurent;
		var countElem = $('.circle-container .circle-item').length;
		var indexElem = $('.circle-container .circle-item').index(elem);
		
		$('.circle-container .circle-item').each(function(index){
			if ($(this).hasClass('selected')) {
				indexCurent = index;
			}
		});
		
		$('.circle-container .circle-item.selected').removeClass('selected');
		
		if (indexCurent < indexElem) {
			degree = degree - ((360 / countElem) * (indexElem - indexCurent));
		}
		if (indexCurent > indexElem) {
			degree = degree + ((360 / countElem) * (indexCurent - indexElem));
		}
		
		$('.circle-container').css({
			'-webkit-transform': 'rotate(' + degree + 'deg)',
			'-moz-transform': 'rotate(' + degree + 'deg)',
			'-ms-transform': 'rotate(' + degree + 'deg)',
			'-o-transform': 'rotate(' + degree + 'deg)',
			'transform': 'rotate(' + degree + 'deg)'
		});
		
		elem.addClass('selected');
	}
	
	function rotatePrev(elem) {
		$('.circle-container .circle-item.selected').removeClass('selected');
		
		var countElem = $('.circle-container .circle-item').length;
		var indexElem = $('.circle-container .circle-item').index(elem);
		degree = degree + (360 / countElem);
		
		$('.circle-container').css({
			'-webkit-transform': 'rotate(' + degree + 'deg)',
			'-moz-transform': 'rotate(' + degree + 'deg)',
			'-ms-transform': 'rotate(' + degree + 'deg)',
			'-o-transform': 'rotate(' + degree + 'deg)',
			'transform': 'rotate(' + degree + 'deg)'
		});
		
		elem.addClass('selected');
	}
	
	function rotateNext(elem) {
		$('.circle-container .circle-item.selected').removeClass('selected');
		
		var countElem = $('.circle-container .circle-item').length;
		var indexElem = $('.circle-container .circle-item').index(elem);
		degree = degree - (360 / countElem);
		
		$('.circle-container').css({
			'-webkit-transform': 'rotate(' + degree + 'deg)',
			'-moz-transform': 'rotate(' + degree + 'deg)',
			'-ms-transform': 'rotate(' + degree + 'deg)',
			'-o-transform': 'rotate(' + degree + 'deg)',
			'transform': 'rotate(' + degree + 'deg)'
		});
		
		elem.addClass('selected');
	}
	
	$('.circle-container .circle-item').on('click', function(e) {
		e.preventDefault();
		var elem = $(this);
		rotateElem(elem);
		appendContent(elem);
	});
	
	$('.circle-nav .circle-nav-prev a').on('click', function(e) {
		e.preventDefault();
		var prev = $('.circle-container .circle-item.selected').prev();
		if (prev.length == 0) {
			prev = $('.circle-container .circle-item:last-child');
		}
		rotatePrev(prev);
		appendContent(prev);
	});
	
	$('.circle-nav .circle-nav-next a').on('click', function(e) {
		e.preventDefault();
		var next = $('.circle-container .circle-item.selected').next();
		if (next.length == 0) {
			next = $('.circle-container .circle-item:first-child');
		}
		rotateNext(next);
		appendContent(next);
	});
	
	appendContent($('.circle-container .circle-item.selected'));
});

Здесь у нас 4 функции и 3 обработки нажатия (нажатие на кнопки "назад", "вперед" и нажатие на сам элемент):
appendContent(elem) - функция, которая получает заголовок, описание и ссылку элемента и размещать в центральном блоке;
rotateElem(elem) - функция, которая будет поворачивать всю карусель к элементу, на который был произведен клик;
rotatePrev(elem) - функция, которая будет поворачивать карусель на один элемент назад при клике на кнопку "назад";
rotateNext(elem) - функция, которая будет поворачивать карусель на один элемент вперед при клике на кнопку "вперед".

Скрипт можно даже не трогать, вставить как есть, независимо от количества элементов в структуре карусели, т.к. расчет ведется в функции. Всё что Вам понадобится, это изменить названия классов, в случае, если Вы их изменяли в разметке.

И, не менее важная деталь - не забываем подключить библиотеку jQuery.

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

Демо


Оставьте свой комментарий

Оставить комментарий от имени гостя

0 / 2500 Ограничение символов
Ваш текст должен быть в пределах 10-2500 символов
Комментарии | Добавить свои
  • Комментарии не найдены