Статьи

Использование встроенных SVG с HTML5

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


Вы можете взаимодействовать с элементами SVG, используя методы DOM, как и с другими элементами веб-страницы.

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

Проверьте демо сейчас, чтобы у вас было четкое представление о том, что мы строим.

Как вы, вероятно, знаете, встроенные SVG-файлы соответствуют новым стандартам HTML5, поэтому код, который мы используем в этом руководстве, не будет полностью поддерживаться во всех браузерах. Хотя встроенные SVG теоретически поддерживаются во всех текущих версиях основных браузеров, внутренние анимации и интерактивные эффекты, которые мы будем использовать, пока не так хорошо поддерживаются. Окончательный результат должен работать правильно в текущих версиях Firefox, Chrome и Opera. Как всегда с техникой HTML5, убедитесь, что вы не полагаетесь на эти эффекты ни на каких живых сайтах, над которыми вы работаете, и по возможности включайте альтернативы.

Давайте начнем с создания схемы страницы HTML5, например, так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<script>
 
</script>
<style>
 
</style>
</head>
<body>
 
</body>
</html>

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

1
2
3
<div id=»picHolder»>
 
</div>

Чтобы увидеть, как SVG находится внутри содержащего элемента, добавьте следующее в раздел стиля в заголовке страницы:

1
#picHolder {background:#dedeff;

В элемент контейнера в теле вашей страницы добавьте схему элемента SVG следующим образом:

1
2
3
4
5
6
<svg version=»1.1″
        baseProfile=»full»
        xmlns=»http://www.w3.org/2000/svg»
        height=»100%» width=»100%»>
 
</svg>

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


Видимые фигуры на графике будут определены внутри элемента SVG. Перед этим мы будем работать над разделом defs . Раздел defs — это место, где вы размещаете определения, к которым вы можете позже обратиться при создании ваших фигур. В этом уроке раздел defs будет содержать определения для нескольких градиентных заливок и нескольких теней. Добавьте этот новый раздел внутри элемента SVG:

1
2
3
<defs>
 
</defs>

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

Сначала линейный градиент:

1
2
3
4
<linearGradient id=»backGrad» x1=»0%» y1=»0%» x2=»0%» y2=»100%»>
    <stop offset=»10%» style=»stop-color:#990000; stop-opacity:1″ />
    <stop offset=»90%» style=»stop-color:#cccc00; stop-opacity:1″ />
</linearGradient>

Этот градиент будет указан как заливка для фоновой прямоугольной области. Атрибуты x1 и y1 представляют начальные точки градиента внутри заполненной фигуры, при этом градиент разворачивается оттуда до точки, представленной x2 и y2 . В этом случае градиент будет проходить сверху вниз. Стоп-элементы представляют цветные точки в градиенте. Первый заявляет, что 10% от начала градиента будет сплошным темно-красным цветом, а второй останавливается, что 90% от конца градиента будет желтого цвета. Между этими двумя точками градиент будет смешивать цвета друг с другом. Оба цвета имеют полную непрозрачность.

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

1
2
3
4
5
6
7
8
<radialGradient id=»recordGrad» cx=»50%» cy=»50%» r=»50%» fx=»50%» fy=»50%»>
    <stop offset=»30%» style=»stop-color:#000000; stop-opacity:1″ />
    <stop offset=»35%» style=»stop-color:#222222; stop-opacity:1″ />
    <stop offset=»45%» style=»stop-color:#000000; stop-opacity:1″ />
    <stop offset=»85%» style=»stop-color:#000000; stop-opacity:1″ />
    <stop offset=»95%» style=»stop-color:#222222; stop-opacity:1″ />
    <stop offset=»100%» style=»stop-color:#000000; stop-opacity:1″ />
</radialGradient>

Радиальный градиент начинается с внутренней части круга, при этом самые внутренние и внешние части круга, определенные как cx , cy , fx и fy , перечислены вдоль радиуса. В этом случае радиальный градиент будет занимать всю форму круговой записи. Основная часть записи будет черной, с двумя кольцами чуть более светлого цвета, представляющими более гладкие участки в центре записи и по ее краям. Мы также разместим лейбл на пластинке в ее центре, поэтому первый патч более светлого цвета на пластинке появится сразу за ее пределами. Добавьте градиентную заливку метки следующим образом:

