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

Область просмотра, клиппирование.
Клиппирование — это обрезка объектов выходящих за рамки области просмотра (любой другой области). Зачем нам это нужно? Внутрь тэга <svg> я добавил атрибуты viewBox=»0 0 1440 800″ preserveAspectRatio=»xMidYMax slice». ViewBox ограничивает область просмотра и гарантирует нам, что «горизонт» окажется в одной и той же Y координате на разных браузерах. PreserveAspectRatio срежет лишнее по краям и скроет верх изображения если пропорции экрана не позволят все показать.
Таким образом, мы ограничили область просмотра нашего пейзажа окном с размерами 1440 на 800 единиц, которые будут пересчитываться в реальные пиксели уже в браузере и если пропорции его окна просмотра не будут соответствовать заявленным нами, то он возьмет нижний край пейзажа, расположит его снизу и срежет верх, либо обрежет боковые края. Обе ситуации станут понятнее если вы посмотрите на картинку.
Еще один важный момент, который должны помнить те, кто планирует писать файлы SVG своими руками (без применения графических редакторов).Начало координатной плоскости лежит в левом верхнем углу и оси направлены слева-направо и сверху-вниз.

Графические примитивы и их свойства.

Теперь давайте снова вернемся к основной цели данной статьи — написание пейзажа для интернет страницы. У нас уже есть структура документа, а точнее схема по которой мы будем добавлять графические примитивы. Мы разобрались как эти примитивы описывать в файле и нам осталось разобраться со свойствами которыми обладают наши примитивы, а также трансформацией объектов и групп размещающей их на холсте в конечном виде.
Начнем со свойств, таких как толщина линии обводки, ее цвет, а так же заливкой, и сразу приведу маленький пример:
<rect width="1198" height="398" fill="none" stroke="blue" stroke-width="1" />
Тут у нас прямоугольник без заливки, но с бордюром синего цвета в 1 единицу толщиной. Эти свойства указаны в атрибутах тэга, что не всегда удобно. И W3C находит выход — свойства можно описать в парном тэге <style> в манере CSS как это делается в HTML документах и тогда написав:
.blueBorder {fill:none; stroke:blue; stroke-width:1}
мы можем задать те же свойства не только вышеописанному прямоугольнику, но и любому другому примитиву указав атрибут для тэга примитива например:
<circle cx="600" cy="200" r="100" />
Ну что же, теперь мы во всеоружии и можем приступать к написанию нашего пейзажа… Для начала расставим «заглушки» обозначив блоки, которые будем постепенно заполнять:
<?xml version="1.0" standalone="no"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 <svg version="1.1" xmlns="http://www.w3.org/2000/svg">
        <style type="text/css"><![CDATA[
                /* Стили */
        ]]></style>
          <defs>
                /* Градиенты */
        </defs>
        <g>
                /* Группы и примитивы */
      </g>
 </svg>
Тут ненавязчиво появились еще тэги требующие пояснения для новичка. <!DOCTYPE — это еще один из заголовочных обязательных тэгов указывающий на тип документа с которым будет иметь дело браузер его разбирающий. «Ноги» в данном случае растут из древнего SGML, предшественника XML, в котором тип документа описывался файлом .dtd и такой файл для SVG имеется на сервере W3C, в чем мы уверены указывая его в ссылке. Еще один непонятный тэг <![CDATA[ и его пара ]]> ограничивают «неродную» для SVG таблицу стилей написаную в манере CSS, о чем сказано в атрибуте type=»text/css» тэга <style>.
Добавим наш фон (прямоугольник) и получим:
<?xml version="1.0" standalone="no"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 800" preserveAspectRatio="xMidYMax slice">
        <g>
           <rect id="bg" width="100%" height="100%" />
        </g>
 </svg>
