Группирование и привязка SVG объектов

Подготовили: Евгений Рыжков и Тимур Лисица Дата публикации: 07.12.2010

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

Элемент <g>

Элемент <g> объединяет все дочерние элементы в группу. Зачастую имеет уникальный id. Так же может в себе содержать <title> и <desc> чтобы улучшить доступность для невизуальных браузеров. В дополнение к этому, <g> обеспечивает удобство и сокращение объема кода при использовании стилей: заданный стиль для <g> будет распространятся на все дочерние элементы. В следующем примере избежим дублирования style="fill:none; stroke:black;" для элементов рисунка:

<svg width="240px" height="240px" viewBox="0 0 240 240">
<title>Рисунок группами</title>
<desc>Рисунок дома и людей</desc>
<g id="house" style="fill: none; stroke: black;">
	<desc>Дос с дверью</desc>
	<rect x="6" y="50" width="60" height="60"/>
	<polyline points="6 50, 36 9, 66 50"/>
	<polyline points="36 110, 36 80, 50 80, 50 110"/>
</g>
<g id="man" style="fill: none; stroke: black;">
	<desc>Мужик</desc>
	<circle cx="85" cy="56" r="10"/>
	<line x1="85" y1="66" x2="85" y2="80"/>
	<polyline points="76 104, 85 80, 94 104" />
	<polyline points="76 70, 85 76, 94 70" />
</g>
<g id="woman" style="fill: none; stroke: black;">
	<desc>Тетка</desc>
	<circle cx="110" cy="56" r="10"/>
	<polyline points="110 66, 110 80, 100 90, 120 90, 110 80"/>
	<line x1="104" y1="104" x2="108" y2="90"/>
	<line x1="112" y1="90" x2="116" y2="104"/>
	<polyline points="101 70, 110 76, 119 70" />
</g>
</svg>
использование элемента g

Допускается вложенность группы элементов в другую группу.

Элемент <g> по своей сущности очень напоминает группирование слоев в Adobe Photoshop и Adobe Illustrator.

Элемент <use>

Часто в дизайне встречаются повторяющиеся элементы. Например, рекламный буклет может содержать логотип компании в верхнем левом и нижнем правом углу каждой страницы. В каком-нибудь Adobe Illustrator достаточно один раз нарисовать логотип, сгруппировать все его составляющие, скопировать сгруппированный рисунок и вставлять его сколько угодно раз в нужные места. Элемент <use> предоставляет аналог функции копи-паста для группы элементов, объединенных с помощью <g>.

Чтобы скопировать-вставить определенную группу (она должна иметь id), добавляем элемент <use>, указываем какую группу будем копировать (атрибут xlink:href) и задаем положение копии (относительно положения оригинала). Возьмем предыдущий пример и сделаем копии дома и людей:

...
<use xlink:href="#house" x="70" y="100"/>
<use xlink:href="#woman" x="-80" y="100"/>
<use xlink:href="#man" x="-30" y="100"/>
использование элемента use

Элемент <defs>

В предыдущем примере сложно не заметить недостатки:

  • нужно знать позицию оригинала и отталкиваться от него, а не просто указать нужные координаты;
  • цвета, а точнее все стили, у копий будут таким же как и у оригинала: их нельзя изменить с помощью <use>;
  • при использовании <g> отобразится все сгруппированные элементы. В нашем примере нельзя определить, сгруппировать и «сохранить» все три элемента, а отобразить только, например, дом или мужчину.

Элемент <defs> позволяет решить эти проблемы. Заключаем сгруппированные объекты в <defs> — определяем элементы без их отображения. Спецификация SVG рекомендует группы, которые будут повторно использоваться, заключать в <defs>, чтобы код получился более гибким и компактным. В следующем примере дом, мужчина и женщина определены так, чтобы их верхний левый угол находился в (0, 0) и не был указан цвет заливки. Так как группы находятся внутри <defs>, они не будут отображаться на экране, но будут служить в качестве «шаблонов» для использования в будущем. Добавим еще одну группу couple, которая, использует <use> для групп man и woman. Заметьте, что нижний рисунок не может использовать couple, потому что поменяли местами женщину и мужчину:

<svg width="240px" height="240px" viewBox="0 0 240 240">
<title>Рисуем группами</title>
<desc>На рисунке дом и люди</desc>
<defs>
	<g id="house" style="stroke: black;">
		<desc>Дом с дверью</desc>
		<rect x="0" y="41" width="60" height="60" />
		<polyline points="0 41, 30 0, 60 41" />
		<polyline points="30 101, 30 71, 44 71, 44 101" />
	</g>
	<g id="man" style="fill: none; stroke: black;">
		<desc>Мужик</desc>
		<circle cx="10" cy="10" r="10" />
		<line x1="10" y1="20" x2="10" y2="44" />
		<polyline points="1 58, 10 44, 19 58" />
		<polyline points="1 24, 10 30, 19 24" />
	</g>
	<g id="woman" style="fill: none; stroke: black;">
		<desc>Тетка</desc>
		<circle cx="10" cy="10" r="10" />
		<polyline points="10 20, 10 34, 0 44, 20 44, 10 34" />
		<line x1="4" y1="58" x2="8" y2="44" />
		<line x1="12" y1="44" x2="16" y2="58" />
		<polyline points="1 24, 10 30, 19 24" />
	</g>
	<g id="couple">
		<desc>Мужик и тетка</desc>
		<use xlink:href="#man" x="0" y="0" />
		<use xlink:href="#woman" x="25" y="0" />
	</g>
