Tuesday, October 25, 2011

SVG. Масштабируемая векторная графика. Часть 4


Градиенты и текстуры.
А как же градиенты, спросите вы, но я отвечу - это тоже просто. В спецификации определено два типа градиента: линейный и радиальный.
Градиенты положено помещать внутрь тэга контейнера <defs> (от англ. definitions - определения), это говорит о том, что содержимое предназначено для многократного применения. Линейный градиент определен парным тэгом <linearGradient>, (а что же должно быть внутри?) который включает в себя тэги <stop />. В спецификации об этом сказано: "Буйство красок, чтобы использовать в градиенте определено элементами 'stop', которые являются дочерними элементами ‘linearGradient’ элемента или ‘radialGradient’ элемента." Разберем вышесказаное на примере градиента для нашего первого элемента (прямоугольника с фоном):
<defs>
        <linearGradient id="sky_n_water">
                <stop offset="0%" stop-color="#09f" />
                <stop offset="35%" stop-color="#9ff" />
                <stop offset="36%" stop-color="#fff" />
                <stop offset="100%" stop-color="#09f" />
        </linearGradient>
</defs>
Вот они наши запланированые переходы в верхней части от темно-синего к светло-синему, а ниже от белого к темно-синему изображающие небо и воду.
Рекомендую, для проектирования градиентов использовать Фотошоп и для этого несколько причин. Во-первых в "Редакторе градиентов" мы видим удобную шкалу на которой размещаем наши контрольные точки (тэги <stop />) и offset атрибут мы видим в поле "Позиция", что можно считать вторым плюсом, а в третьих на "Палитре цветов" поставив галочку в "Только Web-цвета" мы в поле "#" видим код RGB 0099ff, который можно смело сокращать до трех цифр 09f и писать их в stop-color атрибут.

Вот так легко и просто, но на практике мы получим прямоугольник с градиентом идущим слева-направо, вместо желанного сверху-вниз. Градиент надо повернуть и нам поможет атрибут gradientTransform = "rotate(90)", который необходимо указать в тэге <linearGradient>.
Применим теперь наш первый градиент на практике:
<defs>
        <linearGradient id="sky_n_water"  gradientTransform="rotate(90)">
          <stop offset="0%" stop-color="#09f" />
          <stop offset="35%" stop-color="#9ff" />
          <stop offset="36%" stop-color="#fff" />
          <stop offset="100%" stop-color="#09f" />  
        </linearGradient>
        </defs>
        <style type="text/css"><![CDATA[
          #bg {fill:url(#sky_n_water) #09f; stroke="none"}
        ]]></style>
<rect id="bg" width="100%" height="100%"/>
А вот и новые свойства для нашей «кочки»:
<linearGradient id="grass">
    <stop offset="0" stop-color="#6c0" />
    <stop offset="1" stop-color="#9f3" />
</linearGradient>

