フーノページ



CSSアニメーション

SVG、feMorphologyフィルターで
要素を太く/細くする。










syntax。

<filter id = "「「5morph」」">
<feMorphology operator = "「「1dilate/erode」」" radius = "数値">
</feMorphology>  
</filter>
「「3<!--プレゼンテーション属性-->」」
<rect filter = "url(「「5#morph」」)" ../>
「「3/*CSS*/」」
#elm {filter:url(「「5#morph」」)}


膨張/侵食を起こすフィルター。


こんにちは、「ふ」です。
今回はSVGのfeMorphologyフィルターについて紹介します。

Morphologyの「morph」は「変形処理」という意味で、オブジェクトに変形を施します。

⬆︎において、線の部分は元オブジェクトの形状を示しています。
青い部分がfeMorphologyを施したもの。このフィルタにはdilate(膨張)とerode(侵食)の2種類があり、要素を太く/細くさせることができます。

SVGのfilterは何種類かのものを合成させないと使いものにならないものが多いのですが、feMorphologyに関しては単品でも楽しい効果が表現できます。ぜひ使い方を知っておきましょう。



feMorphologyのパラメータ。


@1@ operator 「「3〜侵食か膨張を指定」」
    値:erode(初期値)/dilate
    
@2@ radius 「「3〜フィルターの掛かり具合を半径で指定」」
    値:xy共通またはx,y個別の数値
    初期値:0

feMorphologyフィルター固有の属性は⬆︎のとおり。

operator属性は、erode(侵食)かdilate(膨張)のどちらを使用するかを指定します。初期値はerodeとなっており、特に指定がなければ侵食が採用されます。

フィルターの掛かり具合はradius属性に数値を指定することで、調節します。数値が大きくなるほど深くフィルターが掛かることになります。
初期値は0(まったく侵食/膨張を行わない)となっています。0以上の数値を指定してやらないと、フィルター効果が得られません。
またradius属性に2つの数値を指定すると、x/y方向に対して個別に効果を与えることができます。


⬆︎のアウトライン化したテキストで試していくことにします。

<svg viewBox="0 0 841.9 313.4" >
    <g>
        <path d = "「「3 〜略〜 」」" />
        <path d = "「「3 〜略〜 」」" />
        <path d = "「「3 〜略〜 」」" />
        <path d = "「「3 〜略〜 」」" />
        <path d = "「「3 〜略〜 」」" />
    </g>
</svg>

画像のSVGコードを簡単にしたもの⬆︎。
5文字のテキストをアウトライン化させているので、5つの<path>要素で構成されています(パスデータは複雑なので略)。そして一括でフィルターを掛けられるように、<g>要素でグループ化しておきました。




erode(侵食)。


それではerode(侵食)を使ってみましょう。

<svg viewBox="0 0 841.9 313.4" >

    「「3<!--フィルターを定義-->」」
    <filter id = "「「5morph」」">「「1 ..@1@」」
    <feMorphology operator = "erode" radius = "5"/>「「1 ..@2@」」
    </filter>
    
    「「3<!--フィルターを適用-->」」
    <g filter = "url(「「5#morph」」)">「「1 ..@3@」」
        <path class = "letter1" d = "「「3 〜略〜 」」" />
        <path class = "letter1" d = "「「3 〜略〜 」」" />
        <path class = "letter1" d = "「「3 〜略〜 」」" />
        <path class = "letter1" d = "「「3 〜略〜 」」" />
        <path class = "letter1" d = "「「3 〜略〜 」」" />
    </g>
</svg>

@1@ <filter> 〜 </filter>でフィルターコンテナを用意。参照できるよう、id名「morph」としておきました。

@2@ filter要素の内部に、<feMorphology>フィルターを挿入します。
・operator属性にはerode(侵食)を指定。なお、erodeは初期値なので明記しなくてもOKです。
・radiusは「5」としました。

@3@ path要素をまとめた<g>要素。filter属性に「#morph」を指定します。

結果⬆︎です。


元画像⬆︎と比べてみると「侵食」されて全体が細くなっているのがわかります。

radius属性では、x方向とy方向の度合いを個別に指定することも可能です。
x方向は「0(侵食なし)」、y方向は「15」にしてみます。

<filter id = "morph">
    <feMorphology operator = "erode" radius = "0 15"/>
</filter>    


単調なゴシック体が、ちょっとデザインチックになりました。
ではxy方向とも、radiusを「15」にしてみます。

<filter id = "morph">
    <feMorphology operator = "erode" radius = "15"/>
</filter>    


xy両方向から「15」の侵食が行われるので、表示される部分はわずかになりました。
operator : erodeにおいて、radiusを大きくしていくと徐々に侵食が進み、やがては見えなくなってしまいます。



dilate(膨張)。



次はdilate(膨張)を試します。
指定方法は、feMorphologyのoperator属性を「dirate」に差し替えるだけでOKです。

<filter id = "morph">
    <feMorphology operator = "「「1dilate」」" radius = "10"/>
</filter>    

radiusはxy方向共通で「10」としました。


結果⬆︎です。クッキーみたいなフォントになりました。
dilateでも、xy方向個別のradiusを指定してみましょう。

<filter id = "morph">
    <feMorphology operator = "dilate" radius = "「「110 0」」"/>
</filter>    


縦横の膨張に差をつけることで、明朝体っぽくなりました。



filterUnitsの操作。



星型のオブジェクトに対し、radiusの大きな膨張を施してみます。

<filter id = "morph">
    <feMorphology operator = "dilate" radius = "「「260」」"/>
</filter>    



オブジェクトは大きく膨張しましたが、なんだか端っこが途切れてしまっています。
これは<filter>要素のfilterUnits属性が、初期値の「objectBoundingBox」になっているためです。


<filter>要素のfilterUnits属性は「フィルター効果の描画対象」を指定します。

その初期値は「objectBoundinsBox」となっており、オブジェクトのバウンディングボックス(要素を囲むことのできる最小の長方形)より少し大きい範囲が描画対象となります。一方で属性値を「userSpaceOnUse」とすると、viewBox(画像の表示範囲)がその対象になります。

filter効果がバンディングボックスから大きくはみ出しそうなときは、filterUnits属性を「userSpaceOnUse」に指定しましょう。

<filter id = "morph" filterUnits = "「「1userSpaceOnUse」」">
    <feMorphology operator = "dilate" radius = "60"/>
</filter>    



はみ出した部分も、ちゃんと描画されました。




つかいどころを調査。


feMorphologyの基本的な操作がわかったところで、いろいろ試して特徴や使いどころを探っていきます。

radiusは座標値。



feMorphologyのradius属性の数値は、座標1目盛ぶんを「1」として扱われます。
⬆︎は半径2の円(黄緑)に対して、radius = 1のdilateを施したもの(グレーの部分)。ちょうど座標目盛ぶん、膨張しているのがわかります。


そのため同じ形状をした要素でも、その大きさによってフィルターを掛けた結果が変わってきます。

<filter id = "「「5star_morph」」" filterUnits = "userSpaceOnUse">
<feMorphology operator = "dilate" radius = "25"/>    
</filter>
 
「「3<!--大きいほうの星-->」」
<path filter = "url(「「5#star_morph」」)"  d=" 「「3〜略〜」」"/>
「「3<!--小さいほうの星-->」」
<path filter = "url(「「5#star_morph」」)"  d=" 「「3〜略〜」」"/>

要素の大小に関わらず「座標25個ぶんのradius」で膨張効果が施されています。
大きいほうの星はまだまだ「星型」を保っているのに対し、小さいほうの星はかなり角が取れて元の形状を失いつつあります。


境界部分が混ざり合う。

feMorphologyは「色の境界部分が混ざり合う」という性質をもっています。

2つの星型オブジェクト。
 左 塗り:なし 線:オレンジ
 右 塗り:青 線:オレンジ

を用意しました。ここに同じfeMorphologyのdilateを掛けてみます。

<filter id = "color_morph" filterUnits = "userSpaceOnUse">
<feMorphology operator = "dilate" radius = "25"/>    
</filter>

膨張させた結果⬆︎です。
左の星はオレンジの部分が太くなっています。右の青で塗りつぶしていた星は、外側のオレンジの線と内側の青い塗りつぶしの間に、ピンクの領域ができています。

塗りなしの星は、線のオレンジが透明部分とまざり、オレンジのまま。
青で塗りつぶした星は、青とオレンジの境界部分が混ざり合い、ピンクの部分が生じたということです。

<filter id = "color_morph" filterUnits = "userSpaceOnUse">
<feMorphology operator = "erode" radius = "2"/>    
</filter>

erodeでも試してみました。

塗りなしの星はやせ細っただけですが、青で塗りつぶした星は線の部分がなんだか黒ずんでいます。
また塗りなしの星について、全体の形状が変化していないことにも注目です。


こちらは塗りのみ、線なしの星2つ。右の星にだけ、radius20のerodeを掛けていますが、見た目の形状は小さくなってしまっています。
先ほどの塗りなしの星は、見た目の形状は変わらず、線だけがやせ細っていました。

feMorphologyは線/塗りの区別はなく、最終的に表示されるpx(画素の持つ色情報)に対して作用していることがわかります。



HTML要素に使ってみる。

HTMLの<body>内に<svg>要素を使ってフィルターを定義しておけば、HTML要素に対してSVGフィルターを使用することも可能です。

<body>
    <p>
    弱々しいテキスト
    </p>
<body>

弱々しいテキスト

⬆︎この<p>要素にSVGのfeMorphologyフィルターを試していきます。
erodeを使って、弱々しさを醸し出してみましょう。

<body>
<svg style = "「「2position:fixed;」」">
<filter id = "「「5text_morph」」">
<feMorphology operator = "erode" radius = "0.5"/>    
</filter> 
</svg>

<p style = "filter:url(「「5#text_morph」」);">
弱々しいテキスト
</p>
<body>

<body>内に<svg>要素を記述していますが、CSSでposition : fixedとしています。これはHTML内に<svg>要素を定義したときに、自動的に300px*150pxのSVG領域が確保されてしまうためです。そこでfixedを使って全体のレイアウトに関与しないようにしました。

弱々しいテキスト

⬆︎ちゃんと弱々しくすることができました。
<span>タグを使って文章の一部を消極的にすることもできそうですね。



画像に使ってみる。

◾️ kuro.jpeg



今度は画像にfeMorphologyフィルターを使ってみましょう。

<body>

「「3<!--filterを定義-->」」
<svg style = "position:fixed;">
    <filter id = "「「5img_morph」」">
    <feMorphology operator = "erode" radius = "6"/>    
    </filter> 
</svg>

「「3<!--画像を表示-->」」
<img class = "kuro" src = "kuro.jpeg">
    
「「3<!--filterを指定-->」」
<style>
    .kuro {filter:url(「「5#img_morph」」);}
</style>

</body>



結果⬆︎です。
床のフローリングの継ぎ目が太くなっています。やはり輪郭の付近で「混ざり合い」が起きているんですね。他にも全体的に色の境界線が掛け合わされて、水彩絵の具で描いたような画像になりました。

画像はerodeで試したものです。ちなみにdilateを掛けるとクロちゃんの顔が怖くなるので、掲載するのをやめました。




試しながら整えよう。


最後までお読みくださり、ありがとうございました。

通常SVGのフィルターは幾つかの種類を組み合わせて使われることが多いのですが、その操作は難解で、慣れが必要となってきます。
その点、feMorphologyにおいては単品でも色々な効果が楽しめるので、SVGフィルター初心者にとっては入り込みやすいですね。手始めに使ってみるものとしては最適なものです。

SVGのフィルターシリーズはまだ始まったばかり。これからも記事を追加していくので、楽しみにしていてください。
ではまた〜 🎵




「ふ」です。

ふ

ベクターグラフィック、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。