Можете ли вы контролировать, как рисуется ширина штриха SVG?

В настоящее время создается приложение SVG на основе браузера. В этом приложении различные формы могут быть стилизованы и размещены пользователем, включая прямоугольники.

Когда я применяю stroke-width к элементу SVG rect, например 1px, штрих применяется к смещению rect s и вставка разными способами разными браузерами. Это оказывается неприятным, особенно когда я пытаюсь вычислить внешнюю ширину и визуальное положение прямоугольника и расположить его рядом с другими элементами.

Например:

  • Firefox добавляет 1px-вставку (снизу и слева) и смещение 1px (вверху и справа)
  • Chrome добавляет 1px-вставку (вверху и слева) и смещение 1px (снизу и справа)

Моим единственным решением до сих пор было бы рисовать фактические границы (возможно, с помощью инструмента path) и расположить границы за поглаженным элементом. Но это решение является неприятным обходным решением, и Id предпочитает не идти по этой дороге, если это возможно.

Итак, мой вопрос: можете ли вы контролировать, как SVGs stroke-width нарисованы на элементах?

Ответ 1

Нет, вы не можете указать, выполняется ли штрих внутри или вне элемента. Я сделал предложение рабочей группе SVG для этой функции в 2003 году, но не получил поддержки (или обсуждения).

SVG proposed stroke-location example, from phrogz.net/SVG/stroke-location.svg

Как я отметил в предложении,

  • вы можете достичь того же визуального результата, что и "внутри", удвоив ширину вашего штриха, а затем используя обтравочный контур, чтобы скопировать объект сам по себе, и
  • вы можете достичь того же визуального результата, что и "снаружи", удвоив ширину штриха, а затем наложив на него нерабочую копию объекта сверху.

Изменить. Этот ответ может быть неправильным в будущем. Для достижения этих результатов следует использовать SVG Vector Effects, объединив veStrokePath с veIntersect (для "внутри" ) или с помощью veExclude (для "снаружи" ). Тем не менее, Vector Effects по-прежнему являются рабочим модулем проекта, в котором нет реализаций, которые я еще могу найти.

Изменить 2. Спецификация черновика SVG 2 включает свойство stroke-alignment (с центром | внутри | вне возможные значения). Это свойство может впоследствии превратиться в UA.

Редактировать 3: забавно и разочаровывающе, рабочая группа SVG удалила stroke-alignment из SVG 2. Вы можете увидеть некоторые из проблем, описанных после прозы .

Ответ 2

UPDATE: Атрибут stroke-alignment был 1 апреля перенесен на совершенно новую спецификацию, называемую SVG Strokes.

Как и в редакторе редакторов SVG 2.0 от 26 февраля 2015 года (и, возможно, с 13 февраля), присутствует свойство stroke-alignment со значениями inner, center (по умолчанию) и outer.

Кажется, что он работает так же, как свойство stroke-location, предложенное @Phrogz и более поздним предложением stroke-position. Это свойство было запланировано по крайней мере с 2011 года, но кроме аннотации, в которой говорилось

SVG 2 должен включать способ указания положения хода

он никогда не был детализирован в спецификации, поскольку он был отложен - до сих пор, кажется.

Никакой браузер не поддерживает это свойство, или, насколько мне известно, какие-либо новые функции SVG 2, но, надеюсь, они скоро появятся по мере появления спецификации. Это была собственность, которую я лично призывал, и я очень рад, что она наконец появилась в спецификации.

Кажется, есть некоторые проблемы относительно того, как свойство должно вести себя как на открытых путях, так и на циклах. Эти проблемы, скорее всего, продлят реализацию в браузерах. Однако я обновляю этот ответ с новой информацией, поскольку браузеры начинают поддерживать это свойство.

Ответ 3

Я нашел простой способ, который имеет несколько ограничений, но работал для меня:

  • определить форму в определениях
  • определить путь клипа, ссылающийся на форму
  • использовать его и удвоить ход, так как снаружи обрезается

Вот рабочий пример:

<svg width="240" height="240" viewBox="0 0 1024 1024">
<defs>
	<path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z"/>
	<clipPath id="clip">
		<use xlink:href="#ld"/>
	</clipPath>
</defs>
<g>
	<use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="#00D2B8" clip-path="url(#clip)"/>
</g>
</svg>

Ответ 4