.grass {fill:url(#grass) #6c0; stroke:#090; stroke-width:1}
Обратите внимание, на этот раз для параметра offset я использовал не проценты (0 и 1 соответствуют 0% и 100%, а если бы нам понадобилась середина мы написали бы 0.5 вместо 50%).
Радиальный градиент для цветка сделать тоже не сложно. Отличается только тэг обрамляющий наши точки остановки цвета, вместо linearGradient используется radialGradient
<radialGradient id="flower">
   <stop stop-color="#f00" offset="0"/>
   <stop stop-color="#f00" offset="0.3"/>
   <stop stop-color="#fff" offset="0.3"/>
   <stop stop-color="#fff" offset="1"/>
</radialGradient>
.flower {stroke:#ccc; stroke-width:0.01; fill:url(#flower) #f00}
Текстуры в нашем проекте не используются, хотя их успешно можно было бы применить для раскрашивания наших «кочек». Дело в том, что в SVG для текстурирования используются не только растровые текстуры, но и векторные (что важнее). И наши цветочки можно было бы вынести из основного рисунка и поместить в определения <defs> заключив их в тэге <pattern>. Таким образом присвоив текстуре (паттерну) идентификатор мы сможем использовать ее для заливки. Обязательно попробуйте эту методику в ваших проектах — не пожалеете.

Трансформации

Спецификацией предусмотренно несколько видов трансформации - это перемещение (translate), масштабирование (scale), поворот (rotate), наклон по оси Х (skewX), наклон по оси Y (skewY) и matrix, которая в своих шести параметрах может включать сумму нескольких трансформаций. Но поскольку тема матричного представления двумерного пространства выходит за рамки данной статьи примем как факт, что те из вас кто изучал "Высшую математику" разберутся с матричными трансформациями сами, а те кто не изучал либо будут использовать последовательность простых трансформаций, либо найдут учебник по вышке и изучат матрицы самостоятельно. (заранее огорчу - к Морфиусу, Тринити и Нэо наши матрицы отношения не имеют, а их изучение скучнее просмотра одноименного фильма).
Вот матричные трансформации для цветков. Каждая, из них, увеличивает цветок в десять раз и переносит на новое место.
transform="matrix(10,0,0,10,45,75)"
 transform="matrix(10,0,0,10,125,60)"
 transform="matrix(10,0,0,10,160,85)"
Заменить ее обычными можно так:
transform = “scale(10) translate(45,75)”
Важно помнить, что последовательность трансформаций имеет важное значение. Поясню почему... Ось вращения для объекта всегда совпадает с 0,0 и если сначала его переместить, а затем повернуть, то результат будет сильно отличаться от того, который получиться при повороте с последующим перемещением. Тоже касается и масштабирования, так как при увеличении уже перемещенного объекта увеличится и расстояние его перемещения.

В проекте мы не применяем трансформацию «skewX» или «skewY» предназначенные для наклона объекта по горизонтали или вертикали, но они возможно вам пригодятся для проектов реализующих псевдо3D.Например, из трех прямоугольников можно создать куб, как показано на рисунке.
Для «кочек» я выбрал следующие значения [(3,0,0,3,1000,500), (4,0,0,4,480,410), (6,0,0,6,-150,260)] и получил очередной файл SVG. Да, эта картина грубовата и не сглажена фильтрами и спецэффектами Фотошоп, но я нахожу другой факт более важным - наш SVG весит 7,5 кБ, а этот JPEG с размером 400*250 и качеством 60% уже 18 кБ (а если пытаться сохранить в полном кач-ве и с полным разрешением, то вышло бы - 300 кБ). Еще один плюс - SVG сам масштабируется под разрешение экрана и размер рабочей области браузера, а под растр нам пришлось бы придумывать ухищрения.
И у нас в SVG есть простор для совершенствования, постаравшись мы можем еще уменьшить размер файла, добавив несколько атрибутов изменить стиль линий. Да и визуальные фильтры разработаны W3C, но пока, правда, реализованы не во всех браузерах. Мой любимый Google Chrome в числе передовиков и полностью поддерживает все спецификации консорциума W3C.

Визуальные фильтры.

Не углубляясь в подробности сразу показываю код визуального фильтра:
<filter id="BlurFar"><feGaussianBlur stdDeviation="1.5" /></filter>
<filter id="BlurNear"><feGaussianBlur stdDeviation="0.5" /></filter>
<filter id="BlurSmall"><feGaussianBlur stdDeviation="0.1" /></filter>

  <g transform="matrix(3,0,0,3,1000,500)" filter="url(#BlurFar)">
  <g transform="matrix(4,0,0,4,480,410)" filter="url(#BlurNear)">
   <path d="m0,100 q100,-100 200,0z" class="grass" filter="url(#BlurSmall)" />  
Вот такие, незначительные, изменения привносят в наш пейзаж немного реалистичности, за счет DOF (от англ. depth of field - на русский переведу, как глубина резкости). Парный тэг <filter> как и градиенты располагают внутрь контейнера <defs>, и он (в свою очередь) содержит один и более тэгов описывающих фильтры. Я применил тэг <feGaussianBlur> для размытия по Гауссу, а другие фильтры вы без труда отыщите в спецификации. Применять определенный в "defs" фильтр можно и к группам и к отдельным объектам указав им атрибут "filter".
Быстро и просто мы разобрали на практике большую часть современного SVG. Пока что за бортом остались связанные и интегрированные растры, текстовые объекты, шрифты, анимация и использование сценариев. Все это будет рассмотрено в следующих частях статьи.

1 comment: