Галерея изображений со слайдером

В данном уроке мы создаём галерею со слайдером для миниатюр изображений. Идея заключается в том, чтобы сделать широкую область для миниатюр, которая будет формироваться один раз при загрузке альбома.  Миниатюры при загрузке будут прокручиваться с последней в списке до первой, демонстрируя посетителю все доступные изображения. Посетитель потом сможет выбрать нужное изображение, используя слайдер снизу галереи.  Когда на миниатюре нажимается кнопка мыши, она перемещается в центр экрана и открывается полноразмерное изображение. Навигация между изображениями осуществляется в виде проскальзывания изображений за пределы экрана, при этом  слой с миниатюрами также перемещается, чтобы соответствовать отображаемому полноразмерному изображению. Когда просмотр полноразмерных изображений закрывается, текущая большая картинка сворачивается до миниатюры.

Для данной галереи будет использоваться библиотека jQuery UI и плагин jQuery Easing.

demosourse

Разметка

У нас будет один основной контейнер, в котором содержатся все остальные элементы:

<div id="fp_gallery" class="fp_gallery">
...
</div>

Внутрь основного контейнера первым делом мы добавляем фоновое изображение и элемент div, который будет содержать текстуру:

<img src="images/bgimg.jpg" class="fp_bgImage" />
<div class="fp_bgPattern"></div>

Идея заключается в том, чтобы использовать небольшое изображение (375х500 пикселей), растягивать его по ширине на весь экран и делать почти полностью прозрачным, что придает фону туманный загадочный вид. Почти прозрачная текстура добавляется сверху, так что фоновое изображение видно сквозь нее.

Теперь добавим заголовки и меню с названиями альбомов:

<h1>ДЕМОНСТРАЦИЯ ГАЛЕРЕИ</h1>
<h2>для сайта RUSELLER.COM</h2>
<p>выберите город</p>

<ul id="fp_galleryList" class="fp_galleryList">
	<li>Париж</li>
	<li>Нью Йорк</li>
</ul>

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

<div id="fp_thumbContainer">
	<div id="fp_thumbScroller">
		<div class="container">
			<div class="content">
				<div><a href="#"><img src="images/album1/thumbs/1.jpg" alt="images/album1/1.jpg" class="thumb" /></a></div>
			</div>
			<div class="content">
				<div><a href="#"><img src="images/album1/thumbs/2.jpg" alt="images/album1/2.jpg" class="thumb" /></a></div>
			</div>

			...

		</div>
		<div class="container">
			<div class="content">
				<div><a href="#"><img src="images/album2/thumbs/1.jpg" alt="images/album2/1.jpg" class="thumb" /></a></div>
			</div>
			<div class="content">
				<div><a href="#"><img src="images/album2/thumbs/2.jpg" alt="images/album2/2.jpg" class="thumb" /></a></div>
			</div>
			
			...

		</div>					
	</div>
</div>

Элементы изображений миниатюр содержат в атрибуте alt путь к полноразмерной версии картинки.

Слайдер имеет следующую структуру:

<div id="fp_scrollWrapper" class="fp_scrollWrapper">
	<span id="fp_prev_thumb" class="fp_prev_thumb"></span>
	<div id="slider" class="slider"></div>
	<span id="fp_next_thumb" class="fp_next_thumb"></span>
</div>

И, наконец, добавляем все элементы для режима просмотра полноразмерного изображения:

<div id="fp_overlay" class="fp_overlay"></div>
<div id="fp_loading" class="fp_loading"></div>
<div id="fp_next" class="fp_next"></div>
<div id="fp_prev" class="fp_prev"></div>
<div id="fp_close" class="fp_close">ЗАКРЫТЬ</div>

Разметка готова, можно переходить к заданию стилей.

CSS

Для начала сбросим установки по умолчанию и добавим несколько правил, касающихся страницы в целом:

*{
	margin:0;
	padding:0;
}
body {
	margin:0;
	padding:0;
	background:#000;
	text-align:center;
	color:#fff;
	font-family:Arial, Helvetica, sans-serif;
	overflow:hidden;
}

Фоновое изображение и текстура имеют следующие стили:

