Шаблоны
Шаблоны (Patterns)
Patterns, по моему мнению, одни из самых запутанных типов заполнения (fill types) в SVG. Несмотря на это ,они являются очень мощным инструментом, так что о них определённо стоит поговорить и понять хотя бы основные части. Как и градиенты, элементы <pattern>
должны быть помещены в секцию <defs> в вашем SVG-файле.
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="Gradient1">
<stop offset="5%" stop-color="white" />
<stop offset="95%" stop-color="blue" />
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="red" />
<stop offset="95%" stop-color="orange" />
</linearGradient>
<pattern id="Pattern" x="0" y="0" width=".25" height=".25">
<rect x="0" y="0" width="50" height="50" fill="skyblue" />
<rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)" />
<circle
cx="25"
cy="25"
r="20"
fill="url(#Gradient1)"
fill-opacity="0.5" />
</pattern>
</defs>
<rect fill="url(#Pattern)" stroke="black" width="200" height="200" />
</svg>
Screenshot | Live sample |
---|---|
![]() |
Внутри элемента <pattern> вы можете использовать любые другие основные фигуры, которые использовались ранее. И каждая из них может быть стилизована, используя любые из возможных вариантов стилизаций, которые вы изучали до этого, включая градиенты и прозрачность. Выше мы просто нарисовали два прямоугольника внутри нашего шаблона (которые перекрываются, и один из которых в два раза больше другого и используется для заполнения всего шаблона), и один круг.
Сбивающая с толку вещь - это определение единиц измерения и размера. В примере выше мы определили ширину и высоту соответствующими атрибутами внутри паттерна, что бы указать как далеко паттерн будет "продолжаться", прежде чем начать повторяться. Также доступны x и y атрибуты для смещения стартовой точки этого прямоугольника в том месте где вы его отрисовываете. Причина по которой они тут использованы, описана ниже.
Как и с gradientUnits
атрибутом, использованном ранее, у паттерна также есть атрибут patternUnits
. Он определяет единицы измерения, которые принимают атрибуты. По дефолту используется значение "objectBoundingBox", (как и в предыдущем разделе). Так что значения от 0 до 1 будут масштабированы в зависимости от размеров объекта, к которому вы применяете паттерн. Поскольку в данном случае мы хотим, чтобы шаблон повторялся 4 раза по горизонтали и вертикали, ширину и высоту мы уста��овили в значение 0.25. Что означает 0.25 от размера целевого объекта
В отличие от градиентов, у паттернов есть 2ой атрибут - patternContentUnits
, который описывает единицы измерения, используемые в базовых фигурах внутри элемента pattern. Дефолтное значение для этого атрибута - userSpaceOnUse, противоположность атрибуту patternUnits
. Это означает, что если вы не укажете один или оба этих атрибута (patternContentUnits
и/или patternUnits
), фигуры, которые вы будете рисовать внутри блока <pattern>, будут отрисованы в другой системе координат (отличной от той, которую использует паттерн). Это может немного запутывать, если вы пишете код вручную.
Чтобы сделать эту работу в приведённом выше примере, нам пришлось рассмотреть размер нашей коробки (200 пикселей) и тот факт, что мы хотели, чтобы рисунок повторялся 4 раза по горизонтали и по вертикали. Это означает, что каждый блок шаблонов был квадратом 50 × 50. Затем два прямоугольника и круг внутри рисунка были рассчитаны на размер в коробке 50x50. Все, что мы нарисовали вне этой коробки, не было бы показано. Шаблон также должен был быть смещён на 10 пикселей, чтобы он начинался в верхнем левом углу нашего окна, поэтому атрибуты x и y шаблона должны были быть скорректированы до 10/200 = 0,05.
Здесь предостережение заключается в том, что если объект изменяет размер, сам шаблон будет масштабироваться, чтобы соответствовать ему, но объекты внутри не будут. Таким образом, хотя у нас все ещё будет 4 повторяющихся блока внутри шаблона, объекты, составляющие этот шаблон, будут оставаться одного и того же размера, и вы окажетесь в больших областях между ними.
Изменяя атрибут patternContentUnits
, мы можем поместить все элементы в одну единую систему:
<pattern id="Pattern" width=".25" height=".25" patternContentUnits="objectBoundingBox">
<rect x="0" y="0" width=".25" height=".25" fill="skyblue"/>
<rect x="0" y="0" width=".125" height=".125" fill="url(#Gradient2)"/>
<circle cx=".125" cy=".125" r=".1" fill="url(#Gradient1)" fill-opacity="0.5"/>
</pattern>
Теперь, поскольку содержимое шаблона находится в той же единичной системе, что и шаблон, нам не нужно смещать поле так, чтобы шаблон начинался в правильном месте, и если размер объекта был изменён на более крупный, шаблон автоматически масштабируется так, чтобы в нем было одинаковое количество объектов, повторяющихся внутри него. Это контрастирует с системой userSpaceOnUse, где, если объект изменяет размер, шаблон останется прежним и просто повторится больше раз, чтобы заполнить поле.
Как ни удивительно, но в кругах Gecko, похоже, есть проблемы с рисованием, если их радиус установлен на что-то меньшее 0.075 (хотя их нужно масштабировать, чтобы иметь гораздо больший радиус, чем этот. Это может быть ошибкой только в шаблоне , Или вообще не ошибка, я не уверен). Чтобы обойти это, вероятно, лучше всего избегать рисования блоков «objectBoundingBox», если вам это не нужно.
Ни одно из этих применений не является тем, о чем обычно думают, когда вы думаете о шаблоне. Шаблоны обычно имеют заданный размер и повторяются независимо от формы объекта. Чтобы создать что-то подобное - шаблон и его содержимое должны быть нарисованы в текущем userSpace, чтобы они не меняли форму, если объект:
<pattern id="Pattern" x="10" y="10" width="50" height="50" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="50" height="50" fill="skyblue"/>
<rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)"/>
<circle cx="25" cy="25" r="20" fill="url(#Gradient1)" fill-opacity="0.5"/>
</pattern>
Конечно, это означает, что шаблон не будет масштабироваться, если вы позже измените размер своего объекта. Все три из приведённых выше примеров показаны ниже на прямоу��ольнике, который слегка удлинён до высоты 300 пикселей, но я должен отметить его не исчерпывающее изображение, и есть другие варианты, доступные в зависимости от вашего приложения.