WoW Events Calendar and How to Make It

[Offline] в блоге [Offline]'s notes

Опубликовано: 01 февраля 2016 в 21:55




Несмотря на обилие новостей с альфы Легиона, до выхода самого дополнения еще довольно далеко, а новый контент на live серверах с момента добавления последнего рейдового тира появляется не часто. Поэтому даже для самых упоротых истинных фанатов игры сейчас самый подходящий момент, чтобы отвлечься на что-то ещё и, возможно, потратить время с толком, научившись чему-нибудь красивому и полезному.
 
Здесь я покажу одно из таких направлений использования свободного времени, сделав с нуля интерактивный календарь с различными эвентами из WoW и объяснив основы той чёрной магии, с помощью которой подобные штуки создаются. Не стоит воспринимать это как полноценный гайд - скорее, это краткое описание для понимания общей картины, в котором я попытаюсь сохранить разумный баланс между совсем примитивным и слишком сложным изложением. Ну а для тех, кто заинтересуется, в интернете существует огромное количество обучающих материалов разной степени подробности и глубины.

Творить красоту и разбираться в её коде будем на этот раз ^_^


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

Spoiler: Открыть страшный ящик и выпустить эту магию




HTML

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

Большая часть сайтов в интернете имеет в своей основе HTML, который расшифровывается как Hyper Text Markup Language. Это стандартизированный язык разметки страниц, который "читается" браузером и отображается им в виде различных элементов сайта.

Каждый элемент состоит из открывающего и закрывающего тегов, между которыми помещают его содержимое. Сами элементы представляют собой обычно какой-то определённый тип информации или выполняют какое-либо конкретное действие.

Например, <p>Бла бла бла...</p> - это абзац текста, где <p> - открывающий тег,  </p> - закрывающий тег, а текст  Бла бла бла... - содержимое элемента.

Некоторые элементы не требуют закрывающего тега, например <br> - это переход на новую строку. Впрочем, во избежание всяких экзотических глюков и для улучшения читаемости сайта роботами, подобные теги можно закрывать вот так: <br />.

Примеры HTML-элементов:

Код
Результат
<p>Здесь просто текст...<br>И ещё текст.</p> Здесь просто текст...
И ещё текст.
<button>Я кнопка, потыкай меня</button> Я кнопка, потыкай меня


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

Пара примеров:

Код
Результат
<p>Я обычный текст.</p>
<p color="green">Я зелёный текст.</p>
Я обычный текст.
Я зелёный текст.
<a href="noob-club.ru">Я ссылка, кликни меня</a> Я ссылка, кликни меня.


HTML-элементы могут быть вложенными друг в друга. Например, таблица состоит из элемента <table></table>, внутри которого содержатся её строки <tr></tr>, которые в свою очередь содержат ячейки <td></td>. Выглядит это вот так:

Код
Результат
<table>
   <tr>
      <td>Ячейка 1</td><td>Ячейка 2</td>
   </tr>
   <tr>
      <td>Ячейка 3</td><td>Ячейка 4</td>
   </tr>
</table>
Ячейка 1 Ячейка 2
Ячейка 3 Ячейка 4


Ячейки можно объединять атрибутами colspan и rowspan, которые соответственно позволяют "растянуть" одну ячейку на несколько столбцов или строк.

Код
<table>
   <tr>
      <td>1</td><td>2</td><td>3</td><td>4</td><td>5</td>
   </tr>
   <tr>
      <td>6</td><td>7</td><td colspan="3">Ячейка 8</td>
   </tr>
   <tr>
      <td>9</td><td>10</td><td>11</td><td>12</td><td>13</td>
   </tr>
   <tr>
      <td rowspan="2">Ячейка 14</td><td>15</td><td>16</td><td>17</td><td>18</td>
   </tr>
   <tr>
      <td>19</td><td>20</td><td>21</td><td>22</td>
   </tr>
</table>
Результат
1 2 3 4 5
6 7 Ячейка 8
9 10 11 12 13
Ячейка 14 15 16 17 18
19 20 21 22


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

Чтобы так не мучиться, удобнее использовать элемент <div></div>, который представляет собой универсальный контейнер (блок), внутрь которого можно запихать любой тип данных, а в его свойствах (атрибутах) можно задать любой удобный размер, стиль и расположение относительно других элементов. Собственно, большинство современных веб-страниц собраны именно из div-ов.



Итак, у нас уже достаточно информации, чтобы начать делать календарь. Сетка для каждого месяца - это таблица, которую можно сделать на чистом HTML:

Код
<table>
   <caption>January (01)</caption>
   <tr>
      <th>Mo</th><th>Tu</th><th>We</th><th>Th</th><th>Fr</th><th>Sa</th><th>Su</th>            
   </tr>
   <tr>
      <td></td><td></td><td></td><td></td><td>1</td><td>2</td><td>3</td>
   </tr>
   <tr>
      <td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td>
   </tr>
   <tr>
      <td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td>
   </tr>
   <tr>
      <td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td>
   </tr>
   <tr>
      <td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td><td>31</td>
   </tr>
