パスへのSVGサークル分解
公開: 2022-03-10この記事は告白から始まります:私はSVGを手作業でコーディングするのが好きです。 常にそうであるとは限りませんが、私の好みを共有していない人々に特有のように思われることがよくあります。 ツールでは不可能な方法でSVGを最適化する(パスをより単純なパスまたは形状に変える)、またはD3やGreensockなどのライブラリがどのように機能するかを単に理解するなど、SVGを手動で記述できることには多くの利点があります。 。
そうは言っても、SVGの円形と、基本的な円を通過するときにそれらを使ってできることをもっと詳しく見ていきたいと思います。 なぜサークル? まあ、私はサークルが大好きです。 彼らは私のお気に入りの形です。
まず最初に(SVGで基本的な円を見たことがあるといいのですが)、これが1つを示すペンです。
円を使って多くのことを行うことができます。円をアニメーション化したり、さまざまな色を適用したりすることができます。 それでも、SVG 1.1では円にできない2つの非常に優れた点があります。別のグラフィック要素を円のパスに沿って移動させることはできず( animateMotion
要素を使用)、円のパスに沿ってテキストを形成することはできません(これにより、 SVG 2.0がリリースされた後にのみ許可されます)。
私たちのサークルを道に変える
サークルからパスを作成するのに役立つ小さなオンラインツールがあります(ここで試してみることができます)が、舞台裏で実際に何が起こっているのかを知ることができるように、すべてを最初から作成します。
円形のパスを作成するには、実際に2つの円弧、つまり1つのパスで円を完成させる半円を作成します。 上記のSVGでお気づきかもしれませんが、属性CX
、 CY
、およびR
はそれぞれ、円がX軸とY軸に沿って描画される場所を定義し、 R
は円の半径を定義します。 CX
とCY
は円の中心を作成するため、円はその点の周りに描画されます。
その円を複製すると、次のようになります。
<path d=" M (CX - R), CY a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 " />
CX
は円のcx
属性と同じであることに注意してください。 同じことが、円のCY
とcy
属性、および円のR
とr
属性にも当てはまります。 小さい文字はa
楕円弧のセグメントを定義するために使用されます。 オプションのZ
(またはz
)を使用してパスを閉じることができます。
小文字a
は、現在の位置を基準にして描かれた楕円弧の始まりを示します。特定の場合は、次のようになります。
<path d=" M 25, 50 a 25,25 0 1,1 50,0 a 25,25 0 1,1 -50,0 " />
あなたはこのペンで起こっている魔法を見ることができます:
パスの下に隠れているのは、赤い塗りつぶしのある円です。 パスの値を試してみると、パスが円を完全に覆っている限り(パス自体は同じサイズの円です)、その円が表示され、正しく実行されていることがわかります。 。
また、相対的な円弧を描画している限り、描画する円弧ごとa
コマンドを繰り返す必要がないことも知っておく必要があります。 アークに対して最初の7つの入力が完了すると、次のアークに対して次の7つの入力が取得されます。
パスの2番目a
を削除することにより、上のペンでこれを試すことができます。
a 25,25 0 1,1 50,0 25,25 0 1,1 -50,0
これは同じように見えるかもしれませんが、描画を完了する準備ができるまでそのままにしておくことを好みます。これは、自分がどこにいるかを追跡するのにも役立ちます。
このパスのしくみ
まず、画像内の絶対位置にあるX,Y
座標に移動します。 そこには何も描画されません—ただそこに移動します。 円要素CX
の場合、 CY
は円の中心を示すことに注意してください。 ただし、楕円弧で発生するように、弧の真のCX
とCY
は、その弧の他のプロパティから計算されます。
つまり、 CX
を50
にし、半径を25
にする場合は、 50 - 25
に移動する必要があります(もちろん、左から右に描画する場合)。 これは、最初の円弧が25 X, 50 Y
から描画され、その結果、最初の円弧が25,25 0 1,0 50,0
になることを意味します。
アークの値25,25 0 1,0 50,0
が実際に何を意味するかを分解してみましょう。
-
25
:円弧の相対X半径。 -
25
:円弧の相対Y半径。 -
0 1,0
:3つの中間値(rotation、large-arc-flag、およびsweep-flagプロパティ)については、現在の例のコンテキストではそれほど重要ではないため、説明しません。両方のアークで同じです。 -
50
:円弧の終了X座標(相対)。 -
0
:円弧の終了Y座標(相対)。
2番目のアークは25,25 0 1,0 -50,0
です。 このアークは、最後のアークが描画を停止した場所から描画を開始することに注意してください。 もちろん、XとYの半径は同じですが( 25
)、終了するX座標は現在の座標の-50
です。
明らかに、この円はさまざまな方法で描かれている可能性があります。 円をパスに変えるこのプロセスは、分解として知られています。 SVG 2仕様では、円の分解は4つの円弧で行われますが、現在、セグメント完了クローズパスという名前の機能に依存しているため、推奨される方法はまだ使用できません。
さまざまな方法で円を描くことができることを示すために、さまざまな例を含む小さなペンを用意しました。
よく見ると、元の円と、その円の上にパスを描画する方法の5つの異なる例が表示されます。 各パスには、 CX
、 CY
、およびR
値を使用して円を作成することを説明する子desc
要素があります。 最初の例はここで説明したものですが、他の3つの例では、コードを読んで理解できるバリエーションを使用しています。 最後の例では、2つではなく4つの半円弧を使用しており、上記のSVG2仕様で説明されているプロセスをいくらか複製しています。
円は、マークアップの後半にある要素を前にある要素の上に配置するSVGの自然なzインデックスを使用して、互いに重ねられます。
ペンの円形のパスをクリックすると、最初のクリックでパスがコンソールにどのように構成されているかが印刷され、要素にクラスが追加されて、円の描画方法のストロークの色が表示されます(最初の円は、ストロークから開始するウェッジで描画されます)。 2回目のクリックでサークルが削除されるため、下のサークルを操作できます。
各円には異なる塗りつぶし色があります。 実際の円の要素は黄色で、クリックされるたびにコンソールに「円をクリックしました」と表示されます。 もちろん、 desc
要素は非常に単純なので、コードを読むこともできます。
パスからサークルへの移行
円を描くにはさまざまな方法がありますが、使用されるパスは非常によく似ていることに気付いたと思います。 多くの場合、特に描画プログラムから出力されるSVGでは、円はパスで表されます。 これはおそらく、グラフィックプログラムコードの最適化によるものです。 パスを描画するコードを取得したら、何でも描画できるので、それを使用します。 これにより、SVGがやや肥大化し、推論が困難になる可能性があります。
推奨読書: SaraSoueidanによる「Web用のより良いSVGを作成およびエクスポートするためのヒント」
例として、ウィキペディアの次のSVGを取り上げましょう。 そのファイルのコードを見ると、Jake ArchibaldのSVGOMGを実行すると、多くのエディターの断片が含まれていることがわかります。 (ここで詳細を読むことができます)、かなり最適化された次のファイルのようなものになりますが、ドキュメント内の円はパスとしてレンダリングされます:
それで、パスがどのように機能するかについて私たちが知っていることを考えると、それらが実際の円要素である場合、それらの円がどうあるべきかを理解できるかどうかを見てみましょう。 ドキュメントの最初のパスは明らかに円ではありませんが、次の2つは( d
属性のみを示しています):
M39 20a19 19 0 1 1-38 0 19 19 0 1 1 38 0z
M25 20a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
したがって、2番目a
は省略できることを思い出して、もう少し意味をなすようにこれらを書き直してみましょう。 (最初のパスは大きな円です。)
M39 20 a19 19 0 1 1-38 0 a19 19 0 1 1 38 0z
これらのアークは明らかに次のとおりです。
aR R 0 1 1 - (R * 2) 0 aR R 0 1 1 (R * 2) 0
これは、円の半径が19
であることを意味しますが、 CX
とCY
の値は何ですか? 私たちのM39
は実際にはCX + R
だと思います。つまり、 CX
は20
で、 CY
も20
です。
次のようなすべてのパスの後に円を追加するとします。
<circle fill="none" stroke-width="1.99975" stroke="red" r="19" cx="20" cy="20" />
それが正しいこと、そして赤いストロークの円が正確に大きな円を覆っていることがわかります。 再定式化された2番目のサークルパスは次のようになります。
M25 20 a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
明らかに、半径は5
であり、 CX
とCY
の値は以前と同じであるに違いありません: - 20
。
注: CX = 20
の場合、 CX + R = 25
です。 円は中央の大きい方の円の内側にあるので、明らかに同じCX
値とCY
値を持つ必要があります。
パスの最後に次の円を追加します。
<circle fill="yellow" r="5" cx="20" cy="20" />
次のペンを見ると、これが正しいことがわかります。
円がどうあるべきかがわかったので、これらの不要なパスを削除して、実際に円を作成できます。次のようになります。
テキストを折り返すために循環パスを使用する
パスに円ができたので、それらのパスでテキストを折り返すことができます。 以下は、以前の「すべての円」ペンと同じパスを持つペンですが、パスにテキストがラップされています。 パスをクリックするたびに、そのパスが削除され、次のようにテキストが次に使用可能なパスに折り返されます。
さまざまなパスを見ると、それぞれの間に小さな違いがあります(これについては後で詳しく説明します)が、最初に、ブラウザー間の非互換性が少し見られます。特に最初のパスで顕著です。
Firefox開発者 | |
クロム | |
マイクロソフトエッジ |
Firefoxソリューションで「Smashing」の開始「S」がその面白い角度になっている理由は、実際にパスを描画し始めた場所であるためです(使用したvRコマンドのため)。 これは、私たちが描いた円の最初のパイ型のくさびをはっきりと見ることができるChromeバージョンでより明白です。
Chromeはすべてのくさびを追跡するわけではないため、これはテキストを「SmashingMagazine」に変更した場合の結果です。 |
その理由は、Chromeには、親text
要素で宣言されたtextLength
属性の継承に関するバグがあるためです。 両方を同じように見せたい場合は、 textPath
要素とtextにtextLength
属性を設定します。 なんで? textLength
属性がtext
要素に指定されていない場合、Firefox Developerにも同じバグがあることが判明したためです(これは数年前から当てはまります)。
MicrosoftEdgeにはまったく異なるバグがあります。 Text
と子TextPath
要素の間の空白を処理することはできません。 空白を削除し、 textLength
属性をtext
要素とtextPath
要素の両方に配置すると、それらはすべて比較的同じように見えます(デフォルトのフォントの違いなどによるわずかな違いがあります)。 したがって、3つの異なるブラウザでの3つの異なるバグ—これが、人々がライブラリを使用することを好む理由です。
次のペンは、問題を修正する方法を示しています。
また、テキストの折り返しが見やすくなるため、さまざまな塗りつぶしの色を削除しました。 塗りつぶしの色を削除するということは、 pointer-events="all"
属性を追加しない限り、パスを循環してどのように見えるかを確認できる小さな関数が機能しないことを意味するので、それらも追加しました。
注:その理由の詳細については、Tiffany B.Brownが説明した「SVGインタラクションとポインターイベントプロパティの管理」を参照してください。
マルチアークパスのラッピングについてはすでに説明したので、他のパスを見てみましょう。 ラップするパスが1つあるため、テキストは常に同じ方向に移動します。
画像 | 道 | 説明 |
---|---|---|
M CX, CY a R, R 0 1,0 -(R * 2), 0 a R, R 0 1,0 R * 2, 0 translate 機能を使用して、X軸上で+R を移動します。 | textPath の開始位置(指定していないため)は、円弧自体の半径を指定して、最初の終了円弧-(R * 2) によって決定されます。 | |
M (CX + R), CY a R,R 0 1,0 -(R * 2),0 a R,R 0 1,0 (R * 2),0 | 前のパスと同じことが当てはまります。 | |
M CX CY m -R, 0 a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 | 最初のアークでは(R * 2 ) で終了しているので、明らかに反対の位置から開始します。 つまり、これは前の2つのパスが終了したところから始まります。 | |
M (CX - R), CY a R,R 0 1, 1 (R * 2),0 a R,R 0 1, 1 -(R * 2),0 | これは、 (R * 2) のために最後の位置と同じ位置から始まりますが、スイープフラグプロパティ(黄色でマーク)を1 に設定したため、時計回りに実行されます。 |
円内の単一のパスでテキストを折り返す方法を見てきました。 それでは、そのパスを2つのパスに分割する方法と、そこから得られるメリットを見てみましょう。
私たちの道を部品に壊す
パス内のテキストを使用して実行できることはたくさんあります。つまり、 tspan
要素を使用してスタイル効果を実現したり、テキストのオフセットを設定したり、テキストをアニメーション化したりします。 基本的に、あなたがすることは何でもパス自体によって制約されます。 ただし、マルチアークパスを単一のアークパスに分割することで、テキストの方向、テキストのさまざまな部分のzインデックスを操作し、より複雑なアニメーションを実現できます。
まず、別のSVG画像を使用していくつかの効果を示します。 前述のポインタイベントに関する記事のひし形を使用します。 まず、その上に単一パスの円形テキストを配置すると、どのように見えるかを示しましょう。
私たちの円がCX 295, CY 200, R 175
あると仮定しましょう。 ここで、Circular pathメソッドに従うと、次のようになります。
M (CX - R), CY a R,R 0 1,1 (R * 2),0 a R,R 0 1,1 -(R * 2),0
パスやテキストサイズ、塗りつぶし、ストロークの色については説明しません。 私たちは皆、今ではそれを理解し、私たちが望むものにすることができるはずです。 しかし、テキストを見ると、すぐにいくつかの欠点や制限がわかります。
- テキストはすべて一方向に実行されます。
- 特にMAGAZINEと書かれている場合は、テキストの一部をアメジストの後ろに置くとよいでしょう。 「M」と「E」を円上に並べるには、「A」をアメジストの下側に配置する必要があります。これは、別の方法でバランスが崩れているように感じます。 (「A」は正確に配置され、そのポイントで下向きになっている必要があるように感じます。)
これらの問題を修正する場合は、単一のパスを2つに分割する必要があります。 次のペンでは、パスを2つのパスに分割しました(そして、 textPath
が参照できるようにSVGのdefs
領域に配置しました)。
ここでも、 CX
が295, CY 200, R 175
であるとすると、2つのパスは次の形式になります(上部の半円形パスの場合)。
M (CX - R), CY a R,R 0 1,1 (R * 2),0
そして、下部については次のとおりです。
M (CX + R), CY a R,R 0 1,1 -(R * 2),0
ただし、すべて同じ方向に移動する円形のテキストがまだあります。 Edge以外のすべてについてこれを修正するには、「MAGAZINE」 textPath
を保持するtext
要素にside="right"
属性を追加するだけです。
テキストを別の方向に進める
できるだけ多くのブラウザをサポートしたい場合は、パスを変更する必要があり、完全にサポートされていないside
属性に依存しないでください。 できることは、一番上の半円のパスをコピーすることですが、スイープを1
から0
に変更します。
前:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
1
350,0
350,0
後:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
0
350,0
350,0
しかし、テキストはスイープによって定義された内側の円に描画されるようになり、さまざまなブラウザではあまり見栄えが良くなりません。 これは、パスの位置を移動して「スマッシング」の「S」に揃え、パスの末尾のXを大きくして、テキストにオフセットを設定する必要があることを意味します。 ご覧のとおり、Firefoxと他のFirefoxの間にはテキストの違いも少しあります。これは、 text
要素のtextLength
属性を増やし、 textPath
から空白を削除することで改善できます(Firefoxは明らかに空白が意味があると考えているため)。
ソリューション:
サーキュラーテキストの一部のZインデックスを変更する
最後に、テキストをアメジストの前と後ろの両方に配置します。 まあ、それは簡単です。 SVGの要素のzインデックスは、マークアップのどこにあるかに基づいていることを覚えていますか? したがって、2つの要素がある場合、要素1
は要素2
の後ろに描画されます。 次に、SVGマークアップでtext
要素を上に移動して、アメジストの前に描画するだけです。
「MAGAZINE」という単語の一部がアメジストの下部に隠れている結果を以下に示します。
マークアップを見ると、テキストの下半円がアメジストを描くパスの前に移動されていることがわかります。
サークルの一部をアニメーション化する
これで、テキストを2つの半円に配置して、テキストの一部の方向性を完全に制御することにより、円形のテキストを作成できるようになりました。 もちろん、これを利用してテキストのアニメーションを作成することもできます。 クロスブラウザSVGアニメーションの作成は、実際には別の記事(またはさらに多くの記事)の主題です。 これらの例は、CSSキーフレームやGreensockなどのツールの代わりにSMILアニメーション構文を使用しているため、ChromeとFirefoxでのみ機能します。 しかし、それは分解された円をアニメートすることによって達成できる効果の良い指標を提供します。
次のペンを取ります。
アニメーションの動作を確認するには、codepenの[再実行]ボタンを押してください。 円形のテキストの2つの部分は同時にアニメーションを開始しますが、継続時間が異なるため、異なる時間に終了します。 textLength
属性をアニメーション化するため、各テキストの下に2つのanimate
ディレクティブを配置しました。1つはtext
要素用(Firefoxが機能するように)、もう1つはtextpath
要素用(Chromeが機能するように)です。
結論
この記事では、パスを最適化する必要がある場合とそうでない場合をよりよく理解するために、円をパスに変換して元に戻す方法を説明しました。 円をパスに変えると、テキストを円形のパスに配置できるようになるだけでなく、円形のパスをさらに半円に分割して、円形のテキストの構成要素の方向性とアニメーションを完全に制御する方法もわかりました。 。
SmashingMagの詳細:
- レスポンシブSVGの再考
- SVGatorを使用したSVGファイルのアニメーション
- CSSを使用したSVGのスタイリングとアニメーション
- ポインタイベントプロパティとのSVG相互作用の管理