Открыть изображение »
Внутренняя сторона таймлайна
04 ноября 2012 :: 10 комментариев :: 4869 просмотров :: 1210 слов

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

Загорелся идеей сделать timeline я практически сразу, как только увидел его в бета-тестировании на facebook. Не знаю почему, но мне показалось это очень крутой идеей, даже несмотря на звучащие где-то негодования а-ля «дуров верни стену». Надо ли говорить, что в начале года (а если посмотреть на пост, он датирован 3-м января), не было даже упоминаний о таймлайне с технической точки зрения, не говоря уже о каких-то библиотеках или готовых решениях. Гуглить что-то было бесполезно, ничего кроме новостных сайтов и старых представлений о таймлайне (помните сервис plurk в самом начале своей карьеры?) тогда не находилось. Это я как бы так ненавязчиво подвожу, что «не мы такие, жизнь такая» и в начале 2012-го нельзя было просто взять и сделать все правильно.

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

Не очень хорошо, как мне кажется. Начал думать.

Небольшое лирическое отступление. Так как уже конец 2012 и таймлайны стали популярны, вы можете встретить множество попыток реализации такого таймлайна. Особенно популярен перевод вот этой статьи (даже на хабре был), где автор использует библиотеку jQuery Masonry, против которой я ничего не имею и даже использовал ее у себя в галерее, однако я не считаю ее использование тут подходящим. Не считая того, что это тотальный оверкилл (masonry кроме своей гибкости еще и очень прожорлива, и как и любая jQuery-библиотека на 100500 блоков обязательно начнет тормозить), она относится к хронологии блоков просто по-хамски, еще более хамски, чем приведенное здесь решение. Больше адекватных реализаций я не нашел. Так что продолжим свой рассказ.

Когда я рассуждаю над такими решениями, я сначала думаю как бы сделали Интересные и Разносторонние Парни (с), гордящиеся своим видеорегистратором и офисом, потому что у них два монитора и Командный Дух (с), повышающий способности к программированию, ведь как известно если одна женщина рожает ребенка за 9 месяцев, то сплоченная мотивированная команда из трех женщин-профессионалов делает это всего за 3. В таким моменты я представляю, что в одной руке у меня любимый видеорегистратор, а в другой Преданность Своему Делу (с) и начинаю думать: наверное, нужно использовать серверную компоновку шаблонов, нужно как-то узнавать размеры каждого блока до того, как определяется его размещение и в зависимости от этого и весовых коэффициентов определять где его выводить. Написать для каждого типа блока (сейчас их 9) формулу расчета его высоты, в зависимости от содержимого и среднего размера шрифта в этом блоке, а если еще он содержит несколько сообщений, то нужно учитывать их количество и количество прикрепленных изображений к ним, плюс учитывать растянутые на 100% блоки (пока таких нет) чтобы обнулять коэффициенты... СТОП, БЛЯДЬ.

Оставим ка мы это решение Разносторонним Парням, у них есть оклад и куча времени в офисе, чтобы заниматься такими извращениями хоть целый день. Я же — сидящий дома зазнавшийся долбоеб с завышенной самооценкой (или как там говорили), и мне нужно такое решение, чтобы работало здесь, сейчас и на моем конкретном случае.

Решение пришло мне когда я вешал часы в туалете, упал и ударился головой о раковину. Затем я взял и нарисовал вот это:

Ой, в смысле вот это:

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

Идея состоит в следующем: изначально расстановка блоков делается при компиляции шаблона по принципу слева-справа (float: left, float: right). Браузер расставляет эти блоки правильно до тех пор, пока ему не встретится последовательность «плохих» блоков, после чего он начинает косячить и делать всё наоборот. Вот здесь и вступает в дело javascript, который смотрит, если физическое положение блока и его класс не совпадают (блок с классом .left оказался справа и наоборот) он просто берет и... меняет класс на противоположный (строки 16 и 22). Тонким моментом здесь является то, что после такой манипуляции нужно так же сменить на противоположные классы всех блоков после этого (строки 5-12). Вторым тонким моментом являет то, что если следующий блок расположен так же «плохо», то нужно сменить его класс, но продолжать менять классы после него уже не нужно. В общем для этого есть бинарный флаг swap_next_position, которому присваивается отрицание самого себя (строки 17 и 23) в случае, если мы меняем класс блока. Ну и в конце нужно отобразить все это безобразие со стрелочками. Вот тут мы подходим к третьему тонкому моменту, который не заметно в общем месиве блоков, но если выровнять два блока, то можно заметить, что стрелочка правого ВСЕГДА ниже стрелочки левого. Так достигается то, что они выглядят как будто идут друг за другом.

Пара моментов, которые хотелось бы упомянуть:

1) Чтобы пользователь с очень медленным интернетом при загрузке страницы ничего этого не видел, можно чем-то это добро скрыть до полного рендеринга.

