Слайд-шоу на галерее 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.