Подготовка к конференции SVG Open

Недавно я демонстрировал тест-драйв современного SVG на примере файла SVG «Игральные кости», который сейчас размещен на веб-сайте, посвященном тест-драйву Internet Explorer 9. При создании этого примера я обнаружил, что производительность и взаимодействие для файлов SVG мало связаны друг с другом и не образуют пару. Это настолько меня зацепило, что я внес изменения в свою презентацию для конференции SVG Open Conference на этой неделе, проходящей под названием «Будущее SVG и HTML5», включив в нее методы, с помощью которых сообщество разработчиков SVG может, объединив усилия, расширить возможности взаимодействия SVG.

Тестирование SVG и тест-драйв SVG

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

В HTML5 будущее SVG связано со следующим поколением интерактивной графики в Интернете, в которой SVG будет использоваться значительно шире. Как сообществу разработчиков, нам необходимо подумать о том, как осуществить разностороннее тестирование спецификации SVG.

Тестирование SVG

Наборы тестов SVG W3C «пытаются» проверить возможность применения спецификации, но как мы узнали в рабочей группе, этого недостаточно, чтобы обеспечить ряд возможностей взаимодействия, позволяющих разработчику использовать одну и ту же разметку, которая будет правильно работать во всех браузерах. Набор тестов SVG предназначен не для проверки соответствия, а скорее для проверки того, может ли быть реализована данная спецификация. Из статьи о тестировании SVG на вики-узле W3C:

«Наши наборы тестов необходимы, но не достаточны для проверки соответствия. Поэтому результаты тестирования поддержки относятся к более сложным функциям SVG, и не демонстрируют общий уровень поддержки SVG.»

Другими словами, существующие наборы тестов не проверяют, соответствует ли браузер спецификации. В связи с этим мы тесно сотрудничаем с рабочей группой SVG, содействуя проведению этих тестов; группа SVG Interest Group прилагает усилия для создания теста на соответствие SVG DOM 1.1. На момент написания этого сообщения IE9 прошел 100% этих автоматизированных тестов. Вместе с рабочей группой SVG мы помогаем разрешить проблемы взаимодействия, продолжая систематически вносить улучшения в набор тестов SVG.

Кроме того, существует некоторый дисбаланс между количеством требований в модулях спецификации SVG и количеством тестов в наборе тестов SVG, представляющих эти требования. Группа Internet Explorer помогает устранить этот дисбаланс, внося свой вклад в разработку тестов. Но этого недостаточно. Мы уже разработали 56 тестов и планируем со временем увеличивать это число.

Тест-драйв SVG

Более наглядным показателем соответствия, и что более важно, взаимодействия, была разработка более сложного SVG-объекта для Интернета. Мой собственный опыт тест-драйва SVG при разработке демонстрационного файла SVG «Игра в кости» раскрывает некоторые моменты, в которых мы должны улучшить взаимодействие SVG совместными усилиями.

Get Microsoft Silverlight

Спецификация SVG содержит более 2000 отдельных требований. Это много по сравнению с другими веб-спецификациями, и подразумевает простор для различных интерпретаций. Рабочая группа SVG W3C прилагает все усилия, чтобы выявить такие интерпретации. При разработке демонстрационного файла SVG, который мог бы работать в любых браузерах, у меня была возможность изучить некоторые сложности, с которыми сталкиваются веб-разработчики.

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

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

Сравнение реализаций

Я написал демонстрацию SVG «Игральные кости», исходя из собственного понимания спецификации, используя Internet Explorer 9, а затем последовательно проверил ее в других браузерах. В большинстве случаев при столкновении с конфликтующим поведением я замечал, что как минимум два браузера все-таки интерпретировали демонстрацию одинаково. В одних случаях поведение Internet Explorer соответствовало поведению браузеров Chrome или Safari, в других случаях — поведению Firefox или Opera. Поскольку Internet Explorer является самой последней реализацией, он использует преимущества спецификации SVG последней версии, в которой устранена хотя бы часть неоднозначностей и конфликтов. Очевидно, что их значительно больше.