</defs>

<!-- используем определенные ранее группы -->
<use xlink:href="#house" x="0" y="0" style="fill: #cfc;" />
<use xlink:href="#couple" x="70" y="40" />

<use xlink:href="#house" x="120" y="0" style="fill: #99f;" />
<use xlink:href="#couple" x="190" y="40" />

<use xlink:href="#woman" x="0" y="145" />
<use xlink:href="#man" x="25" y="145" />
<use xlink:href="#house" x="65" y="105" style="fill: #c00;" />
</svg>
использование элемента defs

Посмотреть в живую.

Элемент <use> не ограничен рамками одного SVG документа: атрибут xlink:href может сослаться на любой подходящий файл или адрес в Сети. Это позволяет собрать несколько общих элементов в один SVG файл и использовать в качестве «донора». Например, создаем identity.svg, в котором соберем графику, использующуюся организацией:

<g id="company_mascot">
	<!-- талисман компании -->
</g>
<g id="company_logo" style="stroke: none;">
	<polygon points="0 20, 20 0, 40 20, 20 40" style="fill: #696;" />
	<rect x="7" y="7" width="26" height="26" style="fill: #c9c;" />
</g>
<g id="partner_logo">
	<!-- логотип партнера -->
</g>

и затем ссылаемся на него:

<use xlink:href="identity.svg#company_logo" x="200" y="200" />

Элемент <symbol>

Элемент <symbol> позволяет группировать элементы еще одним способом. В отличии от элемента <g>, <symbol> никогда не отображается: нет необходимости его скрывать с помощью <defs>.

Еще одна особенность <symbol> — это возможность использования атрибутов viewBox и preserveAspectRation, чтобы изображение смогло вписаться в окно просмотра, установленное элементом <use>. В следующем примере видим, что width и height для простой группы игнорируются (для верхних двух прямоугольников), но они используются при отображении <symbol>. Края правого нижнего прямоугольника на обрезаны, потому что для preserveAspectRation задано slice.

<svg width="240px" height="240px" viewBox="0 0 240 240">
<title>Symbols vs groups</title>
<desc>Use</desc>
<defs>
	<g id="octagon" style="stroke: black;">
		<desc>Octagon as group</desc>
		<polygon points="36 25, 25 36, 11 36, 0 25,0 11, 11 0, 25 0, 36 11"/>
	</g>
	<symbol id="sym-octagon" style="stroke: black;" preserveAspectRatio="xMidYMid slice" viewBox="0 0 40 40">
		<desc>Octagon as symbol</desc>
		<polygon points="36 25, 25 36, 11 36, 0 25,0 11, 11 0, 25 0, 36 11"/>
	</symbol>
</defs>

<use xlink:href="#octagon" x="40" y="40" width="30" height="30" style="fill: #c00;"/>
<use xlink:href="#octagon" x="80" y="40" width="40" height="60" style="fill: #cc0;"/>
<use xlink:href="#sym-octagon" x="40" y="80" width="30" height="30" style="fill: #cfc;"/>
<use xlink:href="#sym-octagon" x="80" y="80" width="40" height="60" style="fill: #699;"/>
</svg>
использование элемента symbol

Посмотреть в живую.

Элемент <image>

Если <use> позволяет повторно использовать часть SVG файла, то элемент <image> содержит или SVG файл целиком, или растровый файл (JPEG или PNG). Если использоваться будет SVG файл — атрибуты x, y, width и height устанавливают окно просмотра, в котором будет отображаться содержимое этого файла. Если растровый файл — он будет масштабироваться чтобы соответствовать прямоугольнику, определенному атрибутами. Пример внедрения растрового изображения:

<svg width="310px" height="310px" viewBox="0 0 310 310">
<!--эмулируем тень для эллипса-->
<ellipse cx="154" cy="154" rx="150" ry="120" style="fill: #999999;&quo;/>
<!--основная фигура эллипса-->
<ellipse cx="152" cy="152" rx="150" ry="120" style="fill: #cceeff;"/>
<!-- внедряем картинку: xlink:href - ссылка на растровое изображение; x и y - положение врхнего левого угла image -->
<!-- width и height - размеры image, под которые будет подгонятся реальное изображение -->
<image xlink:href="kwanghwamun.jpg" x="72" y="92" width="160" height="120"/>
</svg>
использование элемента image

Куда дальше

Показать комментарии