.fp_bgPattern{
	position:fixed;
	top:0px;
	left:0px;
	width:100%;
	height:100%;
	background:transparent url(../images/greyscale_natural_grunge3.jpg) repeat bottom left;
	opacity:0.3;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);
}
img.fp_bgImage{
	position:fixed;
	top:0px;
	left:0px;
	width:100%;
	opacity:0.2;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
}

Оба элемента имеют фиксированное положение и маленькое значение свойства opacity, чтобы получить описанный выше эффект.

Теперь зададим стили для заголовков:

h1{
	font-weight:normal;
	margin:40px 0px 10px 0px;
	text-transform:uppercase;
}
h2{
	font-weight:normal;
	font-size:22px;
	color:#FFED2F;
	margin-bottom:50px;
}

Нам не нужны никакие контуры на элементах, которые будут воспринимать нажатия кнопки мыши:

a{
	outline:none;
}

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

Альбом галереи будет стилизован так:

ul.fp_galleryList{
	list-style:none;
	position:relative;
}
ul.fp_galleryList li{
	display:inline;
	margin:0px 30px;
	text-transform:uppercase;
	cursor:pointer;
	font-size:14px;
	text-shadow:0px 0px 1px #fff;
}
ul.fp_galleryList li.current{
	color:#FFED2F;
}
ul.fp_galleryList li.current:hover{
	border:none;
}
ul.fp_galleryList li:hover{
	border-bottom:1px solid #fff;
}

Белая тень вокруг текста придает шрифту очень гладкий вид в браузере Chrome.

Контейнер миниатюр при начальной загрузке страницы скрыт, поэтому мы устанавливаем для него высоту 0 пикселей. В коде Javascript он будет "открываться" с помощью анимации при установке высоты в 240 пикселей. Мы устанавливаем для него ширину 100% от ширины экрана и запрещаем переполнение. В то же время, элементы внутри основного контейнера будут иметь такую ширину, чтобы обеспечивать прокрутку содержания:

#fp_thumbContainer{
	position:relative;
	overflow:hidden;
	width:100%;
	margin:50px 0 30px 0;
	height:0px; /*выводим 240px*/
	background-color:#111;
	-moz-box-shadow:0px 0px 10px #000 inset;
	-webkit-box-shadow:0px 0px 10px #000 inset;
	box-shadow:0px 0px 10px #000 inset;
}

Элемент thumbScroller будет контейнером, в котором будет прокручиваться содержание:

#fp_thumbScroller{
	position:relative;
	overflow:hidden;
}

Контейнер element представляет альбом, и его ширина будет определяться динамически в коде JavaScript на основании содержимого:

#fp_thumbScroller .container{
	position:relative;
	float:left;
	display:none;
}
#fp_thumbScroller .content{
	float:left;
	margin-top:17px;
}
#fp_thumbScroller .content div{
	margin:0px 5px;
	height:100%;
}

Элементу с изображением сделаем белую рамку со скругленными углами и тень:

#fp_thumbScroller img{
	border:3px solid #fff;
	height:200px;
	-moz-box-shadow:1px 1px 3px #000;
	-webkit-box-shadow:1px 1px 3px #000;
	box-shadow:1px 1px 3px #000;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
}
#fp_thumbScroller a{
	padding:1px;
}

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

.fp_overlay{
	display:none;
	position:fixed;
	top:0px;
	left:0px;
	right:0px;
	bottom:0px;
	z-index:10;
	background:#000;
	opacity:0.8;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=80);
}

div индикатора загрузки изображения будет центрироваться относительно всей страницы, мы используем трюк "50%/отрицательное значение поля":

.fp_loading{
	display:none;
	position:fixed;
	top:50%;
	left:50%;
	margin:-35px 0px 0px -35px;
	background:#fff url(../images/loader.gif) no-repeat center center;
	width:70px;
	height:70px;
	z-index:9999;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
	-moz-box-shadow:1px 1px 3px #000;
	-webkit-box-shadow:1px 1px 3px #000;
	box-shadow:1px 1px 3px #000;
	opacity:0.7;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}

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

