SVGのストローク幅の描画方法を制御できますか?


204

現在、ブラウザベースのSVGアプリケーションを構築しています。このアプリ内では、長方形を含むさまざまな形状をユーザーがスタイル設定および配置できます。

sayのstroke-widthSVG rect要素にaを適用すると1px、ストロークはrectのオフセットとインセットにさまざまなブラウザによってさまざまな方法で適用されます。これは、特に長方形の外側の幅と視覚的な位置を計算して、他の要素の隣に配置しようとするときに、厄介であることがわかります。

例えば:

  • Firefoxは1pxインセット(下と左)と1pxオフセット(上と右)を追加します
  • Chromeは1ピクセルのインセット(上と左)と1ピクセルのオフセット(下と右)を追加します

これまでの私の唯一の解決策は、実際に境界線を自分で(おそらくpathツールを使用して)描画し、境界線をストローク要素の背後に配置することです。しかし、この解決策は不快な回避策であり、できればこの道をたどらない方がいいと思います。

だから私の質問は、SVG stroke-widthを要素に描画する方法を制御できますか?


これを達成するために使用できるフィルターハックがありますが、それは素晴らしい解決策ではありません
Michael Mullany

2
ありpaint-orderますが、「外に整列」を取得しますので、あなたは、塗りつぶし、ストロークの一番上に描画されるべきであることを、指定することができるパラメータは、参照jsfiddle.net/hne0kyLg/1
イワンKuckir

css 'outline-'属性を使用してこれを行う方法が見つかりました:codepen.io/badcat/pen/YVzmYY。ブラウザー全体でこれがどのようにサポートされているかはわかりませんが、役に立つかもしれません。
bplmp 2018年

回答:


375

いいえ、ストロークを要素の内側または外側のどちらに描くかは指定できません。私が作っ提案 2003年に、この機能のためのSVGワーキンググループには、それは何のサポート(またはディスカッション)を受信していません。

SVGが提案したストローク位置の例(phrogz.net/SVG/stroke-location.svgから)

私が提案で述べたように、

  • ストローク幅を2倍にし、クリッピングパスを使用してオブジェクトをそれ自体にクリップすることで、「内側」と同じ視覚結果を得ることができます。
  • ストローク幅を2倍にして、オブジェクトのストロークなしのコピーをオブジェクトの上にオーバーレイすることで、「外側」と同じ視覚結果を得ることができます。

編集:この答えは将来間違っているかもしれません。これらの結果は、SVGベクトル効果を使用veStrokePathしてveIntersect(「内側」の場合)またはveExclude(「外側」の場合)と組み合わせることで実現できるはずです。ただし、ベクターエフェクトはまだ機能しているドラフトモジュールであり、まだ実装を見つけることができません。

編集2:SVG 2ドラフト仕様にはstroke-alignmentプロパティが含まれています(可能な値は中央|内側|外側)。このプロパティは、最終的にUAになる可能性があります。

編集3:面白くて残念なことに、SVGワーキンググループはstroke-alignmentSVG 2から削除されました。散文の後に説明されている懸念のいくつかをここで見ることができます


2
そうかもしれないと思った。これを解決するために、getStrokedBBox()というgetBBox()のラッパー関数を作成しました。このラッパーは、ブラウザーが図形のインセットとオフセットにストロークを適用する方法に従ってBBoxを返します。これは完璧ではありません(最新のブラウザーバージョンをチェックし続ける必要があります)が、現時点では形状の外幅を正確に提供しています。
Steve

6
@Phrogzたぶん、10年が経過する前に表示されるでしょう。svgwg.org/svg2-draft/painting.html#SpecifyingStrokePaint注釈
frenchone

1
ついに登場!私は、1つは、このプロパティの到着を本当に強く求めてきました。
mnsth 2015年

私は、SVGGeometryElementの輪郭をトレースするためのsvg-contourスクリプトを作成しました。これは、ストロークの配置の回避策として使用できます。興味がある人は、ここで
maioman

2
提案に賛成できるページはありますか?ありがとう。ばかげているようですが、サポートされていません。
マヒッシュ

57

更新:このstroke-alignment属性は2015年4月1日でしたが、SVGストロークと呼ばれる完全に新しい仕様に移行しました

2015年2月26日のSVG 2.0エディタードラフト(およびおそらく2月13日以降)では、stroke-alignmentプロパティが存在し、innercenter (デフォルト)outer

それは同じように動作するようです stroke-location@Phrogzによって提案さプロパティと後のstroke-position提案とです。このプロパティは少なくとも2011年以降に計画されていますが、

SVG 2にはストローク位置を指定する方法が含まれます

延期されたため、仕様に詳述されたことはありません-今まではそうです。

このプロパティ、または私の知る限りでは、新しいSVG 2機能のいずれかをサポートしているブラウザーはまだありませんが、仕様が成熟するとすぐに機能することを期待しています。これは私が個人的に求めている特性であり、仕様に最終的に含まれていることを本当に嬉しく思います。

プロパティがループだけでなくオープンパスでもどのように動作するかについて、いくつかの問題があるようです。これらの問題は、おそらく、ブラウザー間での実装を延長するでしょう。ただし、ブラウザがこのプロパティをサポートし始めたら、この回答を新しい情報で更新します。