</table>
Результат
January (01)
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31


А чтобы можно было потом расположить месяца на экране как нам захочется, каждую такую таблицу обернём в div.


CSS

Указывать атрибуты для описания внешнего вида и способов отображения элемента в его открывающем теге удобно в том случае, когда такой элемент встречается один раз. А что если, например, у нас на сайте 1000 статей, и мы хотим чтобы в каждой из них все заголовки были в одном и том же стиле, одним и тем же шрифтом, одного размера, с одинаковыми отступами и прочими мелочами? Копировать все эти свойства для каждого элемента, понятное дело, задолбаешься.

Для решения такой проблемы придумали CSS - Cascading Style Sheets. Каждому типу элементов, например table или h1, можно отдельно прописать все атрибуты, после чего они будут применяться ко всем таким элементам на странице. Делается это следующим образом:


название_элемента {
   свойство 1: значение;
   свойство 2: значение;
   ...
   свойство N: значение;
}



Более того, стили можно задать таким же образом вообще в отдельном CSS-файле, а для применения их к странице сайта достаточно всего один раз указать на ней линк к этому файлу.

Если мы хотим, чтобы у нас было несколько "скинов" для каждого элемента, например таблицы с разным цветом фона, можно такие элементы объединить в класс. Название класса прописывается как атрибут в открывающем теге, а информация о его стиле указывается в CSS. На примере понятнее:

Код
Результат
<style>
table.kermitnoob {
   color: darkred;
   background: yellow;
}

table.fuckthesystem {
   color: white;
   background: green;
}
</style>

<table class="kermitnoob">
   <tr>
      <td>Ячейка 1</td><td>Ячейка 2</td>
   </tr>
   <tr>
      <td>Ячейка 3</td><td>Ячейка 4</td>
   </tr>
</table>

<table class="fuckthesystem">
   <tr>
      <td>Ячейка 1</td><td>Ячейка 2</td>
   </tr>
   <tr>
      <td>Ячейка 3</td><td>Ячейка 4</td>
   </tr>
</table&gt
;
Ячейка 1 Ячейка 2
Ячейка 3 Ячейка 4

Ячейка 1 Ячейка 2
Ячейка 3 Ячейка 4


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

Теперь применим все эти фичи к нашему календарю. Каждый месяц у нас - это элемент div, содержащий таблицу. Создаём класс .month, для которого прописываем все элементы оформления:


div.month {
   float: left;
   display: inline-block;
   background: #222222;
   padding: 0 10px 10px 10px;
   margin: 10px;
   border-radius: 10px;
   font-size: 60%;
}



Этим коротким кодом мы для всех наших 12 месяцев сделали следующее: выровняли по левому краю, выстроили в линию, задали цвет фона, указали внутрениие и внешние отступы, скруглили углы и указали размер шрифта для всего содержимого.

И сразу же задаём оформление таблиц, которые соответствуют нашему селектору (т.е. этот стиль будет применяться только к тем таблицам, которые находятся внутри div-ов с классом .month):


div.month table, div.month td {
   border: 1px solid #555555;
   border-collapse: collapse;
   color: #f1d991;
   text-align: right;
   padding: 5px;
}

div.month th {
   border: 1px solid #555555;
   background: #444444;
   color: #f1c232;
   padding: 5px;
   text-align: center;
   width: 14.285%;
}



А чтобы было ещё круче, раскидаем месяца по временам года. Для этого поместим div-ы с соответствующими месяцами внутрь div-ов класса .season, стиль которых зададим следующим образом:


div.season {
   width: 95%;
   display: inline-block;
   background: #141414;
   padding 0 10px 10px 10px;
   margin: 5px;
   border-radius: 10px;
}

div.season h1 {
   color: #f1c232;
   font-size: 100%;
   font-style: italic;
   padding-left: 30px;
}



Получается уже вот так:




Мелко и неудобно  :facepalm:  Поэтому давайте сделаем, чтобы месяца увеличивались при наведении на них мышкой. CSS позволяет указать, как должны меняться свойства (в том числе размеры) элемента, когда курсор мыши висит (hover) над ним:


div.month:hover {
   transform-origin: left top;
   transform: scale(2.5);
   opacity: 0.9;
}



В результате месяца будут при наведении курсора увеличиваться в 2.5 раза, сохраняя положение относительно своего левого верхнего угла. И чисто because I can, будут ещё становиться прозрачными на 10%.
 
