«Сущность SVG» открывает двери в мир богатого языка, который позволяет взглянуть на графику в веб с новой стороны. Масштабируемая Векторная Графика (Scalable Vector Graphics) — основанный на XML язык описания графики. Является текстом, и как любой текст, может быть прочитан как человеком, так и поисковым роботом. К тому же SVG не зависит от платформы. Этот язык дает огромную власть дизайнерам и веб разработчикам, которые умеют с ним обращаться. И эта книга помогает научится пользоваться этой властью.
Книга написана для веб разработчиков, которые хотят создавать динамическую графику на своих веб сайтах, получая какие-то данные от пользователя.
Об авторе
David Eisenberg — программист и преподаватель из Сан-Хосе, Калифорния. Он разработал курсы по CSS, Javascript, CGI и XML. Пишет статьи для xml.com и alisapart.com.
Дэвид — это талант в объяснении, обучении и подаче материала. После изучения его материалов вопросов остается очень мало, если таковые вообще остаются.
О переводе
«Сущность SVG» обошла стороной русскоязычные издательства. И судя по всему, к нам она уже не попадет (год издания 2002). Чтобы исправить эту вопиющую несправедливость, эту дискриминацию отечественных веб разработчиков, мы решили своими силами перевести книгу на русский. Спасибо нам )).
Если тебе встретится кривая фраза в переводе, помни, что мы не профессиональные переводчики и нам позволительно немного грешить. А еще лучше напиши, где ошибка, чтобы мы исправили. Перевод будем по ходу дополнять нашими знаниями и примерами с учетом современных веб тенденций и реалий.
О примерах
Помни, что SVG поддерживается не всеми браузерами. Поэтому для просмотров примеров используй те, которые его поддерживают. Сами примеры отображаются в обычном HTML документе. Почему так можно прочитать в статье «Внедрение SVG в HTML».
Начнем
SVG (Scalable Vector Graphics — Масштабируемая Векторная Графика), является приложением к XML, которое дает возможность представлять графическую информацию в компактной, портативной форме. Интерес к графике SVG очень быстро возрастает, а инструменты для создания и просмотра файлов SVG предлагаются большинством компаний. Начнем мы со знакомства с двумя системами компьютерной графики. А так же узнаем как SVG соприкасается с миром графики. В конце главы рассмотрим коротким пример, в котором используется много понятий, на которых мы детально остановимся в последующих главах.
Графические системы
Существуют две основные системы для отображения графической информации на компьютере — растровая и векторная графика.
Растровая графика
В растровой графике картинка представлена как прямоугольная область, состоящая из множества точек, расставленных по своим местам. Такая точка на экране называется пиксель.
Прямоугольник в растровой графике
Каждый пиксель отображается своим цветом. Такая серия пикселей называется растром (bitmap) и зачастую храниться в сжатом формате. Так как большинство современных отображающих устройств являются растровыми, отображение такой картинки требует использование программы для просмотра, которая делает немного больше, чем просто распаковывает растровое изображение и передает его на экран.
Векторная графика
В системе векторной графики изображение описывается как серия геометрических форм. Вместо того, чтобы получить набор пикселей, векторная программа получает команды и рисует образ по определенному набору координат.
Прямоугольник в векторной графике
Если Вы планируете сделать рисунок на клетчатой бумаге, в растровой графике необходимо описать, какая клетка будет заполнена каким цветом. В векторной графике нужно задать начальную, конечную координаты, и выбрать тип линии, которая их соединит. Некоторые описывают векторную графику как набор инструкций для черчения, в то время как растровая графика — это точки разного цвета в определенных местах.
Векторная графика «понимает», чем она является: квадрат «знает», что он квадрат, а текст «в курсе», что он текст. Это потому, что в векторной графике изображение представлено в виде объектов, а не набора пикселей. Векторные объекты могут менять свои цвет и форму, в то время, как растровое изображение — нет. В векторном изображении легко найти текст, независимо от его цвета, шрифта и положения.
Еще способ понять разницу между растровой векторной графикой, если представить растровую графику как рисунок на холсте, а векторную — в виде линий и форм, сделанных из тянущегося материала.
Применение растровой графики
Растровая графика наиболее подходящая для использования в фотографиях, которые крайне редко состоят из отдельных линий или кривых. Сканированные изображения часто сохраняются как растровый рисунок даже если изначально были сделаны как векторный рисунок — мы хотим сохранить рисунок как единое целое, не думая об его отдельных элементах. Факс, например, не определяет, что вы нарисовали — он просто передает пиксели из одного места в другое в форме растрового изображения.
Инструменты для создания изображения в растровой форме более распространены и, в общем, проще в использовании, чем инструменты для векторной графики. Существует много способов сжать и сохранить растровое изображение, и все они доступны. Широко доступны библиотеки программ для чтения и создания изображений в сжатых форматах, таких как JPEG, GIF, PNG. Существует некоторые причины, почему веб браузеры (до прихода SVG) поддерживали только растровые изображения.
Применение векторной графики
Векторная графика используется в:
CAD программах, где очень важна точность и возможность увеличения масштаба изображения, чтобы увидеть детали;
такие программы, как Abobe Illustrator, используемые для создания графики, которая будет печататься на принтерах с высоким разрешением;
Adobe PostScript язык для печати и создания рисунков — каждый символ, который Вы печатаете, описан в виде линий и кривых;
основанная на векторе система Macromedia Flash для создания анимации, презентаций и сайтов.
Именно потому, что большинство этих файлов кодируются двоичным форматом или плотно упакованный битовый поток (bitstreams), для пользовательского агента очень сложно разобрать вставленный текст, а серверу сложно динамично создать файл векторного изображения на основании внешних данных. Большинство векторных рисунков являются запатентованными, а коды для их просмотра или создания — недоступны (прим. ред. — так было в 2002 году, сейчас ситуация меняется. Есть целые сайты с бесплатно доступными изображениями в SVG формате).
Масштабируемость
Хотя векторная графика пока еще не так популярна как растровая, она имеет одну особенность, которая делает ее бесценной во многих приложениях — возможность изменять масштаб изображения без потерь в качестве. Для примера, возьмем два изображения кота. Оба рисунка отображаются на экране при разрешении 72 пикселя на дюйм.
Кот в растровом изображении
Кот в векторном изображении (png картинка результата svg рендеринга)
При увеличении растрового изображения, необходимо как-то растянуть каждый пиксель. Наиболее простой способ — при увеличении в 4 раза, увеличить каждый пиксель в 4 раза. Результат, как видно ниже, не очень лицеприятный:
Результат увеличения растрового изображения
Чтобы исправить ситуацию можно попробовать такие техники как «выделение контуров» и «подавление помех». Но эти техники трудоемки и, в случае автоматической реализации, ресурсоемки. Более того, так как все пиксели в рисунке безымянны, нет гарантии, что алгоритм сможет правильно определить края рисунка.
Результат увеличения растрового изображения с подавлением помех
Чтобы увеличить векторное изображение в четыре раза, просто даем программе команду увеличить все координаты на 4 и перерисовать рисунок. Результатом будет изображение, у которого закругления и сглаженные углы отображены с ощутимо меньшим эффектом ступенек:
Результат увеличения векторного изображения
Создание SVG графики
В этом разделе мы создадим SVG файл, который отобразит картинку кота, которую вы видели ранее. Этот пример поможет представить о чем пойдет речь детально в последующих главах. Данный файл будет служить хорошим примером того, как писать SVG файлы.
Структура документа
Первой строкой будет XML-декларация, как и у любого другого XML-документа. Затем последует определение DOCTYPE. Корневой элемент <svg> определяет ширину (width) и высоту (height) рисунка в пикселях. Содержание элемента <title> пользователь увидит в строке заголовка браузера или в качестве всплывающей подсказки при наведении курсора мыши на рисунок. Элемент <desc> позволяет вам сделать полное описание рисунка (прим. ред. — это описание смогут прочитать поисковые роботы и альтернативные (невизуальные) пользовательские агенты).
Основные фигуры
Мы рисуем морду кота добавляя элемент <circle>. Атрибуты элемента точно определяют центр круга (х и y координаты) и радиус. Точка (0.0) является верхним левым углом рисунка. Координаты х растут по мере того, как Вы двигаетесь горизонтально вправо, координаты у растут по мере того, как Вы двигаетесь вертикально вниз.
Расположение круга и его размер — это часть структуры рисунка. Цвет, которым нарисован рисунок — часть его представления. Так как мы знакомы с XML приложениями, нам хочется разделить структуру и представление для максимальной гибкости. Информация представления содержится в атрибуте style. Его значение будет представлять собой серию пар «свойство: значение» представления. Для контура используем черный цвет, а цвет заливки устанавливаем в none, чтобы сделать морду прозрачной.
Шаг 1 — основная фигура в нашем примере — круг
Стили как атрибуты
Нарисуем еще два круга для глаз. Хотя цвета их заливки и контура являются частью презентации (оформления), SVG позволяет Вам определить их в качестве индивидуальных атрибутов. В данном примере мы задаем цвета заливки и контура как два отдельных атрибута, без использования атрибута style. Таким вариантом, конечно, лучше не злоупотреблять, а в идеале вообще не использовать, но об этом в последующих главах. Тут такой вариант используется только в качестве демонстрации, что SVG и так умеет.
Заметка
Для сокращения кода в примере, выкинем XML и DOCTYPE декларации.
Шаг 2 — имеем контур морды и глаза
Группируем графические объекты
Теперь добавляем нашему коту усы с правой стороны при помощи двух элементов <line>. Мы будем работать с этими усами как с единым элементом (сейчас вы поймете почему). Итак, мы заключаем их в группирующий элемент <g> и задаем ему идентификатор (id). Линия определяется координатами х и у начальной точки (атрибуты х1 и у1) и конечной (х2 и у2).
Шаг 3 — рисуем усы
Трансформируем систему координат
Сейчас мы применим <use> к группе усов справа и трансформируем ее в усы с левой стороны. Для этого сначала меняем систему координат умножая x-координаты на -1 в значении scale атрибута transform. Это значит, что точка с координатами (75,95) получит координаты (-75, 95). В новой системе координаты возрастают влево. В итоге, чтобы «клонированные» усы оказались на нужном месте, нам необходимо перенести (translate) систему координат на 140 пикселей (ширина всего нашего SVG-холста) вправо, в отрицательном направлении.
Шаг 4 — усы с обоих сторон
Значения атрибута transoform представляют собой список трансформаций, которые следуют друг за другом и разделяются пробелом.
Другие базовые фигуры
Тут рисуем уши и рот при помощи элемента <polyline> (ломанная линия), который использует пары значений координат х и у для указания точек линии. Для перечисления этих точек используется атрибут points: пары значений точек линии между собой разделяются запятыми.
Шаг 5 — уши и рот
Маршруты
Все основные фигуры — это всего лишь сокращения более общего элемента <path>. Сейчас мы им воспользуемся чтобы добавить нос коту. <path> определяет последовательность линий и кривых (маршрут), в наиболее компактной форме.
Маршрут для носа можно прочитать так: перейти к координатам (75,90), нарисовать линию к координатам (65,90), нарисовать эллиптическую дугу с радиусом по х = 5 и радиусом по у = 10, и закончить снова в точке с координатами (75,90).
Шаг 6 — нос
Текст
И наконец, так как этот кот нарисован достаточно «криво», есть вероятность, что не все догадаются, что это — кот. Для таких добавим подпись текстом. В этом нам поможет элемент <text>. Атрибуты х и у определяют положение текста. В атрибуте style можно задать имя используемого шрифта, его размер, цвет и прочее свойства отображения. В отличии от других элементов, которые нам встретились в этом примере, <text> является элементом-контейнером. Его содержимое — это текст, который мы хотим показать.
Этим мы заканчиваем наш краткий обзор SVG. В последующих главах мы исследуем его (SVG) значительно глубже.
Координаты
Мир SVG — это бесконечный холст. В этой главе мы обсудим как дать понять браузеру какая именно часть этого холста Вам интересна, каковы размеры этой части и как найти точки на этом участке.
Область просмотра
Участок документа, который будет использоваться для отображения SVG-документа, называется областью просмотра. Его размер можно задать с помощью атрибутов width и height элемента <svg>.
Значением данного атрибута может быть просто число, без указания единиц измерения. Такая запись будет соответствовать пикселям. Вы также можете явно задать единицы измерения ширины и высоты:
em
размер относительно размера шрифта, 1em обычно равен высоте символа
ex
высота буквы x
px
пиксели
рt
точка (1/72 дюйма)
рс
picas (1/6 дюйма)
cm
сантиметры
mm
миллиметры
in
дюймы
Оба варианта определяют область в 200 пикселей шириной и 150 пикселей высотой.
Область шириной в 2 сантиметра и высотой 3 сантиметра.
Можно, хотя это необычно, смешивать единицы измерения. в этом примере определяем участок шириной 2 сантиметра и 36 точек высотой.
Если у Вас один элемент <svg> вложен в другой <svg> элемент, размеры вложенного можно задать в процентах, относительно размеров родителя. Пример вложения увидим в последующих главах. (прим. ред. — вообще <svg> может быть вложен не только в <svg> элемент: в HTML5 можно напрямую вставлять SVG-документ в HTML-документе. Поэтому более справедливым будет сказать, что размеры в процентах могут быть относительно родителя, которым может оказаться любой HTML-контейнер).
Использование системы координат по умолчанию
По умолчанию для элемента <svg>, просмотрщик устанавливает систему координат с двумя осями: X и Y. Значение по оси X (х-координата), увеличивается, если Вы двигаетесь вправо. Для оси Y (у-координата), увеличивается, если двигаетесь вниз. Верхний левый угол графического окна имеет х- и у-координаты равные нулю (*). Эту точку, (0, 0) еще называют началом.
Система координат является чисто геометрической системой. Точки не имеют ни ширины, ни длины, а линии координатной сетки считаются бесконечно тонкими. Мы еще вернемся к данному вопросу в последующих главах.
* — в данной книге мы пишем координаты в скобках парами: х- и у-координата, где х-координата стоит первой. Т.е., (10, 30) — это 10 по оси X и 30 по — Y.
Определим область просмотра в 200 пикселей шириной и 200 пикселей высотой. После чего нарисуем прямоугольник, верхний левый край которого имеет координаты (10, 10). Ширина прямоугольника будет 50 пикселей, а высота 30.
Прямоугольник с использованием координат по умолчанию
Даже если Вы вообще не определили единицы измерения в целом, можно их использовать напрямую для SVG элементов:
Если размеры области просмотра заданы в явных единицах измерения, это никак не влияет на остальные элементы. В следующем примере задаем область просмотра с размерами в мм. Прямоугольнику размеры указываем без единиц измерения, при этом его размеры будут пикселях.
Размеры области просмотра с единицами измерения, у прямоугольника — нет
Определяем пользовательскую систему координат
В приведенных примерах выше, цифры без единиц измерения считались пикселями. Но это не всегда то, что Вам нужно. Например, Вам хочется установить систему, где бы каждая координата представляла бы 1/16 см (это не образец хорошего дизайна — наследовать не нужно :) ). В данной системе, каждая грань квадрата 40 на 40 будет равна 2.5 см.
Для решения таких задач служит атрибут viewBox элемента <svg>. Значение этого атрибута состоит из четырех цифр, которые задают минимальные значения х- и у-координат, а так же пределы значений по осям.
Итак, для того, чтобы установить систему координат в 16-единиц-на-1-сантиметр для области рисования с размерами 4 сантиметра на 5, используем следующий код:
В следующем примере нарисуем домик, котрый будет отображен в пересчитанной системе координат:
Сетка координат и более темные цифры показывают новую систему координат пользователя. Более светлые цифры расположены с интервалом в 1 сантиметр.
Новая система координат пользователя
Цифры в значении атрибута viewBox, могут быть разделены запятыми или пробелами. Если ширина или длина равна нулю, графика не будет отображаться. Это является ошибкой при определении отрицательного значения для ширины или высоты viewBox.
Сохранение пропорций
В предыдущем примере, пропорции или соотношение ширины и высоты графического окна и viewBox были идентичными (4/5=64/80). Что же происходит, если пропорции области просмотра и viewBox будут разными? Например, где пропорциональность viewBox равна 1/1, а у области просмотра — 1/3?
SVG в такой ситуации может пойти тремя путями:
равномерно изменить размеры изображения согласно наименьшей грани области просмотра, чтобы изображение полностью вместилось. В нашем примере, изображение потеряет половину своей ширины и высоты (см. примеры ниже).
равномерно изменить размеры изображения согласно наибольшей грани области просмотра и обрезать части, которые будут находиться за пределами области просмотра. В нашем примере, изображение станет в полтора раза больше своей ширины и высоты (см. примеры ниже).
растянуть/сжать изображение, чтобы оно точно вписывалось в область просмотра (см. примеры ниже).
В первом случае, так как изображение будет меньше области просмотра по одной из осей, поэтому нужно будет задать, где его разместить. В примере, картинка будет равномерно масштабироваться (уменьшаться) пока значение и ширины, и высоты не будут превышать 45 пикселей. Ширина уменьшенной картинки идеально совпадает с шириной области просмотра. Но сейчас нужно решить как картинка будет выровнена по вертикали относительно окна просмотра: по нижнему краю, по центру или по верхнему.
Во втором случае, так как изображение будет больше, чем область просмотра по одной из осей, Вам будет необходимо определить, какая часть будет обрезана. В примере, картинка будет равномерно масштабироваться пока значения и ширины, и высоты картинки не будут меньше 135 пикселей. В итоге высота картинки идеально совпадает с высотой области просмотра. Но Вам необходимо решить какую невмещающуюся часть картинки обрезать, чтобы она поместилась область просмотра шириной 45 пикселей: правый край, левый или оба.
Задаем выравнивание с preserveAspectRatio
Атрибут preserveAspectRatio позволяет определить выравнивание отмасштабированного изображения относительно области просмотра. Так же может сделать так чтобы изображение полностью соответствовало области просмотра или были обрезаны части изображения.
preserveAspectRatio="alignment [meet | slice]"
где alignment определяет ось и выравнивание. Принимает одно из значений: xMinYMin, xMinYMid, xMinYMax, xMidYMin, xMidYMid, xMidYMax, xMaxYMin, xMaxYMid или xMaxYMax. Эти значения приводят к одному из способов выравнивания, которые расписаны в таблице ниже.
Заметка
y-выравнивание начинается с заглавной буквы для удобство восприятия, т.к. x- и y- выравнивания пишутся одним словом.
Выравнивание по оси X
значение
действие
xMin
выровнять в соответствии с минимальным значением x viewBox — левая граница области просмотра.
xMid
выровнять в соответствии с центральной точкой по x viewBox — центр по оси X в области просмотра.
xMax
выровнять в соответствии с максимальным значением x viewBox — правая граница области просмотра.
Выравнивание по оси Y
значение
действие
YMin
выровнять в соответствии с минимальным значением y viewBox — верхняя граница области просмотра.
YMid
выровнять в соответствии с центральной точкой по y viewBox — центр по оси Y в области просмотра.
YMax
выровнять в соответствии с максимальным значением y viewBox — нижняя граница области просмотра.
Итак, если Вы хотите, чтобы изображение с viewBox= "0 0 90 90" полностью вместилось в область просмотра с width=45 и height=135, располагалось в верхнем левом углу, необходимо написать:
Заметка
В данном примере изображение получит ширину равную ширине области просмотра. В таком случае визуально получили бы такой же результат даже если задали значения xMidYmin или xMaxYMin. Но для большей корректности следует указывать одинаковые значения (min-min, mid-mid, max-max).
Но все это достаточно абстрактно и туманно. Нужны конкретные примеры, которые разъяснили бы всю эту мутную теорию. Вот несколько таких, которые показывают Вам, как срабатывает выравнивание в комбинации со спецификаторами meet и slice.
Использование спецификатора meet
Спецификатор meet указывает, что изображение должно сохранить свои пропорции и быть полностью видимым. Следующие примеры демонстрируют действие meet вместе с различными вариантами выравнивания:
Выравнивание в сочетании с meet
Использование спецификатора slice
Спецификатор slice означает, что изображение должно сохранить свои пропорции и будет отмасштабировано в соответствии с максимальным граничным значением области просмотра. Части изображения, которые не помещаются в область просмотра, будут обрезаны.
Выравнивание в сочетании со slice
Использование спецификатора none
Спецификатор none означает, что изображение должно полностью отобразится в области просмотра даже если придется исказить пропорции изображения.
Выравнивание в сочетании с none
Вложенные системы координат
Вы можете создать новую область просмотра со своей системой координат в любое время, вложив еще один элемент <svg> элемент в Ваш SVG-документ. Создается эффект «мини-холста», поверх которого Вы можете рисовать. Мы использовали данную технику для создания этой иллюстрации:
Вместо того, чтобы рисовать прямоугольники, потом изменять масштаб и положение кота внутри каждого из них (грубый метод), мы предпринимаем следующие действия:
рисуем голубые прямоугольники на основном холсте;
для каждого прямоугольника определяем новый элемент <svg> с соответствующим атрибутом preserveAspectRatio;
рисуем кота на новых холстах (применяем <use>) и пусть SVG делает всю тяжелую работу.
На более простом примере разберем как можно применить вложенные <svg>. Нарисуем две фигуры: круг и прямоугольник на основном холсте. И добавим новый холст, который будет расположен внутри прямоугольника.
Сначала создаем SVG для основной системы координат и для круга. Обратите, внимание, что пользовательская система координат совпадает с основной:
Теперь рисуем границы, которыми обозначим, где будет новое окно просмотра:
Сейчас, добавляем еще один элемент <svg> для новой области просмотра. Вдобавок к определению viewBox, width, height и preserveAspectRatio, Вы можете также определить атрибуты х и у. Это будут координаты положения нового холста относительно родительского <svg> элемента. По умолчанию они равны нулю.
Новая система координат вложенного <svg> позволит добавить круг точно в прямоугольник без изменений кода для круга:
Основные фигуры. Линии.
После того, как система координат установлена в <svg> элементе, можно начинать рисовать. В данной главе мы покажем основные фигуры, которые можно использовать для создания большинства элементов в большинстве рисунков: линии, прямоугольники, многоугольники, круги и эллипсы. Начнем с линий.
Линии
SVG позволяет рисовать прямые линии с помощью элемента <line>. Нужно только задать х и у координаты конечных точек линий. Координаты можно указывать без единиц измерения, они будут расцениваться как пиксели, или же можно указывать явно единицы (em, in и т.д.).
Нарисуем несколько линий:
Характеристики кисти
Линии являются следом от кисточки, которая рисует по холсту. Размер, цвет и стиль кисточки являются частью оформления линии — пойдут в атрибут style.
Толщина кисти — stroke-width
В предыдущих главах уже говорилось, что линии холста являются бесконечно тонкими. Тогда как линия или кисточка взаимодействует с линиями координатной сеткой? Ответ — линии координатной сетки совпадают с центром кисти. На следующем примере нарисованы линии, в которых толщина кисти равна десяти пикселям, для того, чтобы сделать эффект более видным:
Цвет кисти
Цвет кисти можно определить несколькими способами:
одним из зарезервированных названий: aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, yellow (полный перечень имен цветов в спецификации SVG);
шестизначный шестнадцатеричный спецификатор в форме #rrggbb, где rr — красный цвет, gg — зеленый, bb — голубой компонент в области 0-ff;
трехзначный шестнадцатеричный спецификатор в форме #rgb, r — красный, g — зеленый, b — голубой компонент в области 0-f. Это сокращенная форма предыдущего способа определения цвета. Чтобы получить эквивалент из шести цифр, каждая цифра сокращенной формы должна дублироваться: #d6e — #dd66ee;
cпецификатор rgb в форме rgb (значение красного, значение зеленого, значение голубого), где каждое значение — это 0-255 или процентное отношение в области от 0% до 100%.
Прозрачность кисти — stroke-opacity
Вы можете управлять прозрачностью линии свойством stroke-opacity, котрое может принимать значение от 0 до 1: 0 — полностью прозрачна, 1 — полностью непрозрачна. Значение меньше нуля будет изменено на 0, а значение больше единицы будет изменено на 1.
Прерывистость кисти — stroke-dasharray
Если Вам необходима прерывистая линия или линия с точками, используйте свойство stroke-dasharray. Его значение состоит из списка чисел, разделенных запятыми или пробелами, которые определяют длину отрезков и промежутков между ними. Список должен иметь четное количество компонентов. Если задать нечетное, SVG повторит список еще раз, чтобы общее количество компонентов стало четным.
Основные фигуры. Прямоугольники.
Прямоугольник — самая простая из основных фигур, отвечает за нее элемент <rect>. Задаем х- и у-координаты верхнего левого угла прямоугольника, его ширину (width) и высоту (height). Прямоугольник будет залит цветом (свойство fill), который мы укажем, по умолчанию — это черный цвет. Цвет заливки можно задать всеми теми же способами, что и для линии. Если указать значение «none», прямоугольник будет без заливки, то есть прозрачным. Правила указания степени прозрачности заливки прямоугольника (fill-opacity) аналогичны правилам для линии. Оба свойства «fill» и «fill-opacity» являются свойствами представления и описываются внутри атрибута style.
Заметка
Визуально x и y координаты в параметрах прямоугольника могут оказаться не левым верхним углом, если например к фигуре будет применена трансформация.
Контуры прямоугольника рисуются той же кисточкой, что и линии, с теми же самыми свойствами. По умолчанию для кисточки используется значение none (stroke: none) и контур не рисуется. Несколько примеров:
Контур рисуется таким образом, что его половина находится внутри прямоугольника, а другая половина — вне его. Смотрим на один из прямоугольников в увеличенном виде:
Если не задать начальное значение х- или у- координате, они будут приравнены к нолю. Если задать ширину или высоту равную нолю — прямоугольник не будут отображаться. Использование отрицательных значений для определения ширины или высоты прямоугольника является ошибкой.
Закругленные прямоугольники
Чтобы нарисовать прямоугольник с закругленными углами, нужно задать радиусы закругления угла по осям x (rx) и y (ry). Максимальное число для rx — половина ширины (width) прямоугольника. Максимальное значение для ry — половина высоты (height). Если задать только одно из rx или ry, тогда неуказанное будет приравнено к указанному.
Чтобы нарисовать круг, используйте элемент <circle>. Укажите центр круга по осям X и Y атрибутами cx и cy, а так же радиус атрибутом r. По аналогии с прямоугольником, круг по умолчанию заливается черным цветом и не рисуется контур. Чтобы это изменить используются все те же самые свойства, как и для прямоугольника: fill и stroke.
Эллипс рисуется с помощью <ellipse>. В атрибутах указываем координаты центра (cx, cy), а вместо одного параметра для радиуса, теперь их два: по оси X (rx) и по оси Y (ry).
Для круга и для эллипса:
если не заданы координаты центра, тогда они будут приравнены к нулю;
если не указан радиус — фигура не отобразится;
отрицательное значение для радиуса считается ошибкой.
В дополнение к прямоугольнику, кругу и эллипсу, можно так же нарисовать шестиугольник, восьмиугольник, звезду или другие произвольные фигуры замкнутой формы. Элемент <polygon> позволяет указать серию точек, которые описывают геометрическую фигуру. Она может быть залита и иметь контур. Атрибут points содержит серию пар х- и у-координат, разделенных запятыми или пробелами. В этой серии чисел должно присутствовать четное количество компонентов. Возвращаться в начальную точку нет необходимости: фигура сама автоматически замкнет контур. Посмотрим в действии на <polygon>: нарисуем параллелограмм, звезду и фигуру неправильной формы:
У многоугольников, показанных выше, очень легко закрасить внутреннюю поверхность. Линии, которые формируют многоугольник не пересекаются друг с другом. Поэтому внутреннюю часть легко отличить от внешней. Другое дело когда линии пересекаются. Бывает сразу и не скажешь, где внутренняя часть фигуры. Для тех кто сомневается, смотрим следующий пример:
И так, средняя секция звезды находится внутри или снаружи контура?
В SVG есть два алгоритма для определения находится ли часть многоугольника внутри этого многоугольника или снаружи. Контролирует это правило fill-rule (относится к оформлению). Имеет два варианта значения: nonzero или evenodd. В зависимости от выбранного значения правила получается разный эффект. Посмотрим на примере разницу:
Не обязательно знать детали fill-rules для того, чтобы пользоваться этим правилом, но мы все же расскажем как оно работают. Правило nonzero определяет положение точки (находится внутри или за пределами многоугольника), путем проведения луча от точки в бесконечность в любом направлении. Счет начинается с нуля. К этому счету добавляется 1, каждый раз когда луч пересекает контур фигуры, который рисовался слева направо. И вычитаем 1, когда пересекает контур с направлением справа налево. После подсчета переходов, если результат равен нулю, то точка находится вне фигуры. В противном случае, она находится внутри.
Правило evenodd также рисует луч от точки в бесконечность, с подсчетом количества раз пересечения контуров фигуры. Но в данном случае подсчитывается только количество раз, сколько раз данный луч пересек контуры фигуры. Если общее количествово пересечений нечетное — точка внутри многоугольника, если четное — за пределами.
Основные фигуры. Ломанная линия.
В конце нашего «обзора» основных фигур, мы возвращаемся к прямым линиям. Иногда может понадобиться нарисовать целую серию линий, но чтобы они не были замкнутой фигурой. Тут можно использовать несколько элементов <line>. Но проще будет применить элемент <polyline>. У него те же атрибуты, что и у <polygon>. Отличием будет только отсутствие замыкающего контура. Для примера нарисуем значок электрического сопротивления:
Если не указать заливку как fill: none для ломаной линии, тогда просмотрщик попытается залить внутреннее пространство черным цветом. Например вот так:
Концы линий и соединения
При использовании <line> или <polyline> можно указать форму концов линий задав свойству stroke-linecap одно из значений: butt, round или square. Следующий пример демонстрирует все три значения. Серыми линиями показано, где фактически расположены края линии: видим, что круглые (round) и квадратные (square) края вышли за пределы линии, трапециевидные (butt), они используются по умолчанию, не выходят за пределы линии:
Так же можно повлиять на вид соединения линий свойством stroke-linejoin, которое может иметь следующие значения: miter (угол), round (скругленное), bevel (срез).
Если линии соединяются под острым углом и имеют соединение вида miter, есть возможность увеличить толщину линий: установить соотношение угла к толщине линии свойством stroke-miterlimit. По умолчанию его значение равно 4.
Структура SVG документа и представление
SVG позволяет разделять структуру документа и его представление. Сейчас попробуем сравнить и сопоставить эти два понятия, обсудить аспекты представления документа более детально и показать некоторые элементы SVG, которые Вы сможете использовать для того, чтобы сделать структуру Вашего документа более четкой, читаемой и более простой в обслуживании.
Одна из целей XML — предоставить доступ к структуре данных и отделить эту структуру от ее визуального представления. Рассматривая SVG-код для рисунка кота в «Создание SVG графики», можно было догадаться по структуре кода, что это кот — об этом говорит расположение и размер геометрических фигур, которые формируют рисунок. Если бы нужно было сделать структурные изменения, например, уменьшить усы, округлить нос, или сделать уши длиннее с закругленными кончиками — получим изображение кролика. И не имеет значения, какой была основа представления. Таким образом, структура подсказывает Вам, что собой представляет графика.
Мы не хотим сказать, что информация о визуальном оформлении неважна. Если бы мы нарисовали кота толстыми фиолетовыми линиями и сделали серую заливку внутренней поверхности рисунка, мы бы все еще смогли узнать кота на рисунке, но внешний вид такого кота был бы менее лицеприятен. Эта разница показана на рисунке ниже. XML помогает Вам разделить структуру и представление. К сожалению, большинство обсуждений XML уделяют больше внимания структуре в ущерб представлению. Мы исправим эту несправедливость, расписав в деталях, как использовать представление в SVG.
Использование стилей с SVG
SVG позволяет оформлять графику четырьмя способами: при помощи встроенных (inline) стилей, внутренних таблиц стилей, внешних таблиц стилей и атрибутов презентации. Давайте попробуем каждый из этих способов по очереди.
Встроенные стили
В следующем примере использованы встроенные стили. Это именно тот способ, который мы использовали во всех предыдущих примерах: атрибуту style задавали серию визуальных свойств со значениями:
Внутренние таблицы стилей
Вообще нет необходимость вставлять стили в каждый элемент SVG, тем самым захламляя код. Можно создать внутренние таблицы стилей для сохранения часто используемых стилей, которые можно применить для всех элементов определенного типа или применить только к элементам, содержащих определенный класс. В следующем примере установлена внутренняя таблица стилей, на основе которой все круги будут создаваться с утолщенной пунктирной линией и светло желтой заливкой. Таблицу стилей помещена в элемент <defs>, который мы обсудим немного позже. На примере будет нарисовано несколько кругов. Два последних будут использовать inline стили, корректирующие оформление, заданное внутренней таблицей стилей:
Внешние таблицы стилей
Представим ситуацию, Вы используете внутренние таблицы стилей для целой серии SVG-документов. Для этого приходится копировать и вставлять таблицы стилей в каждый документ. Думаю уже сейчас понятно, что это не практично. А если вспомнить, что довольно чсто приходится вносить изменения в стили, тогда лень, которая является чуть ли не главным двигателем прогресса, просто завопит от возмущения — кому же охота делать обезьянью работу по внесению изменений стилей в каждый из SVG-документов?!
Вот тут-то и пригодятся внешние таблицы стилей — все содержимое элемента <style> (включая <! CDATA[ и ]]>) сохраняем во внешнем файле, который и станет внешней таблицей стилей. Следующий пример демонстрирует содержимое такой внешней таблице с именем ext_style.css. Эта таблица использует множество селекторов, включая *, который указывает на все элементы:
* { fill:none; stroke: black; } /* по умолчанию для всех элментов */
rect { stroke-dasharray: 7 3; }
circle.yellow { fill: yellow; }
.thick { stroke-width: 5; }
.semiblue { fill:blue; fill-opacity: 0.5; }
Внешняя таблица готова. Теперь посмотрим как ее подключить к SVG-документу:
Линейные стили почти всегда будут выполняться быстрее, чем стили во внутренней или внешней таблице стилей: таблицы стилей и классы увеличивают время выполнение из-за поиска и анализа.
Атрибуты представления
Подавляющее большинство Ваших SVG-документов будут использовать стили для оформления, но не помешает знать, что SVG позволяет также задавать оформление и атрибутами представления. Например, вместо:
можно написать так:
Такая запись может показаться смесью структуры и представления. И тут вы абсолютно правы. И даже следует подумать: а какой от этого толк? А толк вот в чем: атрибуты представления могут пригодиться, когда Вы будете создавать документы SVG конвертируя данные из XML-источника в SVG (об этом детальней в последующих главах). В данном случае будет проще создать отдельные атрибуты, чем содержимое атрибута style. Атрибуты представления также могут пригодится в случаях когда отсутствует поддержка таблиц стилей.
Атрибуты представления имеют самый низкий приоритет среди способов задать оформление. Любое определение, исходящая от встроенных стилей, внутренних или внешних таблиц стилей будет «перекрывать» атрибут представления. В следующем примере круг будет залит красным, а не зеленым цветом.
И еще раз, использование атрибутов style или таблиц стилей у вас должно преобладать ведь они позволяют применить сложные серии характеристик заливки и кисти для всех элементов, находящихся внутри документа без необходимости дублирования информации в каждом элементе. Сила и гибкость таблиц стилей позволяет делать изменения в оформлении документов сколько бы их ни было с минимальными усилиями.
Группирование и привязка SVG объектов
Большинство не абстрактных изображений состоит из групп фигур и линий, которые формируют узнаваемые объекты. Подобные группы элементов SVG позволяет объединить чтобы сделать код более понятным, структурированным и удобным.
Элемент <g>
Элемент <g> объединяет все дочерние элементы в группу. Зачастую имеет уникальный id. Так же может в себе содержать <title> и <desc> чтобы улучшить доступность для невизуальных браузеров. В дополнение к этому, <g> обеспечивает удобство и сокращение объема кода при использовании стилей: заданный стиль для <g> будет распространятся на все дочерние элементы. В следующем примере избежим дублирования style="fill:none; stroke:black;" для элементов рисунка:
Рисунок группамиРисунок дома и людейДос с дверьюМужикТетка
Допускается вложенность группы элементов в другую группу.
Элемент <g> по своей сущности очень напоминает группирование слоев в Adobe Photoshop и Adobe Illustrator.
Элемент <use>
Часто в дизайне встречаются повторяющиеся элементы. Например, рекламный буклет может содержать логотип компании в верхнем левом и нижнем правом углу каждой страницы. В каком-нибудь Adobe Illustrator достаточно один раз нарисовать логотип, сгруппировать все его составляющие, скопировать сгруппированный рисунок и вставлять его сколько угодно раз в нужные места. Элемент <use> предоставляет аналог функции копи-паста для группы элементов, объединенных с помощью <g>.
Чтобы скопировать-вставить определенную группу (она должна иметь id), добавляем элемент <use>, указываем какую группу будем копировать (атрибут xlink:href) и задаем положение копии (относительно положения оригинала). Возьмем предыдущий пример и сделаем копии дома и людей:
...
Элемент <defs>
В предыдущем примере сложно не заметить недостатки:
нужно знать позицию оригинала и отталкиваться от него, а не просто указать нужные координаты;
цвета, а точнее все стили, у копий будут таким же как и у оригинала: их нельзя изменить с помощью <use>;
при использовании <g> отобразится все сгруппированные элементы. В нашем примере нельзя определить, сгруппировать и «сохранить» все три элемента, а отобразить только, например, дом или мужчину.
Элемент <defs> позволяет решить эти проблемы. Заключаем сгруппированные объекты в <defs> — определяем элементы без их отображения. Спецификация SVG рекомендует группы, которые будут повторно использоваться, заключать в <defs>, чтобы код получился более гибким и компактным. В следующем примере дом, мужчина и женщина определены так, чтобы их верхний левый угол находился в (0, 0) и не был указан цвет заливки. Так как группы находятся внутри <defs>, они не будут отображаться на экране, но будут служить в качестве «шаблонов» для использования в будущем. Добавим еще одну группу couple, которая, использует <use> для групп man и woman. Заметьте, что нижний рисунок не может использовать couple, потому что поменяли местами женщину и мужчину:
Рисуем группамиНа рисунке дом и людиДом с дверьюМужикТеткаМужик и тетка
Элемент <use> не ограничен рамками одного SVG документа: атрибут xlink:href может сослаться на любой подходящий файл или адрес в Сети. Это позволяет собрать несколько общих элементов в один SVG файл и использовать в качестве «донора». Например, создаем identity.svg, в котором соберем графику, использующуюся организацией:
и затем ссылаемся на него:
Элемент <symbol>
Элемент <symbol> позволяет группировать элементы еще одним способом. В отличии от элемента <g>, <symbol> никогда не отображается: нет необходимости его скрывать с помощью <defs>.
Еще одна особенность <symbol> — это возможность использования атрибутов viewBox и preserveAspectRation, чтобы изображение смогло вписаться в окно просмотра, установленное элементом <use>. В следующем примере видим, что width и height для простой группы игнорируются (для верхних двух прямоугольников), но они используются при отображении <symbol>. Края правого нижнего прямоугольника на обрезаны, потому что для preserveAspectRation задано slice.
Symbols vs groupsUseOctagon as groupOctagon as symbol
Если <use> позволяет повторно использовать часть SVG файла, то элемент <image> содержит или SVG файл целиком, или растровый файл (JPEG или PNG). Если использоваться будет SVG файл — атрибуты x, y, width и height устанавливают окно просмотра, в котором будет отображаться содержимое этого файла. Если растровый файл — он будет масштабироваться чтобы соответствовать прямоугольнику, определенному атрибутами. Пример внедрения растрового изображения:
Трансформация в SVG: перемещение
До этого момента все рисунки были отображены «как есть». Но на практике обыденное дело, когда требуется изображение переместить куда-то, как-то перевернуть или изменить масштаб. Для решения этих задач существует атрибут transform. Познакомимся с ним поближе.
В материале «Группирование и привязка SVG объектов» мы познакомились с элементом <use>, который мог вставить группу графических объектов в определенное место. Посмотрим на следующий пример: определяем квадрат (он отобразится в верхнем левом углу координатной сетки), затем повторно рисуем его по координатам (50, 50) (пунктирные линии — просто обозначение границ холста):
Как выясняется, значение х и у являются одной из кратких форм более общего и более мощного атрибута transform. В данном случае, значения х и у преобразуются в атрибут в такого вида: transform = "translate (x-value,y-value)", где translate — технический чудо-термин для «перемещения». x-value, y-value измеряются в текущей системе координат пользователя. Повторим эффект перемещения из предыдущего примера с помощью translate:
Результат можем лицезреть на следующем рисунке. Визульно результат удовлетворяет, но полагать, что в данном примере используется перемещение фигуры было бы ошибочным.
«За кулисами» в действительности происходит совсем другая история. Вместо того, чтобы перемещать сам квадрат, translate берет и перемещает всю координатную сетку. Поэтому наш квадрат будет иметь координаты (0, 0):
Следует запомнить
Translate не перемещает сам объект, а изменяет положение координатной сетки.
На первый взгляд, использование translate кажется нелепым. Это все равно если бы для того чтобы отставить диван подальше от внешней стены дома, потребовалось переместить всю комнату вместе со стенами. На самом деле не все так плохо. Как оказывается, перемещается не вся координатная сеть общая для всех объектов, а локальная сеть конкретного перемещаемого объекта. Т.е. как бы образуется несколько систем координат.
Да, кстати, translate можно применять не только к <use>, но и к отдельным элементам, а так же к группам:
P.S. что будет с координатной сеткой и где она окажется, если применить трансформацию только к одному из многих элементов на холсте, узнаем в последующих материалах.
Трансформация в SVG: масштабирование
Масштаб SVG объектов происходит аналогично перемещению — с помощью изменения параметров локальной системы координат (в данном случае это будет масштабирование). Для этого используем значение scale атрибута transform:
transform="scale(value)"
умножаем координаты х и у на указанное value.
transform="scale(x-value, y-value)"
координаты x умножаются на x-value, y — на y-value.
Рассмотрим пример пропорционального масштабирования, в котором значение по обеим осям умножается на 2 (пунктирные линии с точками на рисунке показывают интересующую нас зону холста). Левый верхний угол квадрата имеет координаты (10, 10).
Хм...Квадрат стал больше — это ожидалось. А вот почему он находится в другом месте?. Все становиться ясно, когда посмотрим на следующий рисунок.
Координатная сетка не переместилась: точка (0, 0) в системе координат находиться на том же месте. Но каждая координата стала в 2 раза больше, чем была — произошло увеличение всей координатной сетки. На рисунке по линиям видно, что левый верхний угол прямоугольника все еще в точке (10, 10) — объект не был перемещен.
Масштаб системы координат также объясняет, почему контур увеличенного квадрата стал толще. Stroke-width измеряется в системе координат пользователя и эта единица тоже стала в 2 раза больше. Соответственно и кисть стала толще.
Следует запомнить
Трансформация scale (масштабирование) не изменяет ни размеры объекта, ни ширину кисти — меняется только размер системы координат по отношению к холсту.
А что же получится, если задать разные коэффициенты масштабирования? Пробуем: по оси х коэффициент равен 3, по у — 1,5.
Оказывается толщина кисти элемента, как и сам элемент, также масштабируется неравномерно.
В выше приведенных примерах мы применяли атрибут transform к элементу <use>. Но с таким же успехом его можно применить трансформацию и к группе элементов:
Можете применить трансформацию и к отдельному объекту:
В этом примере ширина и высота масштабированного прямоугольника должна стать в 3 раза больше, чем была. Но пример интресен еще и таким вопросом: координаты х и у определяются до или после того, как прямоугольник масштабируется? Т.е. будет ли объект «пермещен»? Ответ — SVG применяет трансформацию к системе координат до того, как будет отрисована фигура, т.е. фигура будет «перемещена» относительно немасштабируемых объектов. Следующий пример демонстрирует масштабирование прямоугольника отдельно от остальных элементов:
Результат на демо примере или рисунке ниже. Координатная сетка нарисована линиями в немасштабируемой системе координат.
Эффект масштабирования к конкретным фигурам такой же, если бы трансформация была применена к группе:
Последовательность трансформаций в SVG
Для объекта количество возможных трансформаций не ограничивается одной: можно задать несколько. Для этого атрибуту transform задаем несколько значений через пробел. В следующем примере представлен прямоугольник, который подвергнем двум трансформациям: translation и scaling. Оси тут нарисованы для демонстрации как именно прямоугольник переместился.
Ниже вариант применение трансформаций к вложенным группам:
Оба эти варианта дадут одинаковый результат:
Рассмотрим каждый шаг трансформаций в отдельности:
Следует запомнить
Порядок, в котором выполняется последовательность трансформаций, влияет на конечный результат. Трансформация А следующая за В не даст вам тот же самый результат, что и трансформация В следующая за трансформацией А.
Для этого возьмем тот же прямоугольник и применим к нему сначала последовательность translate -> scale (на рисунке он серый). Затем возьмем его «брата-близнеца» и применим scale -> translate (черный):
Причиной отличия результата в данном случае является то, что первой применялось масштабирование. Перенос выполнялся уже в увеличенной системе координат.
Прием: конвертация из декартовой системы координат
На практике можно столкнуться с задачей: перенести векторный рисунок, созданный в декартовой системе координат, в SVG. В декартовой системе координат, точка (0, 0) находится в нижнем левом углу холста, а у-координаты возрастают по мере движения вверх.
Выходит ситуация, когда ось-у перевернута вверх ногами по отношению к системе SVG. Чтобы рисунок отобразился в SVG так же как и в исходной системе, координаты необходимо пересчитать. Чтобы не делать это вручную, можно воспользоваться последовательностью трансформаций, чтобы SVG сам все сделал. Для этого, сначала, просто переносим картинку в SVG с исходными координатами. Для большей наглядности нарисуем оси декартовой системы координат. Результат предсказуем — рисунок получился перевернутым вверх ногами.
Чтобы закончить конвертацию, выполняем следующие шаги:
Находим максимальную y-координату (max-y). В данном случае она будет равна 100 (конец линии, изображающей ось y).
Помещаем весь рисунок в элемент <g>.
Делаем перемещение системы координат вниз на максимальное значение y-координаты: transform="translate(0, max-y)".
Переворачиваем вверх ногами ось y с помощью трансформации scale со значением "-1" для оси y: transform="translate(0, max-y) scale(1, -1)".
В SVG можно повернуть систему координат на определенный угол. По умолчанию, угол увеличивается по мере поворота по часовой стрелке. Горизонтальной линия имеет угол 0°.
Центром вращения (или по другому «осью вращения») по умолчанию является точка (0, 0). На следующем примере нарисуем серый квадрат. Его повернем на 45° и перекрасим в черный. Для наглядности добавим так же оси координат.
В большинстве случаев неудобно поворачивать всю систему координат относительно точки (0, 0). Например, хочется повернуть отдельный объект вокруг произвольной точки. Этого можно добиться серией трансформаций: translate(centerX, centerY) rotate(angle) translate(-centerX, -centerY). О также подобную задачу можно решить более простым способом, благо разработчики SVG об этом позаботились: просто в rotate следует добавить координаты точки, вокруг которой хочется повернуть объект: rotate(angle, centerX, centerY).
В данном случае проявляется эффект временной установки новой системы координат с центром в координатах в centerX и centerY. Выполняется поворот объекта вокруг этой новой оси, а затем система координат возвращается как и была. Следующий пример демонстрирует это — нарисуем стрелку и сделаем несколько ее копий вокруг произвольной точки:
Так же как возможно вращение вокруг произвольной точки, возможно и масштабирование. Для наглядности можно нарисовать центр масштабирования. А чтобы выполнить масштабирование относительно этого центра, следует придерживаться следующей формулы:
Так же можно применить коэффициент масштабирования к stroke-width чтобы толщина контура не менялась с увеличением объекта. Для примера сделаем увеличение прямоугольника вокруг точки.
В SVG имеется еще две трансформации: skewX и skewY. Они позволяют наклонить одну из осей. Общая форма skewX(угол) и skewY(угол). Трансформация skewX сдвигает все х-координаты на определенный угол, оставляя у-координаты без изменения. skewY — у-координаты, оставляя х-координаты без изменений.
Все фигуры, описанные ранее, являются сокращенными записями более общего элемента <path> (путь). Эти сокращения делают код более читабельным и структурированным. Элемент <path> способен создавать фигуры произвольной формы с помощью произвольного числа отрезков и кривых, связанных между собой. Такая фигура может иметь контур и заливку цветом как и обычная фигура. В добавок, эти пути можно использовать для определения усеченной зоны или маски прозрачности.
Все данные для описания элемента <path> содержаться в его атрибуте d (d — data). Данные path состоят из однобуквенных команд, таких как m (moveto) или l (lineto), за которыми следуют координаты для этой команды.
Moveto, lineto и closepath
Любой маршрут должен начинаться с команды moveto. Командная буква — заглавная М, за которой следуют х и у координаты, разделенными запятыми или пробелами. Эта команда устанавливает текущее положение «ручки», которая рисует фигуру.
После чего могут идти одна или несколько команд lineto, обозначающимися заглавной L, за которой также следуют х и у координаты, разделенные запятыми или пробелами. В приведенном ниже примере показано 3 пути. Первый рисует одну линию, второй — прямой угол, третий — два угла по 30 градусов. Когда Вы «берете ручку», используя moveto, Вы начинаете новый под-маршрут. Учтите, что запятые и пробелы используются в качестве разделителей по-разному, но абсолютно законно во всех трех путях.
Рассмотрим последний путь более детально:
Значение
Действие
M 40 60
Передвинуть ручку в точку (40, 60)
L 10 60
Нарисовать линию (10, 60)
L 40 42.68
Нарисовать линию (40, 42.68)
M 60 60
Начать новый маршрут; Передвинуть ручку в точку (60, 60) — нет нарисованных линий
L 90 60
Нарисовать линию (90, 60)
L 60 42.68
Нарисовать линию (60, 42.68)
Заметка
Трудно не заметить, что данные элемента <path> не очень похожи на типичные XML атрибуты. Так как все данные вмещены в один общий атрибут, а не отдельный элемент для каждой точки или линии, фигура занимает меньше памяти когда анализируется DOM структура XML парсером. Такая запись позволяет передавать большие изображения при небольшой пропускной способности.
Если есть желание нарисовать с помощью path прямоугольник, то это можно сделать двумя способами: нарисовать четыре линии или нарисовать три и вызвать команду closepath, обозначенную Z, чтобы нарисовать прямую линию в начальную точку под-маршрута. Как это выглядит в коде показано в следующем примере:
Последний путь разберем детальней:
Значение
Действие
M 40 60
Передвинуть ручку в точку (40, 60)
L 10 60
Нарисовать линию (10, 60)
L 40 42.68
Нарисовать линию (40, 42.68)
Z
Завершить маршрут, нарисовав прямую линию (40, 60), где этот путь начинался
M 60 60
Начать новый маршрут; Передвинуть ручку в точку (60, 60) — нет нарисованных линий
L 90 60
Нарисовать линию (90, 60)
L 60 42.68
Нарисовать линию (60, 42.68)
Z
Завершить маршрут, нарисовав прямую линию (60, 60), где этот путь начинался
Относительные moveto и lineto
Команды, рассмотренные выше, были представлены заглавными буквами, а координаты считались абсолютными. Если Вы используете строчные буквы в качестве команд, координаты воспринимаются как относительные по отношению к текущему положению ручки. Таким образом, представленные ниже маршруты являются эквивалентными:
Если начать маршрут со строчной m (moveto), координаты будут абсолютными, так как нет предыдущего положения ручки, от которого рассчитывать относительное положение. Все команды в этой главе могут быть заданы как заглавными, так и строчными буквами. Координаты команд, написанные заглавными буквами, являются абсолютными, а команды, написанные строчными буквами — относительными. Команда closepath, которая не имеет координат, имеет одинаковый эффект как при написании заглавными, так и строчными буквами.
Сокращение путей
Если представить себе, что дизайн — это королева, а контент — король, то пропускная способность — это королевский придворный, который поддерживает все дела, происходящие в дворце. Так как любой нетривиальный рисунок будет содержать многие десятки пар координат, элемент <path> имеет сокращенный вариант записи, чтобы представить путь минимальным количеством байт.
Команды горизонтального и вертикального lineto
Вертикальные и горизонтальные линии — банальность в графике. Логично, что это в первую очередь требует оптимизации. Горизонтальная линия определяется командой H, за которой следует абсолютная x-координата, или командой h, за которой идет относительная x-координата. Аналогично и с вертикальными линиями: команда V, за которой абсолютная y-координата и v — с относительной.
Сокращение
Эквивалент
Эффект
H 20
L 20 current_y
нарисовать линию к абсолютному положению (20, current_y)
h 20
L 20 0
нарисовать линию к (current_x+20, current_y)
V 20
L current_x 20
нарисовать линию к абсолютному положению (current_x,20)
v 20
l current_x 20
нарисовать линию к (current_x, current_y+20)
Таким образом, мы получим прямоугольник с размерами 15 единиц в ширину и 25 единиц в высоту, с координатами верхнего левого угла (12, 24).
Обозначения сокращений для путей
Пути можно сократить, придерживаясь следующих правил:
Можно ставить несколько серий координат после L и l, так же как делали это в элементе <polyline>. Ниже приведен код, где все шесть маршрутов рисуют один и тот же ромб (рис под кодом). Первые три — в абсолютной системе координат, следующие три — в относительной системе. Третий и шестой маршрут демонстрируют интересный прием — если Вы поставите несколько пар координат после moveto, все пары после первой будут считаться предшествующими lineto. Можно также ставить несколько одиночных координат после horizontal lineto и vertical lineto, хотя это делать бессмысленно. H 25 35 45 — тоже самое, что и H 45, а v 11 13 15 — тоже самое, что и v 39.
Все ненужные пробелы можно убрать. Нет необходимость ставить пробел после каждой командной буквы, если все команды состоят только из одной буквы. Нет необходимости ставить пробел между числом и командой, так как командная буква не может быть частью числа. Не нужно ставить пробел между положительными и отрицательными числами, так как знак минус не может быть частью положительного числа. Сократим третий и шестой маршрут из предыдущего списка:
Еще пример «правила упущения пробелов» продемонстрирован при создании прямоугольника с шириной в 15 единиц, высотой = 25 и координатами верхнего левого угла (12, 24):