Слайд-шоу на галерее Greybox.

Для своих нужд понадобилось сделать фотогалерею.

Казалось бы, что еще проще? Возьми готовое и вперед.

Пересмотрел большое количество галерей, и в каждой мне что-то не нравилось. То привязка к jquery или к другому фреймворку, то размер, то не совсем понятная навигация. А хотелось, что-то такого своего, маленького, понятного.

Так нашелся jsimagebox. Казалось, что еще надо? Я ее даже применил описывая прогулку по прекраснейшим местам Харьковщины.

После решения этой проблемы поиски прекратились. Но что-то в ней мне тогда не понравилось. Скорей всего, прописывание onclick на изображении. И мне тогда не удалось заставить его корректно динамически подгружать изображения.

А тут появился в переработку сайт с установленным lightbox'ом. Я когда глянул в код, ужаснулся и мне быстро-быстро захотелось с него спрыгнуть. Lightbox не понравился только мне, и это не значит, что он не понравится кому-то еще.

Пересмотрев опять определенное количество галерей выбор пал на GreyBox.

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

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

Наконец-то подошли к телу делу.

Подготовительные работы.

Первым делом сделал кнопку Play, переделал кнопки Prev и Next, потом, чуть позже, когда все уже запустилось, сделал кнопку Stop.

Изменения в скрипте и этапы написания функционала

В скрипте gb_scripts.js описан объект GB_Sets, который и отвечает за навигацию при просмотре. С этим объектом я и буду работать.


GB_Sets=GB_Gallery.extend({
	init:function(_3c,set){
		this.parent(_3c);
		if(!this.img_next){	this.img_next=this.root_dir+"next_new.gif"; }
		if(!this.img_prev){ this.img_prev=this.root_dir+"prev_new.gif"; }
//Добавленно для слайд-шоу
		if(!this.img_play){ this.img_play=this.root_dir+"play_new.gif"; }
		if(!this.img_stop){ this.img_stop=this.root_dir+"stop_new.gif"; }
		this.play=false;
		this.pause=5000; //время задержки
/**********************/
		this.current_set=set;
	},
	showSet:function(_3e){
		this.current_index=_3e;
		var _3f=this.current_set[this.current_index];
		this.show(_3f.url);
		this._setCaption(_3f.caption);
		this.btn_prev=AJS.IMG({"class":"lefti",src:this.img_prev,title:"Предыдущая",alt:""});
		this.btn_next=AJS.IMG({"class":"righti",src:this.img_next,title:"Следующая",alt:""});
//Добавленно для слайд-шоу - Создаем кнопку Play
		this.btn_play=AJS.IMG({"class":"righti",src:this.img_play,title:"Запустить слайд-шоу",alt:""});
/**********************/
		AJS.AEV(this.btn_prev,"click",AJS.$b(this.switchPrev,this));
		AJS.AEV(this.btn_next,"click",AJS.$b(this.switchNext,this));
//Добавленно для слайд-шоу - Привязка события onClick к кнопке Play
		AJS.AEV(this.btn_play,"click",AJS.$b(this.switchPlay,this));
/**********************/

		GB_STATUS=AJS.SPAN({"class":"GB_navStatus"});
		AJS.ACN(AJS.$("GB_middle"),this.btn_prev,GB_STATUS,this.btn_next,this.btn_play);
/*************************************************************вот здесь добавляем ее в контейнер ***/
		this.updateStatus();
	}

Замечательно, init сделан, Кнопка Play показывается.

Чтобы проверить, срабатывает ли событие, пишу тест-заглушку, которую потом продолжу работающим кодом


	switchPlay:function(){
	        alert("Play");
	}

Теперь бы проверить хождение по кругу


	switchPlay:function(){
			if(this.current_index < this.current_set.length-1){
						this.current_index++;
					} else {
						this.current_index=0;
					}
					this.updateFrame();
					this.updateStatus();
	}

Итак, все вроде готово к запуску, нужно прикрутить таймер.

В арсенале javascript существует метод setTimeout, который выполняет код(или функцию), указанный в первом аргументе, асинхронно, с задержкой в delay миллисекунд.
Какой код выполнять?
А здесь сейчас его и опишу, впрочем, он уже описан в предыдущем коде.
Но лучше сделать для него отдельный метод playPlay.


	playPlay:function(){
		if(this.current_index < this.current_set.length-1){
			this.current_index++;
		} else {
			this.current_index=0;
		}
		this.updateFrame();
		this.updateStatus();
	}

Внимание! следующий код ошибочный. Так делать нельзя!


	switchPlay:function(){
		if (this.play ==false) {
			this.play = true;
			this.btn_play.src=this.img_stop;
			this.btn_play.title="Остановить слайд-шоу";
			this.timer=setTimeout(function () {this.playPlay()}  ,this.pause);
/**************************************        ТАК ДЕЛАТЬ НЕЛЬЗЯ ***************/
		} else {
			this.play = false;
			clearTimeout(this.timer);
			this.btn_play.src=this.img_play;
			this.btn_play.title="Запустить слайд-шоу";
		}
	}

Но это мой первый опыт работы с таймером и объектами, мне можно, потому и сделал. Ничего страшного не произошло, через 5 сек скрипт останавливался из-за ошибки. Я уже себя корил, мол взялся за неизвестное, не зная броду... Да не знал, но опыт есть. Ведь я привязываю локальный метод к глобальному пространству... Так ведь нужно передавать объект с методом. И быстро-быстро все исправляю


	switchPlay:function(){
		if (this.play ==false) {
			this.play = true;
			this.btn_play.src=this.img_stop;
			this.btn_play.title="Остановить слайд-шоу";
/*********** Вот как надо. ********/
			var tGB_Sets=this;
			this.timer=setTimeout(function () {tGB_Sets.playPlay()},this.pause);
/***************************************          Вот ОНО       *****************/
		} else {
			this.play = false;
			clearTimeout(this.timer);
			this.btn_play.src=this.img_play;
			this.btn_play.title="Запустить слайд-шоу";
		}
	}

Но тут, опять неприятность. Происходит смена только одной картинки. Понятное дело - setTimeout устанавливает интервал для одиночного выполнения функции. Поэтому ... Вот как выглядит готовый код


	playPlay:function(){
		if(this.current_index < this.current_set.length-1){
			this.current_index++;
		} else {
			this.current_index=0;
		}
		this.updateFrame();
		this.updateStatus();
		var tGB_Sets=this;
		this.timer=setTimeout(function () {tGB_Sets.playPlay()},this.pause);
	}

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

Реализация не заставила себя долго ждать


	preloadNext: function(){
		if(this.current_index < this.current_set.length-1){
			next_index = this.current_index+1;
		} else {
			next_index = 0;
		}
		if(!this.current_set[next_index].pre) {
			var pre=new Image(); 
			pre.src=this.current_set[next_index].url;
			this.current_set[next_index].pre = 1;
		}
	}

Таким образом, метод PlayPlay примет следующий вид


	playPlay:function(){
		if(this.current_index < this.current_set.length-1){
			this.current_index++;
		} else {
			this.current_index=0;
		}
		this.updateFrame();
		this.updateStatus();
		this.preloadNext();
		var tGB_Sets=this;
		this.timer=setTimeout(function () {tGB_Sets.playPlay()},this.pause);
	}

Этот метод можно также использовать и в методе switchNext. Кстати, отладку по предзагрузке я на нем и проводил

Работа скрипта проверена в ИЕ8, Opere10, Crome 6, FF 3.6.10, и по секрету скажу - в ИЕ6.