.fp_next,
.fp_prev,
.fp_close{
	width:50px;
	height:50px;
	position:fixed;
	bottom:50%;
	margin-top:-25px;
	cursor:pointer;
	opacity:0.7;
	z-index:1000;
	-moz-box-shadow:0px 0px 3px #000;
	-webkit-box-shadow:0px 0px 3px #000;
	box-shadow:0px 0px 3px #000;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}
.fp_next:hover,
.fp_prev:hover,
.fp_close:hover
{
	opacity:0.9;
}

Кроме того, каждый из них будет иметь индивидуальные установки:

.fp_next{
	background:#fff url(../images/next.png) no-repeat center center;
	right:-50px; /*выводим 10*/
}
.fp_prev{
	background:#fff url(../images/prev.png) no-repeat center center;
	left:-50px; /*выводим 10*/
}
.fp_close{
	display:none;
	width:110px;
	text-align:center;
	padding-left:10px;
	text-transform:uppercase;
	line-height:50px;
	top:10px;
	right:10px;
	margin-top:0px;
	background:#fff url(../images/close.png) no-repeat 10px 50%;
	color:#000;
}

Теперь определим стили элемента scrollWrapper, который содержит слайдер и его навигацию:

.fp_scrollWrapper{
	display:none;
	width:300px;
	padding:10px 45px;
	height:12px;
	position:relative;
	margin:30px auto;
	background:#111;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
}

Также нужно изменить стиль некоторым свойствам CSS для элементов jQuery UI, которые имеют установки по умолчанию, определенные в библиотеке. Ниже определённые правила надо вставлять в код CSS после места вставки стилей jQuery UI.

Следующие стили используются полоской слайдера:

.ui-widget-content{
	height:12px;
	background-color:#353535;
	position:relative;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
}

И его элементами управления:

.ui-slider-horizontal .ui-slider-handle{
	margin-top:5px;
	z-index:1;
	outline:none;
	cursor:pointer;
	border:none;
	width:15px;
	height:12px;
	background: #9b9b9b;
	margin-left:-7px;
}

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

.ui-state-default {
	background-image:none;
}

Элементы навигации слайдера имеют следующие стили:

.fp_prev_thumb,
.fp_next_thumb{
	background:transparent url(../images/nav.png) no-repeat top left;
	position:absolute;
	top:8px;
	width:15px;
	height:17px;
	cursor:pointer;
}
.fp_prev_thumb:hover{
	background-position:left top;
}
.fp_next_thumb:hover{
	background-position:right top;
}
.fp_prev_thumb{
	left:10px;
	background-position:left bottom;
}
.fp_next_thumb{
	right:10px;
	background-position:right bottom;
}

Мы используем одно фоновое изображение, которое содержит две стрелки, каждая стрелка имеет активное и неактивное состояние.

И в завершении мы задаем стиль для элемента, который содержит большое изображение. Положение изображения будет устанавливаться в JavaScript:

img.fp_preview{
	position:fixed;
	z-index:999;
	border:3px solid #fff;
	-moz-box-shadow:1px 1px 3px #000;
	-webkit-box-shadow:1px 1px 3px #000;
	box-shadow:1px 1px 3px #000;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
	opacity:0;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);
}

Теперь можно перейти к JavaScript коду, с помощью которого создаются чудесные эффекты.

JavaScript

Для эффектов будет использоваться плагин jQuery easing, так что обязательно включите его в код. Наша функция jQuery начинается с определения переменных:

//кэшируем 
//основной контейнер галереи
var $fp_gallery	= $('#fp_gallery')
//покрывной слой при показе большого изображения
var $fp_overlay	= $('#fp_overlay');
//статус загрузки изображения
var $fp_loading	= $('#fp_loading');
//кнопки "следующее" и "предыдущее"
var $fp_next = $('#fp_next');
var $fp_prev = $('#fp_prev');
//кнопка "закрыть"
var $fp_close = $('#fp_close');
//основной контейнер для структуры миниатюр
var $fp_thumbContainer = $('#fp_thumbContainer');
//контейнер для слайдера jquery ui
var $fp_scrollWrapper = $('#fp_scrollWrapper');
//общее количество изображений
var nmb_images = 0;
//индекс выбранной галереи
var gallery_idx = -1;
//контейнер для полоски прокрутки
var $fp_thumbScroller = $('#fp_thumbScroller');
//слайдер jquery ui
var $slider = $('#slider');
//ссылки на галереи (города)
var $fp_galleries = $('#fp_galleryList > li');
//текущее показываемое изображение
var current = 0;