Для меня стало неожиданностью влияние аппаратной производительности на ход разработки.

Get Microsoft Silverlight

Как разработчик, я планировал использовать для всех браузеров одинаковые графические эффекты — прозрачность, градиенты, маски и прочее. Это позволило бы создать единообразный интерфейс взаимодействия для пользователей любых браузеров. Однако мне не удалось этого сделать из-за проблем с производительностью. В Windows графика с полным аппаратным ускорением помогает переместить эти интенсивные графические вычисления в GPU. Я добавил режим «Low Fidelity» (Низкое качество), чтобы предоставить пользователям возможность работать с моей демонстрацией в браузерах, не использующих GPU в полную силу. Один положительный «побочный эффект» состоит в том, что таким образом также демонстрируется применение стилей CSS SVG.

Неожиданное «событие переключения»

При поиске различий в поведении браузеров произошло очень интересное для меня, как для разработчика, «событие переключения». В средствах отладки IE9 было несколько серьезных ошибок (теперь исправленных), которые препятствовали помещению в код точек останова при работе с SVG, поэтому я использовал популярную надстройку Firebug для Firefox. Однако в Firefox эта демонстрация выполнялась слишком медленно, поэтому я снова вернулся в Internet Explorer 9, чтобы выполнить отладку.

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

Код

Поскольку о SVG мало известно большинству разработчиков (хотя она является далеко не новой спецификацией), имеет смысл подробнее рассмотреть код и понятия в этой демонстрации.

Структура документа

Первый пример. Большинство браузеров пока не поддерживает SVG в HTML5, поэтому мне пришлось структурировать документ как XHTML со встроенной графикой SVG.

 <!DOCTYPE html>
<html id="demohtml" xmlns="https://www.w3.org/1999/xhtml" class="testdrive">
  <head>
    <title>
      Игральные кости SVG
    </title>
  </head>
  <body id="demobody" onload="Setup()">
    <audio id="sndRemove" volume="1" src="assets/remove.mp3" preload="true"  ></audio>
    <svg  overflow="visible" id="theSVG" xmlns=https://www.w3.org/2000/svg
         xmlns:xlink="https://www.w3.org/1999/xlink" width="100%" height="100%" >
    </svg>
  </body>
</html>
    

Приведенный выше простой <!DOCTYPE html> переводит Internet Explorer 9 в «стандартный режим», в котором SVG поддерживается. Обратите внимание, что SVG встроена непосредственно в HTML. CSS и сценарий привязаны посредством элементов HTML, как и положено.

 <script type="text/javascript" src="demo.js"></script>
<link rel="Stylesheet" type="text/css" href="demo.css" />

На данном этапе у меня есть структуры основного документа html и svg, таблицы стилей и файла скрипта. Далее мне необходимо построить графические элементы, создать стили и написать скрипт для анимаций и взаимодействия с пользователем.

Добавление содержимого

Одним из важных преимуществ и уникальной особенностью сообщества веб-разработчиков является то, что мы называем «копированием/вставкой». Любой разработчик может без труда поискать в Викискладе графические объекты SVG общедоступного домена и использовать их непосредственно в своих приложениях или на веб-сайтах. Существуют другие популярные инструменты для создания нового или изменения существующего содержимого — от общедоступного ресурса Inkscape, который специализируется на SVG, до прочих графических средств Microsoft и Adobe, позволяющих выполнить экспорт в SVG. Игральные кости и кораблик я нашел в открытой коллекции картинок.

Сначала я сохранил эти источники SVG в разных файлах для разделения. К сожалению, работая с браузерами, я столкнулся с несколькими различными проблемами, — от проблем с изменением размеров до проблем с поддержкой SVG, что вынудило меня включить весь код SVG в один файл HTML.

