15

私は長年のプロジェクトを持っています: ブラウザーで実行され、SVG と Javascript を使用する基本的なベクター グラフィック ツールです (おそらく、これらのようなものをどこかで見たことがあるでしょう)。このツールの機能セットは非常に限られています。これは、対象者が限定されており、目的が非常に具体的であり、実際には、明示的に許可されている機能以外の機能を使用することは許可されていないためです (ご存じのとおり)。欠けている機能の 1 つは、多角形やその他のグラフィック要素の浸食 (インセットまたは細線化とも呼ばれます) および膨張 (アウトセット、太さ、太字) です。

私は Adob​​e Illustrator の Offset Path Effect を何度も使用しており、元のオブジェクトに影響を与えることなく、薄くしたり厚くしたりしたグラフィック オブジェクトのコピーを簡単に作成できます。

同じ機能を SVG で機能させようとしましたが、成功しませんでした。

私は次のことを試しました:
- フィルターを膨張させて浸食しますが、満足のいく結果は得られません (ここの画像を参照してください)
- サーバー側の Python の Shapely ライブラリですが、この回避策では遅すぎて、基本的なポリゴンのみを挿入または外に出すことができます (説明here )
- グラフィック要素のパスデータを変更する可能性のある javascript ライブラリ / コード / 関数を検索しますが、javascript には何も見つかりませんでした

Offset Path Effectのようにこれを実装する意味のある方法はありますか?

4

2 に答える 2

26

これは「あなた自身の質問に答えてください -あなたの知識を共有する、Q&A スタイル」スタイルの回答ですが、より良い回答があれば、自由にキーボードを使用してください。

私はSOを数日しか使用していないので、ギャップに反対票を投じないでください。可変幅のストロークとマスクに基づく、この問題に対する興味深い回避策のアイデアを思いつきました。

しかし、あなたの (または私の) 最初のアイデアから始めましょう。SVG で (薄い) グラフィカル オブジェクトを侵食する場合、明らかに最初に考えられるのは、侵食フィルタを使用することです。

しかし、侵食フィルタ (および拡張も)はピクセル データ (ラスタ化されたパス) を使用するため、結果はすべての場合において見栄えがよくありません。実際、ベクター オブジェクトのフィルタリングに使用したときに見栄えのする侵食を見たことはありません。帽子と口を見てください。

浸食画像

膨張フィルターにも同様の問題があります (鼻が良くなく、野球帽がぼろぼろで、その他の矛盾があります)。

膨張画像

Adobe Illustrator のすべてのユーザーは、図形 (オブジェクト) にさまざまなパス操作を適用するために使用できる優れたパス効果を知っています。これらの効果は元のパス データを変更せず、オブジェクトの変更されたコピーを作成するだけです。最も便利なものの 1 つはOffset Path Effectです。これは、選択したオブジェクトから指定された距離 (または類似のもの) だけオフセットするために使用できます。SVG:s erode および dilate フィルターは、Illustrator の Offset Path Effect と類似していますが、ベクター操作としての品質は (対ビットマップ) 高いです。

現在の状態の SVG 形式は、Illustrator のようなオフセット パスのサポートを欠いていますが、ここに記載されているように、可変幅のストロークとマスクを使用して同じ機能を得ることができます。

SVG マスクの世界に飛び込みましょう。膨張 (またはアウトセット パスまたは厚み付け) は、ストローク幅を増やすだけで実現できますが、侵食 (またはインセット パスまたは細線化) には、マスクなど、さらに何かが必要です。SVG では、任意のグラフィックス オブジェクトまたは 'g' 要素を、現在のオブジェクトを背景に合成するためのアルファ マスクとして使用できます( W3C SVG 1.1 勧告)。

上記は、オブジェクトの塗りをマスクとして使用できるだけでなく、ストロークとしても使用できることを意味します。また、マスクとして使用されるパスのストロークの幅を調整することで、現在のオブジェクト (マスク属性を使用してマスクが適用されるオブジェクト) のどれだけをマスクアウトするかを制御できます

マスクの使用例を見てみましょう。まず、SVG:s defs 要素でパスを定義します。

<defs>
<path id="head_path" d="M133.833,139.777c1 ...clip... 139.777z"/>
</defs>

defs 要素でパスを定義すると、ドキュメントの他の部分で同じデータを繰り返す必要がなくなります。パスの id 属性は、ドキュメントのあるポイントからのパスを参照するために使用されます。

これで、このパス データをマスクで使用できます。

