Pull to refresh

Как мы сжимали шарики

Reading time 4 min
Views 1.4K
Вчера ночью мы выложили шарик, помогающий принимать решения, для участия в 10К Apart — конкурсе на лучшее веб-приложение объемом до 10 КБ, использующее только клиентские технологии.
Шарик, помогающий принимать решения

И если некоторые для этого занимались сжатием кода при помощи PNG, то мы решали обратную задачу — сжимали PNG при помощи js кода.


1. История с шариком и результат


В воскресенье вечером понадобился онлайн-шарик из фильма «Трасса 60». Не найдя подходящего варианта, написал свой примитивный шарик. Подумав, не выложить ли его в интернет, немножко допилил внешний вид и выложил. Написал небольшой пост на хабр и внезапно шарик многим понравился.
На следующий день перенес шарик на другой хостинг и зарегистрировал для него отдельный домен.
Казалось бы, на этом все и закончится, но…

2. Предложение участвовать в конкурсе


Утром в понедельник общались с bazilxp и он предложил поучаствоавть в конкурсе 10K Apart. Естественно, я знал про этот конкурс, но ни желания участвовать, ни времени на это у меня не было. Я ответил, что он может взять шарик и поучаствовать сам. bazilxp пообещал потратить вечер на сжатие шарика.

3. Задача


На следующий день оказалось, что все не так просто, как мы предполагали. Первоначальный вариант шарика занимал 45 Кб, из которых основная часть (38 Кб) — это картинка с шариком, 5 Кб — картинка с полупрозрачным синим треугольником (который находится в центре) и остальное — html, js css. Как можно уменьшить размер всего этого?

Половинка шарика

4. Картинка с шариком — 38 Кб, PNG


На картинке везде используется градиентная заливка и, естественно, хотелось бы уменьшить ее размер без потери качества.
  • Первое, что мы сделали, уменьшили количество цветов (до 8 бит на цвет), оставив формат PNG: размер картинки сократился до 31 Кб;
  • Далее bazilxp пришла идея сделать картинку симметричной и отрезать от нее половину. Полный шарик предполагалось рисовать на canvas, используя отражение оригинальной картинки (что bazilxp и реализовал). В результате размер кратинки уменьшился до 16 кб и появился небольшой костыль на js, разруливающий ситуацию, когда картинка не загрузилась в броузер к моменту начала отрисовки шарика.
  • После этого мы попробовали сохранить нашу половинку шарика в GIF. Результат занимал 8 Кб + стала заметна небольшая потеря качества, но в целом выглядело терпимо.
На этом временно перестали мучить шарик.

5. Проблема с синим треугольником — 5.5 Кб, PNG


По нашему мнению, при просмотре должна была создаваться иллюзия, что текст написан на синем треугольнике внутри шарика. Соответственно, при изменении текста синий треугольник с буквами должен плавно исчезать, а потом плавно появляться уже с новым текстом.
Наверно, самым простым решением было — убрать синий треугольник вообще, но подумав, мы отбросили этот вариант.
Итак:
  • Первым делом, как и в случае с шариком, мы уменьшили количество цветов, но размер файла от этого практически не сократился.
  • Далее стоит сказать, что треугольник имеет границы, в которых прозрачность постепенно перетекает от 1 до 0. При наложении треугольника на черный фон картинки с шариком создается впечатление, что границы немного размыты, благодаря чему значительно улучшается общий внешний вид странички. Решено было избавиться от прозрачности, заменив ее на плавное перетекание к черному цвету и положить все в GIF. Благодаря этому размер картинки с треугольником уменьшился до 3.5 Кб.
  • Неожиданно пришла идея нарисовать половину синего треугольника на половинке шарика. Тогда анимацию исчезновения и появления треугольника можно было бы организовать при помощи зарисовывания треугольника черным цветом с меняющимся уровнем прозрачности. В результате мы избавились от картинки с треугольником, но размер картинки с шариком вырос на 1,7 кб


На этот момент мы имели:
  1. картинку с половинкой шарика и половинкой синего треугольника, 9.7 Кб
  2. html + js + css, 4.5 Кб (код на js сильно вырос из-за рисования на элементе canvas)


Не буду описывать, как мы сжимали html/js/css — эти способы всем известны. К сожалению, нам они не помогли: после всего, что нам пришло в голову общий объем файлов составлял 11300 байт.

Решено было нарисовать шарик полностью руками на JavaScript в элементе canvas.

6. Рисование


После окончания рабочего дня, я сел в кофе хаусе, открыл tutorial и приступил к рисованию. bazilxp сделал то же самое у себя дома (кстати, он сидит в Китае и его часовой пояс отличается на +6 часов).
Самым сложным для нас оказалось рисование «восьмерки» в верхней части шарика и расчет на JavaScript координат для градиента, размывающего края синего треугольника (пришлось вспоминать тригонометрию, чего я не делал уже лет 5).
В результате примерно через 5 часов (к 23 часам по Москве) мы имели готовую, везде, где только можно протестированную страничку, которая почти полностью повторила оригинальную страничку с шариком. При этом размер всех файлов, включая css и favicon.ico даже без сжатия кода составил 7,65 КБ. Я отправился домой, а bazilxp — регистрировать наш шарик для участия в конкурсе.

Наблюдать результат (а также поддержать наш шарик путем голосования) можно на странице шарика на сайте конкурса.

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

Спасибо за внимание.

ЗЫ. Напоследок, скриншоты этапов рисования картинки с шариком:

Этапы рисования шарика


UPD: Напишу сразу про SVG, т.к. уже начались вопросы про это

Сейчас я тоже думаю, что SVG — менее трудоемко, но позавчера утром я, к сожалению, совсем ничего не знал ни про canvas, ни про SVG.

Мы схватили первое, что попалось под руку.

В любом случае, я не считаю, что мы впустую потратили время, т.к. получили опыт. Это очень важно для меня.

UPD2: Про серый фон
Вот такая картина наблюдается на Mac и в Safari под Windows.
image

Сами виноваты: забыли залить canvas фоном по умолчанию.

К сожалению, теперь поздно что-то менять.
Tags:
Hubs:
+106
Comments 65
Comments Comments 65

Articles