//флаги управления:
//предотвращаем быстрое нажатие на "следующее" и "предыдущее"
var photo_nav = true;

Мы привязываем событие click к пункту галереи / альбома. Индекс пункта сохраняется для определения, какая галерея открыта в данный момент. Если какая-то другая галерея уже открыта, то мы закрываем ее (плавно сворачивая) прежде чем открыть выбранную.

//пользователь нажал на городе / галерее;
$fp_galleries.bind('click',function(){
	$fp_galleries.removeClass('current');
	var $gallery = $(this);
	$gallery.addClass('current');
	var gallery_index = $gallery.index();
	if(gallery_idx == gallery_index) return;
	gallery_idx = gallery_index;
	//закрыть галерею и слайдер, если они открыты
	if($fp_thumbContainer.data('opened')==true){
		$fp_scrollWrapper.fadeOut();
		$fp_thumbContainer.stop()
				  .animate({'height':'0px'},200,function(){
					openGallery($gallery);
				  });
	}				  
	else
		openGallery($gallery);
});

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

Инициализируется слайдер jQuery UI и устанавливается максимальное положение для прокрутки содержимого контейнера.

Чтобы прокрутить все изображения перед пользователем при открытии галереи, мы прокручиваем содержимое контейнера вправо перед открытием, а после открытия галереи анимируем установку scrollLeft в значение 0px.

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

//открыть галерею после нажатия на город / галерею
function openGallery($gallery){
	//текущая позиция сбрасывается
	current	= 0;				  
	//контейнер div, который содержит изображение
	var $fp_content_wrapper = $fp_thumbContainer.find('.container:nth-child('+parseInt(gallery_idx+1)+')');
	//прячем все остальные контейнеры миниатюр
	$fp_thumbContainer.find('.container').not($fp_content_wrapper).hide();
	//и выводим только один выбранный
	$fp_content_wrapper.show();
	//общее количество изображений
	nmb_images = $fp_content_wrapper.children('div').length;
	//переменные для вычисления ширины,
	//отступа слева
	//и отступа справа 
	var w_width = 0;
	var padding_l = 0;
	var padding_r	= 0;
	//центр экрана
	var center = $(window).width()/2;
	var one_divs_w  = 0;
	/*
	Примечание:
	отступ слева - это положение центра минус половина ширины первого элемента div
	отступ справа - это положение центра минус половина ширины последнего элемента div
	*/
	$fp_content_wrapper.children('div').each(function(i){
		var $div 		= $(this);
		var div_width	= $div.width(); 
		w_width			+=div_width;
		//если это первый элемент, вычисляем отступ слева
		if(i==0)
			padding_l = center - (div_width/2);
		//если это последний элемент, вычисляем отступ справа
		if(i==(nmb_images-1)){
			padding_r = center - (div_width/2);
			one_divs_w = div_width;
		}	
	}).end().css({
			'width' : w_width + 'px',
			'padding-left' : padding_l + 'px',
			'padding-right'	: padding_r + 'px'
	});
					
	//прокручиваем все налево;
	$fp_thumbScroller.scrollLeft(w_width);
					
	//инициализируем слайдер
	$slider.slider('destroy').slider({
		orientation	: 'horizontal',
		max			: w_width -one_divs_w,//общая ширина минус ширина одного элемента div
		min			: 0,
		value		: 0,
		slide		: function(event, ui) {
			$fp_thumbScroller.scrollLeft(ui.value);
		},
		stop: function(event, ui) {
			//когда прокрутка останавливается,
			//ближайшее к центру экрана изображение 
			//центрируется
			checkClosest();
		}
	});
	
	//открываем галерею и показываем слайдер
	$fp_thumbContainer.animate({'height':'240px'},200,function(){
						$(this).data('opened',true);
						$fp_scrollWrapper.fadeIn();
					});
					
	//прокручиваем все направо;
	$fp_thumbScroller.stop()
			 .animate({'scrollLeft':'0px'},2000,'easeInOutExpo');

	//пользователь нажал на элементе div (изображении)
	$fp_content_wrapper.find('.content')
			 .bind('click',function(e){
				var $current 	= $(this);
				//получаем индекс текущего выбранного изображения
				current	= $current.index();
				//центрируем и показываем изображение
				//второй параметр, установленный в значение true, означает,
				//что мы хотим выводить изображение после того, как миниатюра будет отцентрирована на экране
				centerImage($current,true,600);
				e.preventDefault();
	});					
}

Когда прокручивается содержимое контейнера, нужно также прокручивать слайдер:

//при прокрутке галереи нужно также прокручивать слайдер
$fp_thumbScroller.scroll(function(){
	$slider.slider('value',parseInt($fp_thumbScroller.scrollLeft(),10));
});

Код обработчиков события click для кнопок "следующее" и "предыдущее", которые пользователь видит на экране в виде изображений стрелок при просмотре изображения большого размера. Функция navigate вызывается либо с аргументом "1" для переключения на следующее изображение, либо с аргументом "0" для переключения на предыдущее изображение.

//пользователь нажал кнопку "следующее" (режим просмотра)
$fp_next.bind('click',function(){
	if(photo_nav){
		photo_nav = false;
		navigate(1);
	}	
});
				
//пользователь нажал кнопку "предыдущее" (режим просмотра)
$fp_prev.bind('click',function(){
	if(photo_nav){
		photo_nav = false;
		navigate(0);
	}	
});

Кроме прокрутки миниатюр с помощью слайдера, мы также хотим прокручивать по одной картинке с помощью кнопок. Следующий код реализует обработчики события click для кнопок рядом со слайдером, выполняющие данное действие.

//пользователь нажал кнопку "следующее" (режим миниатюр)
$('#fp_next_thumb').click(function(){
	slideThumb(1);
});
				
//пользователь нажал кнопку "предыдущее" (режим миниатюр)
$('#fp_prev_thumb').click(function(){
	slideThumb(0);
});

Функция centerImage используется для прокрутки содержимого контейнера до тех пор, пока соответствующая миниатюра не будет отцентрирована на экране. Если аргумент “open” имеет значение true, то функция centerImage также открывает изображение большого размера, вызывая соответствующую функцию.

//центрируем изображение и открываем его, если нужно
function centerImage($obj,open,speed){
	//смещение элемента слева
	var obj_left = $obj.offset().left;
	//центр элемента - это смещение слева плюс 
	//половина ширины
	var obj_center = obj_left + ($obj.width()/2);
	//центр окна
	var center = $(window).width()/2;
	//насколько полоска прокрутки уже смещена
	var currentScrollLeft 	= parseFloat($fp_thumbScroller.scrollLeft(),10);
	//чтобы отцентрировать изображение,
	//нужно прокрутить расстояние равное положению центра изображения минус положение центра экрана
	//и добавить то расстояние, которое уже прокручено
	var move = currentScrollLeft + (obj_center - center);
	if(move != $fp_thumbScroller.scrollLeft()) //проверка 'easeInOutExpo'
			$fp_thumbScroller.stop()
					 .animate({scrollLeft: move}, speed,function(){
						if(open)
							enlarge($obj);
			});
	else if(open)
			enlarge($obj);
}

Функция enlarge выполняет вывод изображения большого размера, которое соответствует выбранной миниатюре. Мы загружаем соответствующее большое изображение, размещаем его над миниатюрой, а затем анимируем процесс раскрытия до максимально возможного размера, который определяется на основании текущего размера окна. После увеличения изображения мы выводим кнопки "следующее", "предыдущее" и "закрыть".