1
2
3
4
<linearGradient id=»labelGrad0″ x1=»0%» y1=»0%» x2=»100%» y2=»0%»>
    <stop offset=»40%» style=»stop-color:#000099; stop-opacity:1″ />
    <stop offset=»60%» style=»stop-color:#009900; stop-opacity:1″ />
</linearGradient>

Это простой линейный градиент, который будет использоваться в качестве заливки для круглой метки записи. Однако обратите внимание, что идентификатор градиента имеет ноль на конце. Это связано с тем, что мы собираемся добавить интерактивную функцию, позволяющую пользователю «изменить запись». Функция JavaScript будет переключаться между диапазоном градиентной заливки для элемента метки. Для этого добавьте еще пару градиентов:

01
02
03
04
05
06
07
08
09
10
11
12
13
<linearGradient id=»labelGrad1″ x1=»0%» y1=»0%» x2=»100%» y2=»0%»>
    <stop offset=»0%» style=»stop-color:#990000; stop-opacity:1″ />
    <stop offset=»20%» style=»stop-color:#ff6600; stop-opacity:1″ />
    <stop offset=»40%» style=»stop-color:#cccc00; stop-opacity:1″ />
    <stop offset=»60%» style=»stop-color:#009900; stop-opacity:1″ />
    <stop offset=»80%» style=»stop-color:#000099; stop-opacity:1″ />
    <stop offset=»100%» style=»stop-color:#990099; stop-opacity:1″ />
</linearGradient>
         
<linearGradient id=»labelGrad2″ x1=»0%» y1=»0%» x2=»100%» y2=»0%»>
    <stop offset=»0%» style=»stop-color:#330033; stop-opacity:1″ />
    <stop offset=»100%» style=»stop-color:#cc00cc; stop-opacity:1″ />
</linearGradient>

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

1
2
3
4
5
<linearGradient id=»shineGrad» x1=»0%» y1=»0%» x2=»100%» y2=»100%»>
    <stop offset=»35%» style=»stop-color:#000000; stop-opacity:0″ />
    <stop offset=»50%» style=»stop-color:#ffffff; stop-opacity:0.2″ />
    <stop offset=»65%» style=»stop-color:#000000; stop-opacity:0″ />
</linearGradient>

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

1
2
3
4
<radialGradient id=»dialGrad» cx=»50%» cy=»60%» r=»60%» fx=»40%» fy=»40%»>
    <stop offset=»30%» style=»stop-color:#cccccc;stop-opacity:1″ />
    <stop offset=»100%» style=»stop-color:#333333;stop-opacity:1″ />
</radialGradient>

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

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

1
2
3
4
<filter id=»recordShadow» x=»0″ y=»0″ width=»200%» height=»200%»>
    <feOffset result=»offOut» in=»SourceAlpha» dx=»5″ dy=»5″ />
    <feGaussianBlur result=»blurOut» in=»offOut» stdDeviation=»3″ />
</filter>

Этот собирается появиться позади области записи. Свойства x , y , width и height относятся к положению и размерам в фигуре с использованием этого фильтра. Смещение определяет тень относительно исходной формы. Размытие препятствует тому, чтобы смещенная форма была сплошным цветом, поэтому она выглядит как тень. В этом случае будет отображаться только тень, а не сама форма — тень будет определяться выделенной формой, которая будет размещена за формой записи. Для пользовательских элементов управления, которые являются круглыми и металлическими, мы также хотим отбрасывать тень, но мы хотим, чтобы сама фигура также отображала:

1
2
3
4
5
<filter id=»dialShadow» x=»0″ y=»0″ width=»200%» height=»200%»>
    <feOffset result=»offOut» in=»SourceAlpha» dx=»2″ dy=»2″ />
    <feGaussianBlur result=»blurOut» in=»offOut» stdDeviation=»1″ />
    <feBlend in=»SourceGraphic» in2=»blurOut» mode=»normal» />
</filter>

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


Достаточно подготовки; давайте продолжим с графикой! Каждый элемент, который вы добавляете в тело SVG, будет отображаться поверх ранее перечисленных элементов, поэтому мы будем работать снизу вверх, начиная с фигур сзади и заканчивая фигурами спереди.

