Можете ли вы контролировать, как рисуется ширина хода SVG? - PullRequest
180 голосов
/ 30 августа 2011

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

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

Например:

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

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

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

Ответы [ 9 ]

337 голосов
/ 01 сентября 2011

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

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

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

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

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

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

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

55 голосов
/ 01 марта 2015

ОБНОВЛЕНИЕ: Атрибут 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, но, надеюсь, они появятся в ближайшее время, когда спецификации будут готовы. Это свойство, которое я лично хотел получить, и я очень рад, что оно наконец-то есть в спецификации.

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

33 голосов
/ 23 августа 2015

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

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

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

<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>
9 голосов
/ 09 августа 2018

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

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

Код CSS:

paint-order: stroke;
7 голосов
/ 02 сентября 2011

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

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
            };

        }

    };
6 голосов
/ 04 ноября 2014

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

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

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

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

3 голосов
/ 30 июля 2015

Вот обходной путь для с внутренней границей 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 s может быть вложенным, и каждый svg создает новый видовой экран, который обрезает все перекрывающиеся области, включая перекрывающуюся границу. Для более подробного обзора происходящего прочитайте эту фантастическую статью Сары Соуэйдан.

1 голос
/ 08 ноября 2016

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

0 голосов
/ 03 июня 2015

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

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

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>
...