Этот SVG всегда показывает сегодняшнюю дату

Автор оригинала: Terence Eden
  • Перевод
Для своей странички с контактными данными нужна была стандартная иконка календаря, чтобы люди просматривали мой ежедневник. Такие иконки почти всегда делают наподобие бумажного календаря. Но мне стало интересно, можно ли сделать календарь чуть полезнее, если добавить динамическую иконку.

И вот он, SVG-календарь, который всегда показывает сегодняшнюю дату:


Фоновое изображение сделано на основе иконки Twitter TweMoji Calendar — CC-BY

Поддержка текста в SVG слегка неудобная, так что позвольте объяснить, как я это сделал.

SVG поддерживает JavaScript. Это запускается сразу после загрузки изображения.

<svg onload="init(evt)" xmlns="http://www.w3.org/2000/svg"
aria-label="Calendar" role="img" viewBox="0 0 512 512">

Следующий этап — получить различные строки с датами. Я использую британскую локаль en-GB, поскольку нахожусь в Великобритании.

<script type="text/ecmascript"><![CDATA[
function init(evt) {
  var time = new Date();
  var locale = "en-gb";

Мне нужно что-то вроде “Sunday 25 FEB”. Настройки локали поддерживают короткие и длинные имена, так что вы можете выбрать “SUN 25 February”.

  var DD   = time.getDate();
  var DDDD = time.toLocaleString(locale, {weekday: "long"});
  var MMM = time.toLocaleString(locale,  {month:   "short"});

Наконец, добавляем текст на изображение.

  var svgDocument = evt.target.ownerDocument;

  var dayNode = svgDocument.createTextNode(DD);
  svgDocument.getElementById("day").appendChild(dayNode);

  var weekdayNode = svgDocument.createTextNode(DDDD);
  svgDocument.getElementById("weekday").appendChild(weekdayNode);

  var monthNode = svgDocument.createTextNode(MMM.toUpperCase());
  svgDocument.getElementById("month").appendChild(monthNode);

}
]]></script>

Позиционировать текст относительно просто. Координаты X и Y привязываются к нижней границе текста — помните, что литеры с нижними выносными элементами, такие как g, выйдут за пределы координаты Y. Тут же мы устанавливаем цвет текста, размер и шрифт.

Макетирование проще всего с моноширинными шрифтами.

<text id="month"
  x="32" 
  y="164" 
  fill="#fff" 
  font-family="monospace"
  font-size="140px"
  style="text-anchor: left"></text>

По поводу выравнивания. Чтобы выровнять текст по центру, укажите style="text-anchor: middle".

Предварительные тесты показали, что этот SVG работает во всех десктопных браузерах и в браузерах под Android. Мы не проводили тесты на iPhone или более экзотических устройствах.