<defs>
...
<mask id="myMask" maskUnits="userSpaceOnUse">
<use xlink:href="#head_path" fill="#FFFFFF" stroke="#000000" 
stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
...
</defs>

'use' 要素は 'path' 要素を参照します。その id は 'head_path' であり、'head_path' 要素のグラフィック コンテンツ (この場合はパス データのみ) がこのマスクに含まれていることを示します。上記の「use」要素で定義されているストローク幅は、オフセット (浸食) 効果の量になります。この量は、次に描画する場合に備えて要素からマスクされます。

よし、最初にマスクなしで「頭」を描いて、それがどれほど美しいか見てみましょう:

...
</defs>
<use x="5" y="5" xlink:href="#head_path" fill="#4477FF" stroke="black"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>

これにより、次の形状が生成されます。

元の形状

次に、マスクを使用して何を達成できるかをテストします。

...
</defs>
<use x="5" y="5" xlink:href="#head_path" fill="#22EE22" stroke="black"
stroke-width="21" stroke-linecap="round" stroke-linejoin="round"
mask="url(#myMask)"/>

上記の「use」要素は、「myMask」をマスクとして使用し、「head_path」をグラフィック コンテンツとして使用するように指示されています。マスク効果が 'use' 要素に適用され、次の形状が描画されます。

マスクされた形状

両方をそれぞれの上に重ねると、元の頭とマスクされた頭を比較できます。

元の形状とマスキングされた形状

悪くない、全く?SVG 浸食フィルターを使用した最初の試みと、マスクされたバージョンを比較してみましょう。

侵食 vs 仮面

左は侵食フィルターをかけ、右はイラストレーターのようなオフセット パス効果を模倣するためにマスクしています。帽子と口に奇妙なアーティファクトはありません!

では拡張はどうでしょうか。鼻のパスの不正確さと野球帽のぼろぼろを取り除く方法はありますか? もちろん。その方法は実にシンプルですが、ハックのようなものです。幸いなことに、マスクを使用する必要はありません。代わりに、ストローク幅を調整して、目的の効果を実現できます。また、ストロークは既に太字化に使用されているため、(必要に応じて) 太字化された形状の周りに黒いストロークを取得するには、少し幅の広いストロークを持つ要素の追加のコピーを追加し、太字化された形状の下に配置する必要があります。

<!-- To get the black stroke -->
<use x="220" y="5" xlink:href="#head_path" fill="red" stroke="black"
stroke-width="24" stroke-linecap="round" stroke-linejoin="round"/>
<!-- To get the boldened shape -->
<use x="220" y="5" xlink:href="#head_path" fill="red" stroke="red"
stroke-width="21" stroke-linecap="round" stroke-linejoin="round"/>

これにより、次の形状が生成されます。

オフセット パス効果が適用されました

元のシェイプと、カスタム オフセット パス効果が適用されたシェイプの両方を次に示します。

オリジナルとオフセット パス効果を適用

カスタムの太字化と膨張フィルターとの比較:

膨張対太字

左のもの (上) は SVG:s 拡張フィルターを使用して拡張され、右のものはカスタム オフセット パス効果を使用して太字になっています。かなりいいですね、好きです。パスは、指定された距離で元のパスを忠実にたどり、ベースボール キャップにスクラップの兆候はありません。

最後に、すべてのワイヤをまとめましょう。 Dilate/Origina/Erode と Offset Path の組み合わせ

左のもの (上) は SVG の膨張/浸食フィルターを使用し、右のものは SVG マスクと太いストロークを使用して実現される Illustrator を模倣したオフセット パス効果を使用します。あなたならどちらを選びますか?

結論: SVG のグラフィック要素を濃くしたり薄くしたりするために、Javascript やその他のスクリプトを使用することは強制されていません。SVG の Erode および Dilate フィルタにはいくつかの使用目的があるかもしれませんが、高品質のパス「変更」にはあまり適していません。マスクの使い方は少し複雑ですが、数回の実験で慣れることができます。将来の SVG が Offset Path Effect をネイティブにサポートし、このようなハックを使用しないことを本当に願っています。

フィルターとマスクで遊ぶために、これらの例で使用されている形状を jsfiddle しました: http://jsfiddle.net/7Y4am/
(少なくともストローク幅を変更するためにテストしてください!)

(ネイティブスピーカーを死ぬまで笑わせる下手な英語で申し訳ありませんが、覚えておいてください、私は英語をネイティブに話さない人類の94%に属しています。しかし幸いなことに、Google翻訳があります。)

于 2012-10-04T09:04:00.900 に答える