А чтобы изменение размера происходило не резким скачком, зададим плавную анимацию. В коде для анимации указывается её название (пусть оно у нас будет enlarge), а также начальное (в фигурных скобках после from) и конечное (в фигурных скобках после to) состояние объекта:


@keyframes enlarge {
   from {transform: scale(1); opacity: 1;}
       to {transform: scale(2.5); opacity: 0.9;}
}



Теперь прицепляем анимацию к свойствам класса, указывая её параметры (название, длительность, тип замедления и ускорения и т.п.) в описании стиля:


div.month:hover {
   animation: enlarge .5s ease-in-out;
   transform-origin: left top;
   transform: scale(2.5);
   opacity: 0.9;
}



Ура, получилось - при наведении мышкой месяц плавно увеличивается.


JavaScript

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

Для начала, берём полный список праздников в WoW и дат, в которые эти события отмечаются. Каждый день в нашем календаре - это ячейка таблицы. Всем таким ячейкам "праздничных" дней нужно присвоить класс, соответствующий активному в этот день событию. Пожалуй, это самый унылый и утомительный момент, но за 15 минут вполне можно управиться.

Теперь для каждого класса мы можем задать отдельное оформление, и все дни какого-нибудь Лунного Фестиваля окрасятся в тот цвет или приобретут ту анимацию, которую мы захотим. Но как нам сделать, чтобы это оформление можно было включать и отключать?

Тут на помощь приходит JavaScript. С помощью тега <script></script>  мы можем помещать на страницу код, который будет выбирать определённые элементы или классы элементов и менять их свойства в тот момент, когда мы этот код запустим. А запускаться он будет при клике на кнопочку, являющуюся одним из стандартных элементов в HTML.

Например, включать подсветку Лунного Фестиваля у нас будет функция с названием HolidaysMoon(). Создаём кнопку для её запуска:


<button type="button" class="Moon" onclick="HolidaysMoon()"&gtLunar Festival</button&gt


И прописываем код самой функции, включающей анимацию для элементов класса .Moon, который мы присвоили всем ячейкам календаря, соответствующим дням Лунного Фестиваля (и кстати, самой кнопке мы его тоже присвоили):


<script&gt
function HolidaysMoon() {
   var list = document.querySelectorAll(".Moon");
   for (var j = 0, length = list.length; j    list[j].style.animation = "glow_white 2.5s ease-in-out infinite";
}
</script>



Ну и конечно, не забываем саму анимацию:


@keyframes glow_white {
      0% {box-shadow: 0 0 5px white inset;}
       50% {box-shadow: 0 0 15px white inset;}
       100% {box-shadow: 0 0 5px white inset;}
}



Теперь при нажатии кнопки с надписью Lunar Festival у нас все дни этого события в календаре начинают пульсировать белым цветом.

Аналогично поступаем со всеми остальными эвентами. Стили для кнопок и их взаимного расположения задаём через CSS, как и для всех остальных элементов. Анимации с разными цветами тоже создаём по аналогии с уже показанной.


It's Time to Put It Together

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

На Нуб-Клабе, как всегда, что-нибудь не работает, и мой код не помещается в пост (к тому же, тут отсутствует нормальный хайлайтер синтаксиса), поэтому код я выложил вот здесь (ниже самого календаря).


Всем добра, красоты, сисек и счастливых праздников.


  • 1305
  • 5

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

Default avatar
02 февраля 2016 в 07:36
1. Есть нюанс с весной/осенью/... -- у Близзард свои понятия о начале времён года на Азероте, это бы следовало учесть в календаре, любители ловителей сезонных петов будут рады.

2. Учесть временные зоны и чудаческое начало событий на Азероте, не совпадающее с 00:00.

3. Интегрировать с Оружейной, чтобы подсвечивало недобитые ачивками события.

4. Таки Тыквовин, а не Тыквовен. Ширять тыквенный сок в вены это слишком круто %)

5. Подсветить/обрамочить сегодняшний день.
Отредактировано 02 февраля 2016 в 07:40
75233 e899ada10bdc735f074c3fae5afd7bd0
02 февраля 2016 в 12:19
1. Время на Азероте может течь как угодно, эвенты же соответствуют вполне конкретным датам реального человеческого календаря, эти даты и подсвечиваются.

2. В разных часовых поясах всё равно события будут начинаться/заканчиваться в разное время. Тут максимум можно сделать пометку, что совсем не обязательно всё начинается в 00:00.

3. Для такого потребовалось бы как минимум идентифицировать юзера/персонажа.

4. Fixed.

5. Вот это мейби, но тут тоже могут возникнуть косяки с часовым поясом.
Default avatar
02 февраля 2016 в 08:25
оффлайн где анимешные boobs? I тебя not узнаю, серьезно . . .
Отредактировано 02 февраля 2016 в 08:25
Default avatar
22 июня 2018 в 15:35
1
Default avatar
22 июня 2018 в 15:35
1