SVG marker служит для указания направления, начала, середины, конца линии (line) или пути (path), а также маркеры могут быть применены для элементов SVG – polyline и polygon.
Графическое изображение маркера задается внутри тегов <marker> … </marker > в секции <defs> файла SVG с помощью элементов: line, polyline, path, rect, circle.
Маркеру присваивается уникальное имя с помощью индефикатора id=”…”. Созданный таким образом маркер может быть использован далее один или несколько раз, в одном или нескольких файлах SVG.
Тип маркеров
Маркеры бывают следующих типов: marker-start, marker-mid, marker-end. Каждый тип указывают на расположение маркера, соответственно в начале, середине, конце линии или пути, к которым они присоединяются. На рисунке выше в качестве начального маркера marker-start использован круг (circle). Конечный маркер marker-end создан с помощью пути (path), нарисовавшего стрелку.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="150" height="150" version="1.1" viewBox="0 0 150 150" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <defs> <marker id="MarkerArrow" viewBox="0 0 20 20" refX="0" refY="10" markerUnits="userSpaceOnUse" orient="auto" markerWidth="20" markerHeight="20"> <polyline id="markerPoly1" points="0,0 20,10 0,20 2,10" fill="crimson" /> </marker> <marker id="MarkerCircle" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="userSpaceOnUse" markerWidth="10" markerHeight="10"> <circle cx="5" cy="5" r="5" fill="crimson" /> </marker> </defs> <line x1="20" y1="80" x2="110" y2="80" style=" marker-start: url(#MarkerCircle); marker-end: url(#MarkerArrow); fill:none; stroke:green; stroke-width:2; "/> </svg> |
Атрибуты маркеров
Атрибут | Описание |
viewBox | позволяет перемещать,масштабировать маркер. |
markerWidth и markerHeight | длина и высота прямоугольной области, в которой располагается маркер |
refX | перемещает курсор по оси абцисс влево при положительных значениях . |
refY | перемещает курсор по оси ординат. |
markerUnits | отвечает за масштабирование маркера в зависимости от увеличения, уменьшения толщины линии, к которой присоединяется маркер. Значение по умолчанию – strokeWidth. |
orient | “auto | <angle>” отвечает за ориентацию маркера относительно линии. |
Атрибуты markerWidth и markerHeight
Дословный перевод названия этих атрибутов маркера несколько вводит в заблуждение.
Вместе с этой областью просмотра маркера создается новая система координат с начальной точкой отсчета (0,0) в верхнем левом углу этой области. Именно от этой начальной точки новой системы координат будет идти расчет и отрисовка графических фигур маркера. В свою очередь прямоугольная область просмотра маркера присоединяется своим верхним левым углом к началу или концу линии, в зависимости от указанного в кода типа маркера.
На рисунке 2 показаны четыре зеленые линии в разных положениях, к концу каждой линии присоединен однотипный концевой маркер marker-end розового цвета, созданный с помощью прямоугольника шириной 20px и высотой 10px. Область просмотра маркера ограничена прямоугольником 40х40px.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="220" height="220" version="1.1" viewBox="0 0 220 220" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <defs> <marker id="end-rect" viewBox="0 0 40 40" markerUnits="userSpaceOnUse" markerWidth="40" markerHeight="40" refX="0" refY="0" orient="0" > <rect x="0" y="0" width="20" height="10" stroke="black" fill="red" fill-opacity="0.5"/> </marker> </defs> <g style=" fill:none; stroke:green; stroke-width:4; marker-end: url(#end-rect);"> <line x1="100" y1="90" x2="100" y2="20" /> <line x1="110" y1="100" x2="180" y2="100" /> <line x1="100" y1="110" x2="100" y2="180" /> <line x1="90" y1="100" x2="20" y2="100" /> </g> </svg> |
Позиционирование маркера
Позиционирование маркера относительно линии, к вершине которой он присоединяется, осуществляется с помощью атрибутов: refX, refY, orient и viewBox.
Начнем с атрибута маркера orient, который отвечает за поворот области отрисовки и соответственно новой системы координат маркера отностительно системы координат viewport. По умолчанию orient=”0″ градусов.
На этом рисунке виден результат присвоения атрибуту значения отличного от нуля. При orient=”30″ область просмотра и сиcтема координат маркера поворачивается по часовой стрелке на 30 градусов. При отрицательных значениях orient поворот области просмотра и соответственно маркера будет против часовой стрелки.
Позволяет соориентировать маркер вдоль линии или пути. Разработчики предположили, что длина (width) маркера, на самом деле, длина области просмотра маркера – markerWidth должна быть больше его высоты. Поэтому более длинной стороной маркер при атрибуте orient=”auto” распологается в продолжении линии, к которой присоединен. Если длина области просмотра маркера меньше её высоты, то всё равно он будет расположен так, что его длина(ширина) области просмотра markerWidth будет расположена в продолжении линии или пути. На рис.4 показано стрелками, как будет вращаться области просмотра маркеров, чтобы совместить markerWidth с продолжением линии или пути.
1 2 3 4 5 6 7 |
<marker id="end-circle" markerUnits="userSpaceOnUse" markerWidth="40" markerHeight="40" refX="0" refY="0" orient="auto" > <rect x="0" y="0" width="40" height="20" stroke="black" fill="grey" fill-opacity="0.5"/> <circle cx="10" cy="10" r="10" style="fill:red; stroke-width:1px; stroke:teal;" /> </marker> |
В коде выше для формирования графики маркера использованы две основные фигуры SVG: прямоугольник и окружность, которые расположены в одной прямоугольной области просмотра маркера, ограниченной сторонами markerWidth и markerHeight. Могут быть и более сложные комбинации.
На рис.6 видно, что orient=”auto” помогло только частично. Для правильного расположения маркера необходимо его сдвинуть влево на 20px и поднять вверх на 40px. Для этих целей служат атрибуты маркера refX и refY. При положительных значениях refX маркер сдвигается влево, при отрицательных значениях происходит сдвиг вправо. Для refY положительные значения сдвигают маркер вверх, отрицательные вниз.
1 2 3 4 5 6 |
<marker id="MarkerArrow" refX="20" refY="40" markerUnits="userSpaceOnUse" orient="auto" markerWidth="80" markerHeight="80" > <polyline id="markerPoly1" points="0,0 80,40 0,80 20,40 0,0" fill="none" stroke-width="2" stroke="black" /> </marker> |
Атрибут markerUnits имеет значение по умолчанию – “strokeWidth”, то есть его можно и не писать в определении маркера, но он всё равно будет оказывать своё действие на масштабирование маркера. Видимо разработчики SVG задумывали это свойство атрибута следуя логике, что маркер, как правило, это стрелка, которая имеет небольшие размеры и если толщина линии, к которой присоединен маркер увеличивается, то должен пропорционально увеличиваться и сам маркер.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="200" height="200" version="1.1" viewBox="0 0 200 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <defs> <marker id="MarkerArrow" refX="5" refY="10" markerUnits="strokeWidth" orient="auto" markerWidth="20" markerHeight="20" > <polyline id="markerPoly1" points="0,0 20,10 0,20 5,10 0,0" fill="crimson" fill-opacity="0.7" stroke-width="1" stroke="green" /> </marker> </defs> <line x1="20" y1="80" x2="110" y2="80" style=" marker-start: url(#MarkerCircle); marker-end: url(#MarkerArrow); fill:none; stroke:green; stroke-width:1; "/> </svg> |
При markerUnits=”strokeWidth”, см. 8-ую строку кода, масштаб маркера зависит от толщины линии, указанной в 17-ой строке – stroke-width:1; При таких значениях масштаб отображения маркера будет 1:1 см. Рис.9. При значении stroke-width:4; Размеры маркера увеличатся ровно в 4 раза см. Рис.10.
Выглядит не очень. Наверное лучше было бы пропорционально увеличивать не габаритные размеры маркера, а толщину обводки маркера.
К счастью есть спасение:
Крылья мельницы не напоминают маркеры на Рис.5 этой статьи? 🙂 Да, код взят оттуда, добавлены украшательства и две кнопки: мужской силуэт запускает анимацию при наведении курсора мышки, женский силуэт останавливает анимацию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!-- Four rotating marker blades of the windmill --> <g style=" fill:none; stroke:green; stroke-width:4; marker-end: url(#end-circle);"> <desc>the animation of the four markers </desc> <line x1="120" y1="110" x2="120" y2="40" /> <line x1="130" y1="120" x2="200" y2="120" /> <line x1="120" y1="130" x2="120" y2="200" /> <line x1="110" y1="120" x2="40" y2="120" /> <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 120 120" to="360 120 120" begin="man.mouseover" end="woman.mouseover" dur="2.5s" repeatCount="indefinite" fill="freeze"/> |
Этот пример иллюстрирует рисунки: Рис.6,7 и 8 (см.выше) – на которых изображена коррекция положения маркера относительно линии, к которой он присоединён. Параметр refX отвечает за перемещение маркера вдоль оси x-ов, параметр refY перемещает маркер по оси “y”. В этом примере анимацию запускает “клик” мышки по кнопке “Start” begin=”startButton.click”. Маркер сначала поднимается по “y”, затем перемещается по оси “x”. Вторая анимация начинётся по команде: begin=”refY1.end+1s” то есть после окончания первой анимации, вторая часть анимации начинается через 1 секунду (см. 25-28 строки листинга ниже).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="200" height="200" version="1.1" viewBox="0 0 200 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > <title>attributes marker refX, refY</title> <desc> animation attributes marker refX, refY http://svg-art.ru</desc> <defs> <pattern id="newpattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" > <g fill="#85D2FF" stroke-width="1px" stroke="none" fill-opacity="0.5"> <rect x="0" y="0" width="10" height="10" /> <rect x="10" y="10" width="10" height="10" /> </g> </pattern> <marker id="MarkerArrow" refX="0" refY="0" markerUnits="userSpaceOnUse" orient="auto" markerWidth="80" markerHeight="80"> <polyline id="markerPoly1" points="0,0 80,40 0,80 20,40 0,0" fill="none" stroke="black" stroke-width="2" /> <animate id="refY1" attributeName ="refY" from ="0px" to="40px" begin="startButton.click" dur = "2.5s" fill="freeze" /> <animate attributeName ="refX" from ="0" to="20" begin= "refY1.end+1s" dur = "5s" fill="freeze" /> </marker> </defs> <!-- area fill pattern --> <rect x="0" y="0" width="100%" height="100%" style="stroke: #000000; fill: url(#newpattern);" /> <!-- control button animation - "Start" --> <g id="startButton"> <rect x="20" y="170" width="54px" height="20px" rx="5px" ry="5px" fill="dodgerblue" stroke="blue" /> <text x="27px" y="185px" font-size="18" font-weight="bold" font-family="serif" fill="white">Start</text> </g> <!-- line with attached marker --> <line x1="20" y1="80" x2="110" y2="80" style=" marker-end: url(#MarkerArrow); fill:none; stroke:green; stroke-width:2;" /> <!-- the visibility area of the marker --> <rect x="110" y="80" width="80" height="80" fill="none" stroke="crimson" stroke-dasharray="2,2" /> <g font-size="16" font-weight="bold" font-family="serif" text-anchor="middle" fill="red" > <text x="55" y="75">refX="20"</text> <text x="140" y="20">refY="40"</text> </g> </svg> |
Продолжение. Примеры анимации маркеров ⇛
⇚ viewport и ViewBox SVG pattern element ⇛