function enlarge($obj){
	//элемент изображения
	var $thumb = $obj.find('img');
	//выводим индикатор загрузки изображения
	$fp_loading.show();
	//предварительная загрузка изображения
	$('<img id="fp_preview" />').load(function(){
		var $large_img 	= $(this);
				
		//подтверждаем, что нет других больших изображений
		$('#fp_preview').remove();
				
		$large_img.addClass('fp_preview');
		//позиционируем изображение сверху над миниатюрой
		//добавляем данное изображение к div fp_gallery
		var obj_offset 	= $obj.offset();
		$large_img.css({
			'width'	: $thumb.width() + 'px',
			'height': $thumb.height() + 'px',
			'top'	: obj_offset.top + 'px',
			'left'	: obj_offset.left + 5 + 'px'//поле 5 пикселей 
		}).appendTo($fp_gallery);
		//getFinalValues дает нам максимально возможные значения ширины и высоты
		//большого изображения на основании размеров окна
		//данные значения сохраняются для элемента с помощью jQuery.data()
		getFinalValues($large_img);
		var largeW 	= $large_img.data('width');
		var largeH 	= $large_img.data('height');
		//ширина окна, высота окна и прокрутка
		var $window = $(window);
		var windowW = $window.width();
		var windowH = $window.height();
		var windowS = $window.scrollTop();
		//скрываем индикатор загрузки изображения
		$fp_loading.hide();
		//выводим покрывной слой
		$fp_overlay.show();
		//анимируем большое изображение
		$large_img.stop().animate({
			'top'		: windowH/2 -largeH/2 + windowS + 'px',
			'left'		: windowW/2 -largeW/2 + 'px',
			'width'		: largeW + 'px',
			'height'	: largeH + 'px',
			'opacity'	: 1
		},800,function(){
			//после анимации
			//выводим кнопки "следующее", "предыдущее" и "закрыть"
			showPreviewFunctions();
		});
	}).attr('src',$thumb.attr('alt'));
}

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

//пользователь нажал кнопку "закрыть"
$fp_close.bind('click',function(){
	if(!photo_nav) return;
	//прокручиваем окно наверх
	var windowS = $(window).scrollTop();
	//большое изображение, которое было открыто
	var $large_img	= $('#fp_preview');
	//текущая миниатюра
	var $current = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
						   .find('.content:nth-child('+parseInt(current+1)+')');
	//значение смещения текущей миниатюры
	var current_offset	= $current.offset();
	//большое изображение будет сворачиваться с анимацией по направлению к центру,
	//после чего оно будет полностью удалено из структуры DOM
	$large_img.stop().animate({
			'top'			: current_offset.top + windowS + 'px',
			'left'			: $(window).width()/2 - $current.width()/2 + 'px',
			'width'			: $current.width() + 'px',
			'height'		: $current.height() + 'px',
			'opacity'		: 0
		},800,function(){
			$(this).remove();
			//прячем покрывающий слой, и кнопки "предыдущее" и "следующее"
			hidePreviewFunctions();
	});				
});

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

Если мы нажмем на кнопку "следующее" текущее изображение проскользнет за левую сторону окна, а следующее изображение выскользнет из-за правой стороны окна. При нажатии кнопки "предыдущее" логика работы будет такая же, но движение изображений будет выполняться в другую сторону.

function navigate(way){
	//показываем индикатор загрузки изображения
	$fp_loading.show();
	if(way==1){
		++current;
		var $current = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
						.find('.content:nth-child('+parseInt(current+1)+')');
		if($current.length == 0){
			--current;
			$fp_loading.hide();
			photo_nav = true;
			return;
			}
		}
	else{
		--current;
		var $current = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
						.find('.content:nth-child('+parseInt(current+1)+')');
		if($current.length == 0){
			++current;
			$fp_loading.hide();
			photo_nav = true;
			return;
		}
	}
					
	//загружаем большое изображение в следующий/предыдущий элемент div
	$('<img id="fp_preview" />').load(function(){
		$fp_loading.hide();
		var $large_img 		= $(this);
		var $fp_preview 	= $('#fp_preview');
						
		//смещаем текущее изображение влево, если нажата кнопка "следующее"
		//смещаем текущее изображение вправо, если нажата кнопка "предыдущее"
		var animate_to 		= -$fp_preview.width();
		var animate_from	= $(window).width();
		if(way==0){
			animate_to 		= $(window).width();
			animate_from	= -$fp_preview.width();
		}
				
		//теперь центрируем миниатюру 
		centerImage($current,false,1000);
					
		$fp_preview.stop().animate({'left':animate_to+'px'},500,function(){
			$(this).remove();
			$large_img.addClass('fp_preview');
			getFinalValues($large_img);
			var largeW 	= $large_img.data('width');
			var largeH 	= $large_img.data('height');
			var $window	= $(window);
			var windowW = $window.width();
			var windowH = $window.height();
			var windowS = $window.scrollTop();
			$large_img.css({
				'width'	: largeW+'px',
				'height': largeH+'px',
				'top'	: windowH/2 -largeH/2 + windowS + 'px',
				'left'		: animate_from + 'px',
				'opacity' 	: 1	
			}).appendTo($fp_gallery)
			  .stop()
			  .animate({'left':windowW/2 -largeW/2+'px'},500,function(){photo_nav = true;});
		});
	}).attr('src',$current.find('img').attr('alt'));	
}

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