Наслаждайтесь!
Поддержать автора
Поделиться публикацией

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

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

    +28

    В связи с чем возникает законный вопрос: что будет, если кто-нибудь догадается встроить в SVG криптомайнер и начнёт постить такую картинку везде в комментариях?

      +1
      Она по сигнатурам попадет в фильтры uBlock.
        0
        В связи с чем? Статья не о том, что SVG поддерживает JavaScript. Или, вы думаете, автор сделал открытие?
          +20
          Майнеры сделали открытие)
          +4
          Картинки в комментариях обычно выводятся «as image»
          Теоретически скрипты бы должны не работать.
          SVG_Security
            0
            Ну вот в этом комменте почему-то работает: habrahabr.ru/post/350596/#comment_10699028
              0
              В текущей вкладке стартует ровно с 00:00
                +1
                Здорово. Можно утащить куки пользователей Хабра.
                  0
                  Скрипт в этих часах используется только для инициализации. Вся анимация работает без скриптов.
                    0
                    Точно, ваша правда. Понял в чём суть, спасибо.
              0
              кстати пришла похожая мысль на тему svg.
              но не столь радикальная
              0
              Мы не проводили тесты на iPhone.
              В iOS 11 в сафари работает.
                +7
                Откройте в новой вкладкеimage
                  +3
                  А в текущей вкладке показывает ерунду
                    0
                    Можете заскринить?
                      0
                      Лучше ссылкой)
                        0
                        И что же не так? На текущей вкладке запускается с нуля (с 12и), на новой вкладке — системное время.
                      +1
                      как и календарь в статье
                        0
                        Не ерунду, а часы, которые правильно показывают время только дважды в сутки (если открыть их в соответствующие моменты).
                          0
                          В том-то и дело, что они движутся, просто не инициализируются текущим временем.
                            0
                            Движутся они не скриптом. Там transform используется
                            (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform)
                        +2

                        Ну хоть секундомер в картинке работает.

                          0
                          Откройте диспетчер задач и посмотрите как кушает проц
                            0
                            я и так в хроме сижу… 4 гб оперативы — используется 104к КБ
                              0
                              Мопед не мой, я лишь… :)
                                0
                                Всего-то одно ядро сожрано…
                                0
                                Все конечно интересненько, только память жрёт
                                  0
                                  Там случайно не встроен майнер?
                                  image
                                    0

                                    Это анимация жрёт. Её коряво реализовали в браузере. Даже если в картинке ничего не меняется она перерисовывается полностью.

                                      0
                                      не неполностью, там три момента анимации — для каждой стрелки, можно по частям убирать и смотреть на проц. это относится и к мозиле и к хрому.
                                        0

                                        Это да. Но когда они встроены через тег img а в этом случае картинка перересовывается полностью постоянно. Даже шаговая анимация в одну минуту (<animateTransform calcMode="discrete" dur="1min" type="rotate" fill="freeze" by="6" />) перерисовывается несколько раз в секунду хотя в этом нет необходимости.

                                          0
                                          как это можно проверить/увидеть?
                                          если это без тега img — то нагрузка на проц будет меньше?
                                          В хроме можно залезть во внутрь svg, а в мозиле — нет.
                                            0

                                            В Firefox есть кнопка "Подсветить прорисованную область" в панели иструментов консоли. Её надо добавить в "Настройки инструментов" -> "Дополнительные кнопки инструментов" -> "Подсветить прорисованную область".
                                            В хроме аналог флажок "Enable paint flashing" на вкладке Rendering в консоли.
                                            Только осторожно с этим. Зрелище не для эпилептиков. В хроме это нежнее реализовано.

                                              0
                                              проверил, перерисовывает не всю картинку, а только прямоугольник, в который вписывается стрелка(и)
                                                0

                                                В оригинальном svg или встроеном через тег img?

                                                  0
                                                  если смотреть на этой странице — то вся картинка, если в новой вкладке — то отдельными примоугольниками
                                                    0

                                                    Вот об этом и речь.

                                        0

                                        Вот пример:


                                        Здесь спрятан квадрат который грузит процессор

                                        image


                                        Этот квадрат не делает ничего кроме того что жрёт процессорное время.


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


                                        Как включить этот режим

                                        В Firefox есть кнопка "Подсветить прорисованную область" в панели инструментов консоли. Её надо добавить в "Настройки инструментов" -> "Дополнительные кнопки инструментов" -> "Подсветить прорисованную область".
                                        В хроме аналог флажок "Enable paint flashing" на вкладке Rendering в консоли.
                                        Только осторожно с этим. Зрелище не для эпилептиков. В хроме это нежнее реализовано.


                                        Как он это делает?


                                        <animateTransform fill="freeze" repeatCount="indefinite" attributeName="transform" by="0" calcMode="discrete" dur="1000000000000000000000000000000h" type="rotate"/>

                                        Разберём по полочкам:


                                        1. calcMode="discrete" — выполнить без переходов.
                                          В этом режиме отключается переход и анимация в определённый момент выполняется мгновенно меняя одно значение на другое.
                                        2. dur="1000000000000000000000000000000h" — это время анимации.
                                          Дофига часов которое анимация будет работать. Точнее просто жрать процессор ничего не меняя в картинке. В режиме discrete через половину этого времени должна быть мгновенно изменено значение.
                                        3. type="rotate" — это анимация должна повернуть фигуру
                                        4. by="0" — на 0 градусов.
                                          То есть опять ничего не изменится даже в тот момент когда должно поменяться значение.

                                        Для лучшего понимания как работает режим discrete:


                                        Другой квадрат который грузит процессор

                                        image


                                        Тут я уже задал значения при которых квадрат меняет поворот. Но он также постоянно перерисовывается даже когда не движется.


                                        Его анимация:


                                        <animateTransform fill="freeze" repeatCount="indefinite" attributeName="transform" by="45" calcMode="discrete" dur="5s" type="rotate"/>

                                        1. repeatCount="indefinite" — повторять бесконечно
                                        2. dur="5s" — длительность анимации 5 секунд
                                        3. calcMode="discrete" — выполнить смену значения мгновенно без переходов
                                        4. type="rotate" — повернуть
                                        5. by="45" — на 45 градусов

                                        И никаких скриптов и майнеров не надо.

                                          0

                                          Я поэкспериментировал и сделал свой SVG секундомер в котором анимация включается каждую секунду на 0.001 секунды.
                                          image
                                          image

                                      0
                                      del
                                      +3
                                      А если заменить
                                      var locale = "en-gb";

                                      на
                                      var locale = undefined;

                                      то получим то же самое в текущей локали.
                                        +2
                                        Со скриптами и я могу) Но скрипты в svg не работают, если svg показывается как картинка на странице, а не как отдельный документ.
                                          0

                                          Скрипты не работают, если svg показывается как картинка на странице.


                                          +10
                                          Вся статья сводится к трем тезисам:

                                          • SVG поддерживает Javascript
                                          • new Date()
                                          • evt.target.ownerDocument.createTextNode()
                                            0
                                            SVG поддерживает Javascript

                                            А не дыра ли это?

                                              0

                                              С чего вдруг? В img скрипты не работают. Они работают только если svg встроен напрямую в html или открыт в отдельном окне.

                                                0
                                                открыт в отдельном окне.

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

                                                  0
                                                  Ох. То есть вот почему солидные дяди отдают картинки с отдельного домена…
                                            0
                                            На iPhone тоже работает.
                                              +10
                                              >>Этот SVG всегда показывает сегодняшнюю дату
                                              Нет, он показывает дату открытия, завтра соврет.
                                                0

                                                Видмо имеется ввиду если его встроить напрямую в страницу на не тегом img.

                                                  +3
                                                  Я имел ввиду, что код выполняется один раз на инициализации и при переходе времени на следующий день — не обновится.
                                                    –2

                                                    Почему? Я вижу уже 7

                                                      0
                                                      И завтра увидите
                                                        0
                                                        Имеется ввиду, что скрипт не будет перезапускаться, когда будет пройдет день, и на SVG будет старая дата
                                                  0
                                                  Мы не проводили тесты на iPhone или более экзотических устройствах.

                                                  С каких это пор айфон — хоть сколько-нибудь экзотическое устройство?)
                                                    0
                                                    А вне браузера он и не должен исполняться, верно? По крайней мере в eog скрипт не отрабатывает и картинка показывает дефолтное 29 февраля.

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

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