Здесь функция, которая будет подсчитывать, сколько пикселей вам нужно добавить - используя данный штрих - вверху, справа, внизу и слева, все на основе браузера:

var getStrokeOffsets = function(stroke){

        var strokeFloor =       Math.floor(stroke / 2),                                                                 // max offset
            strokeCeil =        Math.ceil(stroke / 2);                                                                  // min offset

        if($.browser.mozilla){                                                                                          // Mozilla offsets

            return {
                bottom:     strokeFloor,
                left:       strokeFloor,
                top:        strokeCeil,
                right:      strokeCeil
            };

        }else if($.browser.webkit){                                                                                     // WebKit offsets

            return {
                bottom:     strokeCeil,
                left:       strokeFloor,
                top:        strokeFloor,
                right:      strokeCeil
            };

        }else{                                                                                                          // default offsets

            return {
                bottom:     strokeCeil,
                left:       strokeCeil,
                top:        strokeCeil,
                right:      strokeCeil
            };

        }

    };

Ответ 5

Как отмечали выше люди, вам придется либо пересчитать смещение в координаты пути хода, либо удвоить его ширину, а затем замаскировать одну или другую сторону, потому что SVG не только поддерживает выравнивание инсультатора Illustrator, но PostScript doesn Это тоже.

Спецификация для штрихов в Adobe PostScript Manual 2nd edition гласит: " 4.5.1 Stroking: Оператор stroke рисует линию некоторой толщины вдоль текущего пути. Для каждого прямого или изогнутого сегмента на пути ход рисует линию, центрированную на сегменте со сторонами, параллельными сегменту. "(Выделение их)

В остальной части спецификации нет атрибутов для смещения позиции линии. Когда Illustrator позволяет вам выровнять внутри или снаружи, он пересчитывает фактическое смещение пути (поскольку он все же вычислительно дешевле, чем надпечатка, затем маскировка). Координаты пути в документе .ai являются справочными, а не то, что растрируется или экспортируется в окончательный формат.

Поскольку родной формат Inkscape является спецификацией SVG, он не может предложить функцию, которой не хватает.

Ответ 6

Вы можете использовать CSS для стилизации порядка обводки и заливки. То есть сначала обведите, а затем залейте второе и получите желаемый эффект.

MDN о paint-order: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/paint-order

Код CSS:

paint-order: stroke;

Ответ 7

Вот работа для внутренней границы rect с помощью symbol и use.

Пример: https://jsbin.com/yopemiwame/edit?html,output

SVG

<svg>
  <symbol id="inner-border-rect">
    <rect class="inner-border" width="100%" height="100%" style="fill:rgb(0,255,255);stroke-width:10;stroke:rgb(0,0,0)">
  </symbol>
  ...
  <use xlink:href="#inner-border-rect" x="?" y="?" width="?" height="?">
</svg>

Примечание. Обязательно замените ? на use на реальные значения.

Фон. Причина этого заключается в том, что символ создает новый видовой экран, заменяя symbol на svg и создавая элемент в DOM тени. Этот svg теневой DOM затем связан с вашим текущим элементом svg. Обратите внимание, что svg может быть вложенным, и каждый svg создает новый видовой экран, который скопирует все, что перекрывается, включая перекрывающуюся границу. Для более подробного обзора того, что происходит, прочитайте эту фантастическую статью от Sara Soueidan.

Ответ 8

A (грязное) возможным решением является использование шаблонов,

вот пример с внутренним гладкоугольным треугольником:

https://jsfiddle.net/qr3p7php/5/

<style>
#triangle1{
  fill: #0F0;
  fill-opacity: 0.3;
  stroke: #000;
  stroke-opacity: 0.5;
  stroke-width: 20;
}
#triangle2{
  stroke: #f00;
  stroke-opacity: 1;
  stroke-width: 1;
}    
</style>

<svg height="210" width="400" >
    <pattern id="fagl" patternUnits="objectBoundingBox" width="2" height="1" x="-50%">
        <path id="triangle1" d="M150 0 L75 200 L225 200 Z">
    </pattern>    
    <path id="triangle2" d="M150 0 L75 200 L225 200 Z" fill="url(#fagl)"/>
</svg>

Ответ 9

Я не знаю, насколько это полезно, но в моем случае я просто создал еще один круг с рамкой и поместил его "внутрь" другой фигуры.