SVG содержит определения <defs>, применяющиеся для описания элементов со стилями и атрибутами, которые можно использовать повторно. Два этих понятия исключительно полезны. Они позволяют мне создать множество изображений игральных костей различных размеров, — тех, которые находятся в стаканчике, или тех, которые крутятся на экране во время игры. Я разместил эти определения из разных файлов в верхней части документа сразу после тега SVG.

 <defs>
    <!-- для левой кости -->
    <linearGradient id="grad21" x1=".445" x2=".554" y1=".442" y2=".555">
        <stop stop-opacity=".9" offset="0" stop-color="#470808"/>
        <stop stop-opacity=".9" offset=".65" stop-color="#700d0d"/>
        <stop stop-opacity=".9" offset="1" stop-color="#8c1111"/>
    </linearGradient>
</defs>

Затем для этих определений создаются ссылки:

 <!-- грани -->
<path d="M 2474 4434 L 4860 2945 C 5009 " fill="url(#grad21)"/>

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

Добавление средств взаимодействия с пользователем и анимации

Одним из наиболее сложных аспектов этой демонстрации является реализация изменения размера. Первым делом я зарегистрировал в коде событие изменения размера и установил размеры <svg> и включенных фрагментов svg. Для простоты я сгруппировал (<g>) их, чтобы иметь возможность изменять размеры и положение по отдельности.

 document.getElementById("theSVG").setAttribute("width", surfaceWidth.toString() + "px");

Здесь следует отметить, что данный код JavaScript знаком веб-разработчикам, поскольку это стандартный JavaScript, работающий с моделью DOM. SVG предлагает собственные методы DOM, которыми я пользуюсь, но, как правило, я придерживаюсь конструкций DOM уровня 2, поскольку участники рабочей группы SVG единодушны в том, что DOM SVG нуждается в пересмотре.

Затем мне потребовалось взять оба статичных изображения игральных костей как фрагменты SVG и написать определенный код для их клонирования, сохранить ссылки в массиве со свойствами, позволяющими управлять их трансформациями для анимационных эффектов, а также убедиться, что физический движок распознает их должным образом. Цикл создания игральной кости довольно прост; он выполняется для необходимого количества костей, клонирует оригинал в DOM и создает массив для управления им.

