Превращаем Хабр в «пятнашки» с помощью Canvas



Добрый день, уважаемые посетители Хабра.

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

Что это?



Как уже видно из заголовка, это игра «пятнашки». Особенностью данной игры является то, что она использует текущее видимое изображение страницы. При разработке была использована библиотека html2canvas Николаса фон Херцена (Niklas von Hertzen), которая позволяет делать скриншот в браузере на стороне пользователя, а результат размещать в canvas. Именно это изображение (или его часть) и будет источником для игрового поля «пятнашек».



Зачем это?



Как говорится, just for fun. Просто в связи с переделкой на одном из своих сайтов, мне захотелось встроить в сайт какое-нибудь пасхальное яйцо. Изначально идея была в том, чтобы сайт «осыпался» с экрана после определенного времени или клика в каком-нибудь особенном месте. Но потом мне подумалось, что интерактивность, требующая действий пользователя, будет несколько интереснее. Выбор пал на пятнашки.

Как это работает?



Как уже было сказано, игра использует библиотеку html2canvas для создания скриншотов в браузере пользователя. Библиотека написана на чистом JavaScript, но имеет в своем составе jQuery-плагин, который я и использовал.

Базовое использование библиотеки предельно простое:

$(element).html2canvas({
onrendered: function(canvas) {
// ... ваш код
}
});


В качестве параметра в коллбек-функцию передается только что созданный canvas.

Созданный мной скрипт по сути является плагином для jQuery. Вызвать его очень просто:

$('body').puzzle15({
tileCount: 4
});


При этом в качестве селектора может быть не только body, но и практически любой элемент. Однако, работа с чем-то, отличным от body практически не была протестирована. Буду рад баг-репортам и конструктивной критике. На всякий случай уточню, что берется только первый элемент набора, поэтому пятнашки на экране будут только одни, несмотря на селектор. При этом для генерации игрового поля используется вся видимая поверхность элемента, какой бы большой (или маленькой) она не была. Для того, чтобы не проглядывал оригинальный элемент, используется дополнительный див-подложка.
Если вы используете body для игры, то в отличие от описанного выше, для игрового поля будет использоваться только видимая на экране часть. А для того, чтобы пользователь не мог укрутить выше или ниже, отключается прокрутка и выставляется фиксированное положение для игрового поля. Однако какая-либо обработка изменения размеров окна отсутствует. Способ отключения прокрутки я подсмотрел вот здесь.

Описывать, как устроены «пятнашки», особого смысла не вижу, так как уже было на Хабре, да и к тематике слабо относится. Ну и в целом, код достаточно простой, содержит небольшие комментарии, поэтому с пониманием проблем возникнуть не должно. Тем не менее, готов ответить на вопросы и поучаствовать в конструктивных дискуссиях.

Хочу уже поиграть. Куда нажимать?



Чтобы установить эту игру, надо зайти сюда и перенести ссылку html2canvas + puzzle 15 в панель закладок. После того, как вы её перенесли, открывайте любой сайт (например, habrahabr.ru) и вызовите bookmarklet. В появившемся окне нужно будет ввести размерность поля.
Сразу хочу предупредить пользователей Opera: на длинных страницах Опера жутко тормозит во время снятия скриншота, но потом все же работает корректно. Я протестировал в FF, Chrome, Safari, IE9 и Opera, но только в последней возникла такая проблема. Думаю, если бы библиотека умела снимать только частичные скриншоты, то зависаний можно было бы избежать. В общем, если что я вас предупреждал.

Где скачать исходники?



Полный архив, включая bookmarklet, можно скачать по этой ссылке.
Исходники библиотеки html2canvas можно скачать на github.

upd: Обратил внимание, что скрипт не работает на яндексе. Во избежание проблем с этим и другими сайтами, я отключил в скрипте проксирование картинок, не подходящих под политику same origin. Дело в том, что проксирование по умолчанию обрабатывается на стороне разработчика html2canvas, и скрипт там иногда падает.
upd2: На некоторых слишком длинных страницах может быть ошибка NS_ERROR_OUT_OF_MEMORY: Component returned failure code: 0x8007000e (NS_ERROR_OUT_OF_MEMORY) [nsIDOMHTMLCanvasElement.height]. Увы, поскольку нет возможности ограничить область в body, то ошибки избежать не удастся.

Комментарии 10

    0
    Прикольная штука. Спасибо!

    >it does not make an actual screenshot, but builds the screenshot based on the information available on the page
    Ах вот оно как. Пока не прочитал, думал что поверх страницы кладется какой-нибудь хитрый прозрачный canvas, а потом из него считывается картинка. Жаль что так нельзя. Было бы не плохо иметь стандартный механизм рендеринга страницы в canvas (для всяких эффектов).
      +1
      Да, я не отметил это в статье. Спасибо за замечание. Кстати, именно по этой причине возникают отличия между «скриншотом» и оригиналом (в частности это касается градиентов и скругленных углов).
        0
        Было бы не плохо иметь стандартный механизм рендеринга страницы в canvas (для всяких эффектов).

        Есть такой метод, drawWindow, кажется. Используется именно, чтобы снимать скрины. Но его можно юзать только в расширениях и плагинах. Я думаю, что его используют, чтобы сделать миниизображение во всяких аналогах Speed Dial.
        0
        Нашел баг: при нажатии на кнопку «Отмена» всё равно создаются паззлы
          0
          Спасибо. Исправил.
          +1
          Может сделать новую капчу в виде пятнашек?..
            0
            Не всегда попадаются собираемые комбинации.
              0
              Да вы правы. Плагин не учитывает этот момент. По-хорошему надо было, наверное, проверку на собираемость сделать. С другой стороны у настоящих пятнашек из реальной жизни от такой ситуации тоже никто не застрахован.
                0
                проще генерацию сделать ситуации из начальной путем n случайных движений)
                  0
                  Согласен. Исправил на генерацию случайных ходов. Сейчас должно быть лучше )

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое