- PVSM.RU - https://www.pvsm.ru -

Разработка анимированных фавиконов

Это — первое, что ищут взглядом, когда переключаются между вкладками браузера. Только что мы дали одно из возможных описаний того, что называется «фавиконом». Пространство на экране, которое занимает ярлык вкладки веб-страницы — это гораздо более ценный ресурс, чем многие думают. Если хорошо поработать с ярлыком, то он, помимо того, что будет продолжать играть роль идентификатора страницы, может стать чем-то вроде «доски объявлений», которая сообщает о том, что именно происходит на странице.

Разработка анимированных фавиконов - 1


Фавикон

Фавиконы, на самом деле, особенно полезны в тех случаях, когда речь идёт о неактивных вкладках браузера. Рассмотрим пример.

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

Это — как раз тот случай, когда можно проявить креативность! Что если бы мы могли динамически менять пиксели, из которых состоит фавикон, и выводили бы на ярлык страницы сведения о процессе выгрузки файлов? Собственно говоря, именно этим мы здесь и займёмся.

В браузерах, которые это поддерживают, можно выводить некую анимацию в качестве фавикона с помощью JavaScript, HTML-элемента <canvas> и древних правил геометрии.

Вот [1] как выглядит анимация загрузки во вкладке браузера.

Сразу приступим к делу и начнём с самого простого. А именно — добавим в HTML-код страницы элементы <link> и <canvas>:

<head>
    <link rel="icon" type="image/png" href="" width=32px>
</head>

<body>
    <canvas width=32 height=32></canvas>
</body>

При практическом использовании этой методики вам, вероятно, захочется скрыть элемент <canvas>. Один из способов сделать это заключается в использовании HTML-атрибута hidden:

<canvas hidden width=32 height=32></canvas>

Я собираюсь оставить элемент <canvas> видимым для того, чтобы мы могли бы наблюдать за тем, как анимация одновременно выводится и на фавиконе, и на элементе <canvas>. И то и другое имеет размер стандартного фавикона — 32x32 пикселя.

Мы, в демонстрационных целях, добавим на страницу кнопку, щелчок по которой запускает анимацию. Добавим в HTML-код страницы следующее:

<button>Load</button>

Теперь займёмся JavaScript-кодом. Сначала проверим поддержку canvas:

onload = ()=> {
  canvas = document.querySelector('canvas'),
  context = canvas.getContext('2d');
  if (!!context) {
      /* если canvas поддерживается*/
  }
};

Далее — подключим обработчик событий нажатия на кнопку, который будет использоваться для запуска анимации в элементе <canvas>:

button = document.querySelector('button');
button.addEventListener('click', function() { 
    /* Переменная, используемая для управления анимацией */
    n = 0, 
    /* Длительность интервала анимации */
    loadingInterval = setInterval(drawLoader, 60); 
});

Сущность drawLoader, которую мы передали setInterval, представляет собой функцию, которая будет вызываться с интервалом в 60 миллисекунд и выводить что-то в элемент <canvas>. Прежде чем мы напишем код этой функции, давайте опишем стиль линий, которые будем использовать при постепенном рисовании квадрата, представляющего собой индикатор загрузки.

/* Стиль линий, которые будут использоваться для рисования квадратного индикатора загрузки */
let gradient = context.createLinearGradient(0, 0, 32, 32);
gradient.addColorStop(0, '#c7f0fe');
gradient.addColorStop(1, '#56d3c9');
context.strokeStyle = gradient;
context.lineWidth = 8;

В функции drawLoader мы будем рисовать линии, основываясь на том, сколько процентов шагов анимации уже выполнено. В нашем случае 1 шаг анимации соответствует 1%. А именно, в течение первых 25% шагов будет постепенно выводиться линия, представляющая собой верхнюю сторону квадрата. Следующие 25% шагов будет выводиться правая сторона квадрата, и так далее — по 25% времени анимации на каждую сторону.

Эффект анимации достигается путём стирания содержимого элемента <canvas> и вывода немного удлинённой, в сравнении с предыдущим шагом, линии. На каждом шаге анимации, после того, как вывод изображения в элемент <canvas> окончен, изображение быстро преобразуется в формат PNG и устанавливается в качестве фавикона страницы.

function drawLoader() {
  with(context) {
    clearRect(0, 0, 32, 32);
    beginPath();
    /* До 25% времени, выделенного на рисование*/
    if (n<=25){ 
      /*
        (0,0)-----(32,0)
      */
      // код для инкрементного рисования верхней линии
    }
    /* Между 25 и 50 процентами */
    else if(n>25 && n<=50){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
                  (32,32)
      */
      // код для вывода верхней и правой линии.
    }
    /* Между 50 и 75 процентами */
    else if(n>50 && n<= 75){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
        (0,32)----(32,32)
      */
      // код для вывода верхней, правой и нижней линий.
    }
      /* Между 75 и 100 процентами */
    else if(n>75 && n<=100){
      /*
        (0,0)-----(32,0)
            |      |
            |      |
        (0,32)----(32,32)
      */
      // код для вывода всех четырёх линий квадрата.
    }
    stroke();
  }
  // Преобразуем то, что нарисовано на элементе <canvas>, в формат PNG, и сделаем полученное изображение фавиконом
  favicon.href = canvas.toDataURL('image/png');
  /* После того, как рисование завершено */
  if (n === 100) {
    clearInterval(loadingInterval);
    return;
  }
  // Инкрементируем переменную, которая используется для управления анимацией
  n++;
}

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

Вот какие данные используются для постепенного вывода верхней стороны квадрата в течение первых 25 шагов анимации:

  • Начальная точка — левый верхний угол изображения (0,0).
  • n — номер текущего шага анимации.
  • x — координата x конечной точки линии на текущем шаге анимации.
  • y — координата y конечной точки, которая равна 0.

Нам нужно, чтобы после завершения всех 25 шагов анимации значение x равнялось бы 32 (то есть — размеру фавикона и элемента <canvas>). Поэтому мы будем искать значение x на текущем шаге анимации n по следующей формуле:

x = (32/25) * n

Вот как выглядит код для рисования линии, в котором реализованы эти рассуждения:

moveTo(0, 0); lineTo((32/25)*n, 0);

Следующие 25 шагов анимации (рисование правой стороны квадрата) выполняются похожим образом:

moveTo(0, 0); lineTo(32, 0);
moveTo(32, 0); lineTo(32, (32/25)*(n-25));

А вот — полный код функции drawLoader:

function drawLoader() {
  with(context) {
    clearRect(0, 0, 32, 32);
    beginPath();
    /* До 25% времени, выделенного на рисование*/
    if (n<=25){ 
      /*
        (0,0)-----(32,0)
      */
      moveTo(0, 0); lineTo((32/25)*n, 0);
    }
    /* Между 25 и 50 процентами */
    else if(n>25 && n<=50){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
                  (32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, (32/25)*(n-25));
    }
    /* Между 50 и 75 процентами */
    else if(n>50 && n<= 75){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
        (0,32)----(32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, 32);
      moveTo(32, 32); lineTo(-((32/25)*(n-75)), 32);
    }
      /* Между 75 и 100 процентами */
    else if(n>75 && n<=100){
      /*
        (0,0)-----(32,0)
            |      |
            |      |
        (0,32)----(32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, 32);
      moveTo(32, 32); lineTo(0, 32);
      moveTo(0, 32); lineTo(0, -((32/25)*(n-100)));
    }
    stroke();
  }
  // Преобразуем то, что нарисовано на элементе <canvas>, в формат PNG, и сделаем полученное изображение фавиконом
  favicon.href = canvas.toDataURL('image/png');
  /* После того, как рисование завершено */
  if (n === 100) {
    clearInterval(loadingInterval);
    return;
  }
  // Инкрементируем переменную, которая используется для управления анимацией
  n++;
}

Итоги

Вот и всё! Код для создания прямоугольного индикатора загрузки, разработкой которого мы тут занимались, можно найти в этом [2] репозитории. А вот [3] — репозиторий с кодом кругового индикатора загрузки. На самом деле, вы, в качестве подобного индикатора, может использовать любую фигуру. А если вы поработаете с атрибутом fill элемента <canvas> — это позволит вам добиться интересных эффектов.

Уважаемые читатели! Есть ли среди ваших проектов такие, в которых пригодились бы анимированные фавиконы?

Автор: ru_vds

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/328492

Ссылки в тексте:

[1] Вот: https://css-tricks.com/wp-content/uploads/2019/08/square-loading-favicon.mov

[2] этом: https://github.com/rpsthecoder/square-loading-favicon

[3] вот: https://github.com/rpsthecoder/favicon-canvas-loader

[4] Источник: https://habr.com/ru/post/464127/?utm_campaign=464127&utm_source=habrahabr&utm_medium=rss