2) Решение без проблем поддерживает блоки на 100% ширины.

3) Половины таймлайна не одинаковые по ширине. Заметил я это лишь через пол года успешного использования.

4) Для вертикальной линии я использовал картинку 1х1 пиксель установленную по центру бекграундом с repeat-y. Если вы Интересный Парень, вы обязательно должны использовать блок, руками ресайзить его и ловить тучу багов. Для стрелочек я использовал картинки, видимо по старой привычке, сейчас я бы сделал их на чистом CSS.

5) Всё немного ломается, если таймлайн умеет ресайзиться. Нужно отлавливать onresize и как-нибудь с задержкой корректировать блоки заново.

7) Решение поддерживает ajax-подгрузку блоков (например бесконечный скроллинг), если не забыть после загрузки снова вызвать волшебную функцию.

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

9) Остерегайтесь использования анимаций, например появления блоков, даже последний chrome стал биться в конвульсиях при попытке сделать .fadeIn() для 1000 элементов.

10) Я не упомянул про серверную реализацию, хотя там тоже есть над чем подумать. Если коротко, то в текущей реализации таймлайн хранится в одной таблице, а не собирается из нескольких как было раньше. Плюс не забывайте про кеширование, ведь таймлайн — очень прожорливая штука, кеш и правильная его инвалидация в моем случае дали ускорение чуть ли не в 100 раз.

11) Да, система лажает в некоторых очень крайних и очень редких случаях в том, что путает хронологическое расположение соседних блоков. Но разве хоть кто-то из вас это замечал? :D Если вы разрабатываете более важные и требовательные к правильной хронологии системы, см. пункт 12.

12) Я долбоеб и ничего не понимаю в %что_угодно%, вам мой вариант не подходит, у вас не тот случай и намного более сложная система. Вы зря прочитали всё это, и вам всё же придется попробовать активировать собственную мозговую активность.

13) В списке пропущен 6 пункт и никто этого не заметил.

P.S.: Если кто-то кинет ссылку на настоящую правильную реализацию таймлайна от больших дядек, я буду благодарен. Поделки подобные моей или на masonry не интересуют. Улучшения так же принимаются. Просьбы оформить как библиотеку буду засчитываться и обдумываться, если вообще будут.

Еще? Тогда вот
Комментарии
0
Ник слиш ⸬ 04 ноября 2012, 13:58 ⸬ Novosibirsk, RU ⸬ Windows лог
#
Ну, я, как обычно, премного благодарствую :D
0
Xeon ⸬ 04 ноября 2012, 14:16 ⸬ Tuymazy, RU ⸬ Apple лог
#
Писалось под пивом? Здорово. Спасибо за дока, надо пересмотреть.
0
themylogin ⸬ 04 ноября 2012, 14:26 ⸬ Novosibirsk, RU ⸬ Apple лог
#
Я всё замечал :3
0
vas3k ⸬ 04 ноября 2012, 14:28 ⸬ Novosibirsk, RU ⸬ Apple лог
#
themylogin, ты всегда все замечаешь, так что читай "никто, кроме themylogin" :D
Xeon, неа, совершенно трезв. Но выпил бы.
0
The Master ⸬ 04 ноября 2012, 18:14 ⸬ Pushkin, RU ⸬ Apple лог
#
Про падение со стула и удар головой об раковину точно пиздёж, инфа сотка! Атвечаю!
0
vas3k ⸬ 04 ноября 2012, 19:51 ⸬ Novosibirsk, RU ⸬ Apple лог
#
The Master, конечно пиздежь. Падение было с унитаза.
(Сколько макоебов подряд в моем уютненьком)
0
Hanggard ⸬ 05 ноября 2012, 02:32 ⸬ Novosibirsk, RU ⸬ Windows лог
#
ладно, испорчу картинку макоебов каментом, не несущин смысловой нагрузки :)
0
_ ⸬ 06 ноября 2012, 06:29 ⸬ Novosibirsk, RU ⸬ Windows лог
#
> сидящий дома зазнавшийся долбоеб с завышенной самооценкой
Мммм.
0
backdor ⸬ 06 ноября 2012, 23:35 ⸬ Novosibirsk, RU ⸬ Apple лог
#
а я макоеб и мимо проходил. привет.
0
werehuman ⸬ 07 ноября 2012, 03:04 ⸬ Novosibirsk, RU ⸬ Linux лог
#
> Остерегайтесь использования анимаций, например появления блоков, даже последний chrome стал биться в конвульсиях при попытке сделать .fadeIn() для 1000 элементов.
Можно попробовать запускать их не все одновременно, а для каждого следующего блока - с задержкой в 250 мс относительно предыдущего.
(не заполняйте это поле)

me@vas3k.ru :: telegram :: twitter :: instagram :: facebook :: github