Сначала добавьте прямоугольник для фона:

1
<rect width=»90%» height=»90%» x=»5%» y=»5%» fill=»url(#backGrad)» />

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

Далее снизу идет тень на запись, используя один из созданных нами фильтров тени:

1
<circle cx=»50%» cy=»50%» r=»33%» fill=»#000000″ filter=»url(#recordShadow)» />

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

Далее идет сама запись:

1
<circle cx=»50%» cy=»50%» r=»33%» fill=»url(#recordGrad)» />

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

На вершине записи находится ее лейбл, поэтому добавьте его следующим

1
<circle id=»recordLabel» cx=»50%» cy=»50%» r=»10%» fill=»url(#labelGrad0)» />

Круг метки имеет ту же центральную точку, что и пластинка, через которую он простирается примерно на треть пути. Мы начнем с первой из опций градиента метки, которые мы определили, и позже мы реализуем переключение между ними пользователем — мы включаем здесь атрибут ID, чтобы ссылаться на этот элемент в JavaScript.

Теперь давайте добавим блеска в начало записи:

1
<circle id=»shine» cx=»50%» cy=»50%» r=»32%» fill=»url(#shineGrad)» />

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

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

1
<circle cx=»50%» cy=»50%» r=»1%» fill=»url(#dialGrad)» filter=»url(#dialShadow)» />

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

И последнее, но не менее важное: пользователям нужна небольшая кнопка для управления изменением записи, используя ту же заливку и фильтр, что и для шпинделя:

1
2
3
<circle cx=»83%» cy=»83%» r=»3%» fill=»url(#dialGrad)» filter=»url(#dialShadow)»>
 
</circle>

На этот раз вместо самозакрывающегося элемента мы разделяем открывающую и закрывающую метки круга. Это связано с тем, что мы собираемся анимировать кнопку, когда пользователь нажимает на нее, и будут включать эффект анимации между этими тегами. Обратите внимание, что мы смогли повторно использовать элементы fill и filter из раздела defs . Вот начальный вид рисунка после того, как размеры страницы на месте:

внешний вид проигрывателя

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

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

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

Внутри элемента формы кнопки, между открывающими и закрывающими тегами окружности, мы добавили анимационное преобразование следующим образом:

1
2
3
4
5
6
7
8
<animateTransform
   attributeType=»XML»
   attributeName=»transform»
   type=»translate»
   from=»0, 0″ to=»1, 1″
   dur=»0.1s» begin=»click»
   repeatCount=»1″
   />

AnimateTransform применяется к атрибуту XML внутри элемента, в котором он появляется. В этом случае это преобразование с переводом. Атрибуты from и to представляют начальную и конечную позиции элемента — они относительно его начальной позиции, поэтому кнопка будет перемещаться вправо и вниз на один пиксель. Преобразование начнется, когда пользователь щелкнет, пройдет более одной десятой секунды и выполнится один раз. Кнопка вернется в исходное положение после завершения анимации. Совет: чтобы сохранить элемент в конечной позиции после анимации, укажите fill = «freeze» .

Теперь для вращения записи. AnimateTransform применяется к элементу SVG, но нам нужно, чтобы вращение применялось к более чем одному элементу — в частности, к записи и метке (не к блеску или тени). Вместо того, чтобы создавать отдельные анимации для каждого и выполнять их одновременно, мы можем использовать одно преобразование, группируя эти элементы вместе. Перед элементом круга, представляющим запись (с «recordGrad» в качестве ее заполнения), добавьте открывающий тег группы:

1
<g>

После круга, представляющего метку, закройте группу:

1
</g>

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

1
2
3
4
5
6
7
8
<animateTransform id=»spinTrans»
   attributeType=»XML»
   attributeName=»transform»
   type=»rotate»
   by=»360, 1, 1″
   dur=»1s»
   repeatCount=»indefinite»
   />

На этот раз анимированный эффект представляет собой поворотное преобразование. Элемент будет вращаться на 360 градусов, и, чтобы добавить к эффекту, он будет перемещаться вправо и вниз на один пиксель при каждом повороте в течение одной секунды, повторяясь бесконечно. Это преобразование также будет включать в себя атрибут from , поскольку необходимо указать начальную позицию вращающихся элементов. Если вы не укажете эту позицию, элементы будут вращаться вокруг точки 0, 0 по умолчанию. Однако в настоящее время вы не можете предоставить относительные (то есть процентные) значения для этих атрибутов, только фиксированные значения. По этой причине мы собираемся установить атрибут from, когда мы указываем размеры SVG в JavaScript.


Теперь давайте реализуем наши интерактивные функции: нажмите кнопку, чтобы изменить запись, и нажмите запись, чтобы замедлить ее.

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

1
2
3
4
//keep track of current record label
var currLabel = 0;
//alter this for a different number of labels
var numLabels = 3;

Теперь внутри открывающего тега для элемента круга, представляющего кнопку (которая теперь имеет анимацию между своими тегами), добавьте следующий прослушиватель события click:

1
onclick=»changeRecord()»

Вернувшись в раздел сценария head, добавьте схему функции:

1
2
3
function changeRecord() {
 
}

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

1
2
3
4
5
6
7
8
//move to next label
currLabel++;
 
//reset if at highest number
if (currLabel > numLabels — 1) currLabel = 0;
 
//set the fill attribute to the next gradient
document.getElementById(«recordLabel»).setAttribute(«fill», «url(#labelGrad»+currLabel+»)»);

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

альтернатива звукозаписи

Теперь добавьте следующие атрибуты события в элемент shine записи (с «shineGrad» в качестве его заполнения), так как мы собираемся использовать события мыши вверх и вниз для запуска замедления записи и ее повторного ускорения:

1
onmousedown=»onRecord()» onmouseup=»offRecord()»

Вернувшись в раздел сценариев, добавьте функцию, когда пользователь нажимает на запись:

1
2
3
4
//function called when user is pressing record
function onRecord() {
 
}

Внутри этой функции мы можем замедлить анимацию вращения записи, изменив атрибут продолжительности animateTransform . Мы также изменяем непрозрачность блеска, чтобы создать впечатление нажатия:

1
2
3
4
//slow the animation duration
document.getElementById(«spinTrans»).setAttribute(«dur», «5s»);
//decrease the shine opacity
document.getElementById(«shine»).style.opacity=»0.7″;

Когда пользователь выпускает запись, мы хотим, чтобы она вернулась к нормальной скорости и внешнему виду, поэтому добавьте функцию «мыши вверх»:

1
2
3
4
5
6
7
8
//function called when user releases record
function offRecord() {
    //reset to normal speed
    document.getElementById(«spinTrans»).setAttribute(«dur», «1s»);
 
    //set opacity back to normal
    document.getElementById(«shine»).style.opacity=»1.0″;
}

Теперь мы наконец можем установить общий размер SVG. В верхней части раздела скрипта добавьте новую переменную:

1
2
//desired size of SVG
var size = 300;

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

1
2
3
4
5
6
7
8
9
//function to set SVG dimensions
function setSize() {
    //set css and transform size
    var holder = document.getElementById(«picHolder»);
 
    holder.style.height=size+»px»;
    holder.style.width=size+»px»;
    document.getElementById(«spinTrans»).setAttribute(«from», «0, «+size/2+», «+size/2+»»);
}

Мы устанавливаем размер на элемент div . Найдите минутку, чтобы взглянуть на последнюю строку в этой функции. Поскольку анимация с поворотным преобразованием не может использовать относительные процентные значения, мы должны установить элемент from с помощью переменной размера (деленной на два для центральной точки записи). С 300 в качестве размера SVG, вот как будет выглядеть преобразование с фиксированными значениями:

1
2
3
4
5
6
7
8
9
<animateTransform id=»spinTrans»
   attributeType=»XML»
   attributeName=»transform»
   type=»rotate»
   from=»0, 150, 150″
   by=»360, 1, 1″
   dur=»1s»
   repeatCount=»indefinite»
   />

Если вы хотите использовать фиксированные значения в SVG, вы можете это сделать. Мы используем эту технику только для демонстрации использования относительных измерений. Наконец, вызовите эту функцию в конце раздела скрипта:

1
window.addEventListener(«DOMContentLoaded», setSize, false);

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

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