function getFinalValues($image){
	var widthMargin		= 0
	var heightMargin 	= 20;
	var $window			= $(window);
	var windowH      	= $window.height()-heightMargin;
	var windowW      	= $window.width()-widthMargin;
	var theImage     = new Image();
	theImage.src     = $image.attr("src");
	var imgwidth     = theImage.width;
	var imgheight    = theImage.height;

	if((imgwidth > windowW)||(imgheight > windowH)){
		if(imgwidth > imgheight){
			var newwidth = windowW;
			var ratio = imgwidth / windowW;
			var newheight = imgheight / ratio;
			theImage.height = newheight;
			theImage.width= newwidth;
			if(newheight>windowH){
				var newnewheight = windowH;
				var newratio = newheight/windowH;
				var newnewwidth =newwidth/newratio;
				theImage.width = newnewwidth;
				theImage.height= newnewheight;
			}
		}
		else{
			var newheight = windowH;
			var ratio = imgheight / windowH;
			var newwidth = imgwidth / ratio;
			theImage.height = newheight;
			theImage.width= newwidth;
			if(newwidth>windowW){
				var newnewwidth = windowW;
				var newratio = newwidth/windowW;
				var newnewheight =newheight/newratio;
				theImage.height = newnewheight;
				theImage.width= newnewwidth;
			}
		}
	}
	$image.data('width',theImage.width);
	$image.data('height',theImage.height);
}

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

//когда закончено смещение,
//ближайшее изображение к центру должно быть отцентрировано
function checkClosest(){
	var center = $(window).width()/2;
	var current_distance 	= 99999999;
	var idx	= 0;	
	$container = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')');
	$container.find('.content').each(function(i){
		var $obj = $(this);
		//смещение элемента слева
		var obj_left = $obj.offset().left;
		//положение центра элемента - это смещение слева плюс половина его ширины
		var obj_center 	= obj_left + ($obj.width()/2);
		var distance	= Math.abs(center-obj_center);
		if(distance < current_distance){
			current_distance 	= distance;
			idx					= i;
		}	
	});
	var $new_current 	= $container.find('.content:nth-child('+parseInt(idx+1)+')');
	current = $new_current.index();
	centerImage($new_current,false,200);
}

Функция slideThumb используется, когда мы хотим передвинуть миниатюры на одно изображение. Она вызывает функцию centerImage для следующего или предыдущего элемента в галерее.

//смещаем полоску прокрутки 
//вправо или влево на одно изображение
function slideThumb(way){
	if(way==1){
		++current;
		var $next = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
  					     .find('.content:nth-child('+parseInt(current+1)+')');
		if($next.length > 0)
			centerImage($next,false,600);
		else{
			--current;
			return;
		}	
	}
	else{
		--current;
		var $prev = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
					     .find('.content:nth-child('+parseInt(current+1)+')');
		if($prev.length > 0)
			centerImage($prev,false,600);
		else{
			++current;
			return;
		}	
	}					
}

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

//выводим кнопки "следующее", "предыдущее" и "закрыть"
function showPreviewFunctions(){
	$fp_next.stop().animate({'right':'0px'},500);
	$fp_prev.stop().animate({'left':'0px'},500);
	$fp_close.show();
}
				
//скрываем покрывной слой, и кнопки "следующее", "предыдущее" и "закрыть"
function hidePreviewFunctions(){
	$fp_next.stop().animate({'right':'-50px'},500);
	$fp_prev.stop().animate({'left':'-50px'},500);
	$fp_close.hide();
	$fp_overlay.hide();
}

Для использования интересный шрифтов мы используем Cufon. Следующий код подключает  использование  выбранного шрифта в заголовках h1 и h2, параграфах и элементах с id fp_close и reference. Используется шрифт Opium.

<script src="js/cufon-yui.js" type="text/javascript"></script>
<script src="js/Opium_400.font.js" type="text/javascript"></script>
<script type="text/javascript">
	Cufon.replace('h1,h2,.fp_close,.reference,p');
</script>