Красным я выделил то, что добавил, и далее буду писать только те куски кода которые будут добавляться. Теперь вы можете увидеть наш первый результат. Надеюсь он вас вдохновил, а чтение не сильно утомило отбив желание изучать SVG.
Что же у нас дальше по плану? Ах да, «кочки». И мы приступаем к рисованию обещанной основы из контура состоящего из ДВУХ точек. Почему их всего две спросят некоторые из вас, а потому, что у нашей кривой Безье только начало и конец, а обратно в начало браузер пройдет кратчайшим путем (по прямой). Мы воспользуемся квадратичной кривой, хотя возможно больше подошла бы кубическая (проверим).
<path d="m0,0 q100,-100 200,0z" />
Вот, вполне приемлемая кочка. Но она пока что черная и стоит не на своем месте. Зададием ей линию обводки. Получим, к примеру:
.grass {stroke:#090; stroke-width:1; fill:#0f0;}

<path d="m0,100 q100,-100 200,0z" />
Нарисуем тропинку. Ее опишет следующий путь — «m50,0 q50,-10 70,-47 0,50 -20,47z» или «m50,0 q10, -50 70,-47 -50,0 -20,47z», обратите внимание — точки в обоих случаях одни и те же, изменяются только опорные пункты путей (нам нужны оба вида «тропинок», чтобы отличать первую и вторую «кочки»), а стиль у них будет такой «fill:#cc9; stroke:#990; stroke-width:2″ назовем его footPath.
.footPath {fill:#cc9; stroke:#990; stroke-width:2}

<path d="m50,0 q10,-50 70,-47 -50,0 -20,47z" />
Переходим к цветочкам. Точнее, нарисуем контур одного цветка, а затем создадим несколько трансформированных копий этого цветка. Путь я «выдернул» из оптимизированного SVG сгенерированного в Inkscape — «m0.54688,-0.11829 c-0.37472,-0.43643 -0.25072,1.0885, 0.04856,0.59722, 0.29928,-0.49124 -1.1127,0.09791-0.55298,0.23074, 0.55967,0.13283, -0.43695,-1.0279 -0.39033,-0.45461, 0.046622,0.57333, 0.84261,-0.73321, 0.31175,-0.51171 -0.53086,0.22151, 0.95771,0.57479, 0.583,0.13836z» для свойств используем радиальный градиент (как его сделать вы узнаете в следующей части статьи) и тонкую серую обводку. «Кочка» почти готова, но она пока еще не на своем месте, как и цветочки, которых хоть и три, но они пока что маленькие и наложены друг на друга.
.flower {stroke:#ccc; stroke-width:0.01}

<path d="m0.5468 .. 0.1383z" />
<path d="m0.5468 .. 0.1383z" />
<path d="m0.5468 .. 0.1383z" />
Объединяем элементы описывающие «Кочку» тэгом контейнером <g> в группу, дважды «копипастим» (дублируем) получая таким образом три «Кочки», как и было задуманно вначале. В первой группе оставляем только цветок в середине, а в средней удаляем первый цветок (их перекроют другие объекты, поэтому они лишние). Меняем путь в тропинке средней «Кочки», а в передней вообще его удаляем. Таким образом мы получаем три группы расположенные одна над другой и нам осталось только указать для каждого тэга <g> атрибут transform=»matrix()», дабы разместить их на холсте с нужным масштабом и в нужных координатах, но об этом речь пойдет в следующей части статьи.
«Облака и островок справа». Три контура: Белое облако с голубой обводкой, голубое облако без обводки и »пролесок» темно-зеленый без обводки объеденены в группу, котораябудет перемещена в правую часть горизонта. Здесь вы можете посмотреть на контуры. Затем была создана копия этой группы, чтобы «отразиться» в воде. Этой группе добавлен атрибут opacity (прозрачность).
<g>
 <path d="m..z" fill="#fff" stroke-width="1" stroke="#09f" />
 <path d="m..z" fill="#3cf" />
 <path d="m..z" fill="#060" />
</g>
<g opacity="0.5">
 <path d="m..z" fill="#fff" stroke-width="1" stroke="#09f" />
 <path d="m..z" fill="#3cf" />
 <path d="m..z" fill="#060" />
</g>
Код приведен не полностью. Немного поразмыслив я не стал придумывать новые контуры для облаков слева, а решил воспользоваться новыми трансформациями для той же группы, что только что была разработана. Пришлось просто убрать контур изображающий «пролесок».
Файл уже весит 7,5 кБ, но мы то помним, что Jpeg с таким разрешением и количеством оттенков весит как минимум в десять раз больше. Остались мелочи: два облачка посреди небосвода и два деревца на двух «кочках».
Сначала деревца. Здесь можно взглянуть на контуры. Крона сформирована из трех клонов одного и того же контура. Думаю вы уже достаточно попрактиковались и сразу заметили, что применением атрибута opacity для среднего контура кроны мы достигаем эффекта при котором создается впечатление, что контуров больше и используется не 3, а 5 оттенка зеленого.
Первое дерево мы вставляем в группу «левой кочки». Дерево на второй «кочке» появляется за счет матричной трансформации и на этот раз я кроме масштабирования и переноса буду использовал отражение по вертикали. Добавляем эту группу к средней «кочки» и, само собой разумеется, она получит «в наследство» размытие, которое в литературе принято называть DOF, которое будет реализовано визуальным фильтром рассматриваемым в следующей части статьи.
Облака посреди небосвода мы сделаем не два, а четыре. Одна пара будет иметь четкий хотя и тонкий контур, а вторая (находящаяся под ней) этого контура лишена, зато будет размыта фильтром. Не стану приводить отдельно контуры этих облаков, а лучше сразу покажу конечный результат к которому мы стремимся.