Примечание. Для экономии места большинство примеров кода даны в сокращенном варианте. Полный код находится на сайте предварительного выпуска платформы (https://ie.microsoft.com/testdrive/Performance/SVGDice/Default.xhtml)

Сначала я клонировал прототип и добавил его в DOM, установив некоторые атрибуты по умолчанию. Следует отметить, что трансформация используется для перемещения игральной кости (translate), поворота кости (rotate) и изменения ее размера (scale).

 // создание экземпляра кости #1 и добавление его в документ SVG
this.die1 = createElement("g");
var tmpChild = this.die1.appendChild(createElement("g"));
var tmpNode = this.die1.appendChild(tmpChild);
tmpNode.appendChild(nodeDie1.cloneNode(true));
// установка некоторых атрибутов по умолчанию
this.die1.setAttribute("id", "die_1_" + number.toString());
this.die1.setAttribute("transform", 
    "translate(" + this.x.toString() + "," + this.y.toString() + ") 
    scale (" + this.scale.toString() + ")");

Здесь я хотел воспользоваться элементом <use>, поскольку это отличный способ клонировать группу фрагментов SVG. К сожалению, элемент <use> по-разному реализован в браузерах, особенно в случае с заданием стилей и событий.

Затем я использую метод SVGDOM getBBox() для захвата размеров игральной кости по мере сжатия каждой из них. Этот метод возвращает SVGRect, который используется в физическом движке для определения столкновения.

 var rectSize = this.die1.getBBox(); // вычисление размеров для использования в физическом движке
this.height = rectSize.height;
this.width = rectSize.width;

Самым приятным открытием при создании этого примера для меня стала подсистема Box2DJS, благодаря которой задача построения физики движения становится сущим пустяком! Эта подсистема используется во многих проектах и теперь доступна веб-разработчикам. Перед тем как создать игральную кость, я фактически сотворил физический мир, в котором будут разворачиваться события:

 function createWorld(width, height) {
    var worldAABB = new b2AABB();

    var world = new b2World(worldAABB, gravity, doSleep);
    createGround(world, width, height);
    // Грань
    createBox(world, 0, 0, 30, height);
    createBox(world, width, 0, 30, height);
    createBox(world, 0, 0, width + 30, 30);
    createBox(world, 0,height , width+30,30);

    return world;
}

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

 // добавление кости в физический движок
this.circleBody = createBall(world, this.xTrans, this.yTrans, this.width);    
// предоставление слегка произвольной начальной скорости
this.circleBody.SetLinearVelocity(initialForce);

Создав элементы взаимодействия с пользователем, позволяющие добавить игральные кости, я удалил кость и потряс стаканчик. Затем я создал таймер и передвинул мир на шаг.

 timer = window.setInterval(DoStuff, 16);
// Передвинуть мир на шаг
world.Step(timeStep, iteration);

Класс Die имеет функцию обновления прототипа, которая вызывается, когда предметы в мире смещаются на один шаг. Основной механизм перемещения кости построен на получении координат от физического движка и установке свойства transform для всех изначально установленных элементов:

 var transFormString = "translate(" + Math.round(this.circleBody.m_position.x)
     + "," + Math.round(this.circleBody.m_position.y) + ") scale (" +
     this.scale.toString() + ") rotate(" + Math.round(this.rotation).toString()
     + "," + Math.round(this.xTrans).toString() + "," +
     Math.round(this.yTrans).toString() + ")";

Теперь у нас есть движущиеся, вращающиеся и соударяющиеся кости.

Следует отметить, что использование атрибута transform не обязательно является самым быстрым способом — все зависит от реализации. Как упоминалось ранее, я не воспользовался SVGDOM, предоставляющей такие методы, как setTranslate() и setRotate(). Метод, выбранный здесь, учитывает потенциальное будущее использование преобразований CSS с переходами CSS и/или анимациями CSS.

Установка стиля графики

Наконец, мне захотелось воспользоваться преимуществом SVG, встроенной в модель DOM, и с помощью CSS изменить оформление сцены. Поскольку первоначальный графический объект был создан в средстве разработки, он содержал значения RGB для цветов и прозрачности.

 <linearGradient id="cgrad2c" x1="1" x2=".17" y1="0" y2=".58">
    <stop stop-opacity=".9" offset="0"  stop-color="#700d0d"/>
    <stop stop-opacity=".9" offset="1" stop-color="#b51616"/>
</linearGradient>

Я заменил эти значения RGB стилями:

 <linearGradient id="cgrad2c" x1="1" x2=".17" y1="0" y2=".58">
    <stop class="diceCorner6"/>
    <stop class="diceCorner7">
</linearGradient>

Это позволило мне создать таблицы стилей для каждого из этих стилей:

 g#classHandler.vegas .diceCorner6 {stop-opacity:.9;offset:0;stop-color:#700d0d;}
g#classHandler.vegas .diceCorner6 {stop-opacity:.9;offset:1;stop-color:#b51616;}

g#classHandler.lowfidielity .diceCorner6 {offset:0;stop-color:#000000;}
g#classHandler.lowfidielity .diceCorner6 {offset:1;stop-color:#000000;}

Затем можно было установить одно свойство класса вверху документа, чтобы изменять все стили документа:

 // set the overall stylesheet via class
document.getElementById("classHandler").setAttribute("class", style);

Это дает пользователю возможность изменять таблицу стилей, даже когда кости вращаются, поскольку для DOM не имеет значения, когда изменяются стили. Аппаратно ускоренная графика в Internet Explorer 9 позволяет таким изменениям происходить очень быстро.

Призыв к действию

Начните работать с SVG в Internet Explorer 9. Последний предварительный выпуск IE9 — практически совершенная платформа для SVG. Поэкспериментируйте с набором функциональных возможностей и сообщите нам об обнаруженных несовместимостях или ошибках с помощью команды «Report Issue» (Сообщить о проблеме) или в Microsoft Connect.

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

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

Патрик Денглер (Patrick Dengler),

старший программный менеджер

Internet Explorer