В целях борьбы с прокрастинацией и повышения js-скиллов, я написал скриптик, которые умеет гененрировать вот такие мозаики из фоток:
Linux Nix Web Development - http://linuxoids.org/ mosaicPhoto

Ещё он умеет обновлять (или не обновлять) мозаику автоматически через определенное время либо при изменении размера экрана. Посмотреть можно вот тут.

Хочу послушать критику местных js-гуру: что я села коряво, что ещё можно добавить?

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

12 Responses to скрипт, который умеет гененрировать вот такие мозаики из фоток

  1. SpoSm:

    Интересненько, но
    1. Засрал к херам всю глобальную область переменными. Если в скоупе создаешь переменную то либо пиши их через запятую, либо перед каждую объявляй через var, либо пиши на coffeescript`е (нынче это модно).
    2. Собирай массив элементов и только потом вставляй их в dom. Одна из самых дорогих операций это работа с Dom`ом. То есть собираешь их в массив через pushStack, а лучше даже в заведомо определённый div в памяти и уже его вставляешь в Dom.
    3. Нужно таймаут на ресайз наверное, хотя бы 150мс. Скрыл, запустил таймер если ресайз опять выстрелил обновил таймер и только потом если таймер успел пробежать тогда вставляешь в Dom элементы.

  2. SpoSm:

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

    var elems = photos.appendTo(containter);
    elems.fadeIn();

    appendTo вернёт тебе обратно ссылки на твои картинки(вернее на втавленный объект) и не надо будет их опять искать в dom`е, а просто на ссылках объектов вызвать метод анимации. Чище и «красивше», но это уже ближе к логике jQuery 🙂

  3. Aynsuper:

    0. Плохо организован код, все практически одним куском, без разделения на свойства и методы.
    1. Непонятно называешь некоторые переменные, типа o и _IMG. Некоторые названы неконсистентно, например topMargin и leftMargin а внутри достаем padding-top и padding-left (кстати replace(‘px’, ») делать в parseFloat не нужно).
    2. Дефолтные значения опций принято в jquery плагинах делать через свойство defaults у объекта с осонвным функционалом плагина, чтобы пользователь смог переопределять эти значения налету без влезания в код самого плагина. Еще, class — это зарезервированное слово в ES5, поэтому лучше не использовать его в качестве названия свойства, или же заключать в кавычки.
    3. Обработчики лучше вешать через delegate на контейнере. И заводить для всех обработчиков плагина свой неймспейс (для resize есть, а для клика почему-то нет). Обрывать дефолтное действие через return false довольно плохо, потому что в таком случае кроме preventDefault делается еще и stopPropagation, если весь интерфейс построен на делегировании событий, то до некоторых элементов всплытие в таком случае не дойдет.
    4. Обязательно нужен деструктор, который удалит все следы действия плагина с элемента а также обработчики с window.resize.
    5. Обязательно нужен метод, который позволял бы менять свойства плагина после применения его к элементу/элементам. Типа $(…).mosaicPhoto.setOptions({ … }).
    6. Самое основное — никогда не делай так, как у тебя сейчас сделана генерация ссылок и картинок и их вставка в ДОМ. Нужно сначала нагенечить весь html строкой (или навставлять в documentFragment) а потом только вне цикла его вставить один раз в ДОМ.
    7. Про глобальные переменные не забываем, да.
    8. Не забываем фильтровать собственные свойства объекта через hasOwnProperty при проходе по нему через for in. И почему, собственно, images — массив, а не объект, если ты его используешь как объект (images = []; images[«weedings»] = […])?
    9. var imgCount = (_IMG > images[imgType].length)? images[imgType].length : _IMG; Это надо через Math.min: var imgCount = Math.min(_IMG, images[imgType].length);

  4. 1yref:

    : Спасибо за столь обширную критику. Буду исправлять.

  5. 1yref:

    почистил код, сделал удобнее формат объекта с картинками и ссылками. Но вот никак не могу понять, как сделать setOptions и деструктор.
    Такое ощущение, что я не улавливаю какую-то простую концепцию. Прочитал уже кучу мануалов, но они все либо «Плагин jQuery для чайников» (там ничего нет про деструкторы), либо сразу для тех, кто каждый день пишет по 5-10 плагинов.

  6. SpoSm:

    Тут есть 2 варианта. У jQuery Ui есть довольно удобная фабрика под названием widget, там ты всё из коробки получишь. Второй вариант, сэмулировать данное поведение. То есть:

    var gallery = $(«#div»).plugin();

    В котором есть метод дестрой (gellery.destroy()), задачи которого:
    1. Убрать все евенты.
    2. Почистить за собой дом.
    3. delete this; (Удалить себя из памяти).
    Если есть что-то еще например создание объектов или другие хитрости, то тоже за собой их почиститить.

    Про setOption точно так же это всего лишь еще один метод, но если ты будешь писать это то тебе нужно сделать функцию конструктор что бы каждый раз при вызове plugin он тебе возвращал новый экземпляр объекта (что бы чистить только его, а не все плагины сразу).
    То есть в твоём случае это будет что-то вроде:

    (function($){
    //Коструктор
    var Plugin = function(el){
    //methods, properties
    }

    //Заносим новый метод в область fn
    $.extend( $.fn, {
    plugin: function(){
    var el = $(this)
    el.each(function(){
    //Связываем элемент с DoM ом, не забываем удалять эту связь в деструкторе.
    $(this).data(«plugin», new Plugin(this));
    });
    // Возвращаем обратно элементы что бы не разбивать «chain pattern».
    return el;
    }
    });
    })(jQuery)

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

  7. 1yref:

    да, про JqueryUI и их виджеты я читал, но мне кажется, что к этому скрипту незачем догружать UI, постараюсь вторым способом сделать.

  8. SpoSm:

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

  9. Aynsuper:

    Да, как верно заметил это вопрос организации кода. Сейчас у тебя плохо сделано, потому что ты все в each запихнул и у тебя нет вообще разделения на объекты => ты не можешь связать дом-элемент с объектом со свойствами, которые к нему относятся. Тебе нужно вне $.fn и each вынести всю функциональность в отдельный объект, а потом инициализировать его в each для каждого элемента и сохранять ссылку в data у элемента. А дальше собственно дело техники.

  10. 1yref:

    Я вроде бы сделал это. Уф!

  11. Aynsuper:

    Ну да, уже норм, только unbind в _windowResize неправильный, нужно анбиндить не все обработчики resize с неймспейсом, а только те, которые были навешаны именно этим объектом. И публичные методы (setOptions, getOptions, destroy, …) нужно вынести в прототип mosaicPhoto (чтобы они каждый раз при инициализации не создавались, про память думаем). Кстати, функцию-конструктор принято с большой буквы называть.

  12. Aynsuper:

    Хотя, можно и не выносить (а то придется дохрена всего сделать публичным). Сам решай, но я обычно просто ограничиваюсь подчеркиванием в названии метода, чтобы обозначить, что он приватный. Насчет сохранения принципов тру-инкапсуляции в JS не особо парюсь.

Добавить комментарий