1
stroke-alignmentW3C草案であるSVG Strokesで指定されています。一方、SVG 2 W3C Editor's Draftでは、ストローク配置プロパティはsvgwg.org/svg2-draft/painting.html#SpecifyingStrokePaintのSVG仕様に含まれるべきであると述べていますが、その仕様はすでにW3C Candidate Recommendationステータスに達しており、そのようなプロパティはありませんstroke-position提案へのリンクを除いて、仕様ではそうではないように見えます。
Patrick Dark

47

いくつかの制限がある簡単な方法を見つけましたが、私にとってはうまくいきました:

  • defsで形状を定義する
  • 形状を参照するクリップパスを定義する
  • それを使用し、外側が切り取られるようにしてストロークを2倍にします

ここで実際の例:

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


2
私が見つけた最良の答え
Ed Kolosovsky 2017年

1
賢いソリューション。ありがとう
Vince Yuan

これは答えとして受け入れられるべきです。<defs>と<use>の使用は、現在利用できる最もエレガントなソリューションです。
Nyerguds

素晴らしい解決策。外側のストロークを作成するには、どのように反転させますか?
Lucent

なぜトップレベルなの<use>か?パスとクリップパスを直接挿入しないのはなぜですか?これは問題なく動作します<svg width="240" height="240" viewBox="0 0 1024 1024"> <path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z" clip-path="url(#clip)" stroke="#0081C6" stroke-width="160" fill="#00d2b8"/> <clipPath id="clip"> <use xlink:href="#ld"/> </clipPath> </svg>。(はい、これは完全に合理的で正しいSVGであり、どこでも正しくレンダリングされます。再帰を恐れる必要はありません。)
Chris Morgan

30

CSSを使用して、ストロークと塗りの順序をスタイル設定できます。つまり、最初にストロークしてから2番目に塗りつぶすと、目的の効果が得られます。

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

CSSコード:

paint-order: stroke;

これは完璧です!共有してくれてありがとう
BrunoFenzl

1
リンクされたドキュメントは、ストロークが内側にあるか、外側にあるか、または中央にあるかを示していないようです?ストロークが描画される場所を制御する方法を明確にできますか?ありがとう。
Crashalot、

2
ストロークはいつものように中央に配置されますが、塗りつぶしがある場合、最初にストロークをペイントするようにペイントの順序を調整すると、ストロークの内側の半分がペイントされるため、描画と同じ効果があります。外の半分の太さのストローク。
クリスモーガン

7

以下は、指定されたストロークを使用して、上、右、下、左にすべてブラウザに基づいて追加する必要があるピクセル数を計算する関数です。

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

上記の人々が指摘したように、SVGはIllustratorのストロークの配置をネイティブにサポートしていないだけでなく、PostScriptもどちらもサポートしていないため、ストロークのパス座標へのオフセットを再計算するか、幅を2倍にして、片側または反対側をマスクする必要があります。 。

Adobe社のPostScriptマニュアル第2版状態におけるストロークの仕様:「4.5.1ストローキング:ストロークオペレータは、現在の経路に沿っていくつかの太さの線を描画する各直線又は曲線セグメントのパスでは、ストロークはれる線描画を中心にし辺が平行なセグメントセグメント。」(彼らの強調)

仕様の残りの部分には、ラインの位置をオフセットするための属性はありません。Illustratorで内側または外側に位置合わせすると、実際のパスのオフセットが再計算されます(オーバープリントやマスキングよりも計算量が少ないため)。.aiドキュメントのパス座標は参照であり、ラスタ化または最終形式にエクスポートされるものではありません。

InkscapeのネイティブフォーマットはスペックSVGであるため、スペックに欠けている機能を提供できません。


4

ここでは、およびを使用して内側の境界線 rectを回避しますsymboluse

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実際の値を持ちます。

背景:これが機能する理由は、シンボルがシャドウDOMで要素を置き換えsymbolsvg作成することにより、新しいビューポートを確立するためです。これsvgにより、シャドウDOMが現在のSVG要素にリンクされます。はsvg入れ子にすることができ、すべてsvgが新しいビューポートを作成することに注意してください。何が起こっているかのより詳細な概要については、Sara Soueidanによるこの素晴らしい記事をご覧ください。


2

それがどれほど役立つかわかりませんが、私の場合は、境界線のみの別の円を作成し、それを他の形状の「内側」に配置しました。


0

(汚れた)可能な解決策は、パターンを使用することです。

以下は、内側のストロークされた三角形の例です。

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>

0

Xavier Hoのソリューションストロークの幅を2倍にし、ペイントの順序を変更するというは素晴らしいですが、塗りつぶしが単色で、透明度がない場合にのみ機能します。

私は他のアプローチを開発しましたが、もっと複雑ですが、どんなフィルでも機能します。楕円またはパスでも機能します(後者では、奇妙な動作のコーナーケースがいくつかあります(たとえば、開いたパスが交差しているが、あまり交差していない)。

トリックは、2つのレイヤーで形状を表示することです。1つはストロークなし(塗りつぶしのみ)で、もう1つは2倍幅のストロークのみ(透明な塗りつぶし)でマスク全体を通過しますが、元の形状はストロークなしで非表示になります。

  <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"/>
    <mask id="mask">
      <use xlink:href="#ld" stroke="#FFFFFF" stroke-width="160" fill="#FFFFFF"/>
      <use xlink:href="#ld" fill="#000000"/>
    </mask>
  </defs>
  <g>
    <use xlink:href="#ld" fill="#00D2B8"/>
    <use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="red" mask="url(#mask)"/>
  </g>
  </svg>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.