Готово!

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://tympanus.net/codrops/2010/10/07/slider-gallery/
Перевел: Сергей Фастунов
Урок создан: 29 Октября 2010
Просмотров: 81244
Правила перепечатки


5 последних уроков рубрики "jQuery"

или авторизуйтесь, чтобы добавлять комментарии, оценивать уроки и сохранять их в личном кабинете
  • 29 Октября 2010 18:11
    SergStril
    Отлично! Обязательно использую её когда-нибудь.
  • 29 Октября 2010 18:17
    НеБот
    Громоздко...
  • 29 Октября 2010 18:18
    Валера
    Я думал фотографии городов, а там бабы какие то) подвисает у меня, видюха слабая, а так вполне эстетично.
  • 29 Октября 2010 21:43
    Мохьмад
    Отлично!!!
  • 29 Октября 2010 23:29
    ChiviK
    В ИЕ не работает... А так прикольно!
  • 30 Октября 2010 03:03
    Expert
    хотеел себе подобную (IMAGEFLOW ), но висит сильно.... у вас кстати тоже
  • 10 Ноября 2010 15:27
    byels
    Уважаемый автор сея уроков и пользователи сея сайта :-) А может кто подскажет: как подцепить описание под увеличенную фотографию? Есть соображения на этот повод? Например создать div контейнер к каждой фотке?
  • 12 Декабря 2010 22:19
    vitalez
    Огромное спасибо за такой разбор по полочкам данной галлереи. Возник вопрос, при изминении длины курсора, он почему то начинает уползать за размеры линии. Я загрузил демо пример на свой сайт, на словах не совсем понятно, что я имею в виду. Вот ссылка http://business-mania.com/demo/ Буду очень признателен за дельный совет.
  • 27 Декабря 2010 16:43
    banshi
    Громадина, но красиво :)
  • 26 Февраля 2011 19:57
    horser
    Спасибо за галерею! У меня вопрос, как можно к каждому разделу галлереи создать уникальный адрес в адресной строке? и возможно ли это?
  • 24 Апреля 2011 00:09
    ease
    Все отлично, а вот как бы контент выводить дополнительный с внешнего файла для каждой картинки было бы вообще прекрасно...
  • 2 Июля 2011 22:11
    maxgrin
    Подскажите пожалуйста как можно сделать так,чтобы при загрузке страницы фотографии в галереии грузились не сразу,а только тогда, когда начинаешь просматривать галерею!?
  • 10 Августа 2011 00:06
    Kajidal
    Спасибо за урок, подскажите пожалуйста как сделать так чтобы при загрузки галерее одна из галерей была сразу активной, т.е чтобы не надо было нажимать по галереи для открытия лишний раз... пример http://s50.radikal.ru/i128/1108/55/ae8063ef088c.jpg такая страница нужна чтоб была при загрузке. Надеюсь я объяснил правильно.
    • 25 Ноября 2011 15:25
      dperisty
      сам ищу сейчас решение. пока по нулям (
  • 29 Ноября 2011 16:14
    antiquary
    Обалденная вещь!!! Спасибо, утащил к себе на будущий сайт. Прекрасно работает во всех браузерах. Скажите, пожалуйста, кто-нибудь знает способ, как заставить большие фотографии меняться по кругу - чтобы за последней шла снова первая и наоборот, если в обратную сторону?
  • 15 Января 2012 20:59
    Vokins_1951
    Подскажите пожалуйста, как сделать, чтобы галерея открывалась сразу после попадания на страницу, без нажатия на альбом?
  • 28 Февраля 2012 00:04
    temp2012
    Сделал 4 альбома, но получается, что когда в альбоме больше 10 фоток, то открывается на одну меньше . Например, вместо 11 - 10, а вместо 17 - 16 . Где ошибка в скрипте, не могу понять.
  • 28 Мая 2012 15:19
    krasdok1
    Здравствуйте!!! Как под большим фото разместить краткое описание что на фото???
  • 2 Декабря 2013 13:35
    groshew1
    Спасибо! Очень удачно получилось. Вставила текст. Вот черновой вариант:http://declin.ru/oksana/ Обязательно укажу на RUSELLER
  • 7 Февраля 2015 23:17
    gala_78
    Нужна помощь, после установки галереи перестали работать ссылки на другие страницы сайта. Помогите справиться с проблемой.
^ Наверх ^