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

И вот он, 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 или более экзотических устройствах.

Наслаждайтесь!

Комментарии (53)


  1. kekekeks
    06.03.2018 15:03
    +14

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


    1. vesper-bot
      06.03.2018 15:07
      -2

      Она по сигнатурам попадет в фильтры uBlock.


    1. anador
      06.03.2018 16:48

      В связи с чем? Статья не о том, что SVG поддерживает JavaScript. Или, вы думаете, автор сделал открытие?


      1. semen-pro
        06.03.2018 18:12
        +6

        Майнеры сделали открытие)


    1. arandomic
      06.03.2018 18:17

      Картинки в комментариях обычно выводятся «as image»
      Теоретически скрипты бы должны не работать.
      SVG_Security


      1. Psychosynthesis
        07.03.2018 05:01

        Ну вот в этом комменте почему-то работает: habrahabr.ru/post/350596/#comment_10699028


        1. nidalee
          07.03.2018 07:43

          В текущей вкладке стартует ровно с 00:00


        1. codemafia
          07.03.2018 09:39
          +1

          Здорово. Можно утащить куки пользователей Хабра.


          1. dmitryredkin
            07.03.2018 17:29

            Скрипт в этих часах используется только для инициализации. Вся анимация работает без скриптов.


    1. kalininmr
      06.03.2018 21:48

      кстати пришла похожая мысль на тему svg.
      но не столь радикальная


  1. Rastishka
    06.03.2018 15:07

    Мы не проводили тесты на iPhone.
    В iOS 11 в сафари работает.


  1. perfect_genius
    06.03.2018 15:20
    +3

    Откройте в новой вкладкеimage


    1. vbif
      06.03.2018 15:44
      +2

      А в текущей вкладке показывает ерунду


      1. perfect_genius
        06.03.2018 16:16

        Можете заскринить?


        1. kruslan
          06.03.2018 16:32

          Лучше ссылкой)


          1. perfect_genius
            06.03.2018 16:37

            И что же не так? На текущей вкладке запускается с нуля (с 12и), на новой вкладке — системное время.


      1. qwert_ukg
        07.03.2018 05:53
        +1

        как и календарь в статье


      1. k0ldbl00d
        07.03.2018 13:28

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


        1. vbif
          07.03.2018 13:46

          В том-то и дело, что они движутся, просто не инициализируются текущим временем.


    1. ivan386
      06.03.2018 15:53
      +2

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


    1. BigDflz
      06.03.2018 15:58

      Откройте диспетчер задач и посмотрите как кушает проц


      1. rmuskovets
        06.03.2018 20:02

        я и так в хроме сижу… 4 гб оперативы — используется 104к КБ


      1. perfect_genius
        06.03.2018 21:17

        Мопед не мой, я лишь… :)


      1. Germanets
        07.03.2018 11:29

        Всего-то одно ядро сожрано…


    1. kentov
      06.03.2018 19:20

      Все конечно интересненько, только память жрёт


    1. Max_JK
      08.03.2018 08:53

      Там случайно не встроен майнер?
      image


      1. ivan386
        08.03.2018 11:07

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


        1. BigDflz
          09.03.2018 18:03

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


          1. ivan386
            09.03.2018 19:05

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


            1. BigDflz
              09.03.2018 19:09

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


              1. ivan386
                09.03.2018 19:20

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


                1. BigDflz
                  09.03.2018 19:39

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


                  1. ivan386
                    09.03.2018 19:41

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


                    1. BigDflz
                      09.03.2018 20:02

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


                      1. ivan386
                        09.03.2018 20:19

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


    1. Kobalt_x
      08.03.2018 20:10

      del


  1. hdfan2
    06.03.2018 15:25
    +1

    А если заменить

    var locale = "en-gb";

    на
    var locale = undefined;

    то получим то же самое в текущей локали.


  1. vvadzim
    06.03.2018 16:07
    +1

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


    1. Goodkat
      06.03.2018 23:58

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



  1. impwx
    06.03.2018 16:48
    +4

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

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


    1. DistortNeo
      07.03.2018 12:20

      SVG поддерживает Javascript

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


      1. ivan386
        07.03.2018 12:31

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


        1. DistortNeo
          07.03.2018 18:45

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

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


          1. vvadzim
            09.03.2018 08:15

            Ох. То есть вот почему солидные дяди отдают картинки с отдельного домена…


  1. BOOTLOADER
    06.03.2018 18:26
    -1

    На iPhone тоже работает.


  1. PoliTeX
    06.03.2018 19:52
    +4

    >>Этот SVG всегда показывает сегодняшнюю дату
    Нет, он показывает дату открытия, завтра соврет.


    1. ivan386
      06.03.2018 20:51
      +1

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


      1. PoliTeX
        07.03.2018 00:35
        +1

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


        1. decomeron
          07.03.2018 01:32

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


          1. ad1Dima
            07.03.2018 07:43

            И завтра увидите


          1. SoloFeeD
            07.03.2018 10:58

            Имеется ввиду, что скрипт не будет перезапускаться, когда будет пройдет день, и на SVG будет старая дата


  1. geoolekom
    07.03.2018 23:49

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

    С каких это пор айфон — хоть сколько-нибудь экзотическое устройство?)


  1. synedra
    08.03.2018 09:14

    А вне браузера он и не должен исполняться, верно? По крайней мере в eog скрипт не отрабатывает и картинка показывает дефолтное 29 февраля.