世界を動かす技術を、日本語で。

SVGパスのインタラクティブガイド

概要

  • SVGの <path>要素 は複雑だが、曲線や自由な形状を描く上で不可欠
  • M (Move)、 L (Line)、 Q/C (Bézier曲線)、 A (Arc)などの基本コマンド解説
  • 各コマンドは 連続的な描画命令 として機能、順序やパラメータが重要
  • アーク(Aコマンド)は パラメータが多く、挙動理解が難しいが、直感的な例で解説
  • Bezier曲線やArc の使い分け、パラメータの意味、コツを明確に説明

SVG <path> 要素の基本とコマンド解説

  • SVGの<path>要素 は、Illustratorなどベクターグラフィックツールの「ペンツール」に相当
  • d属性 は「data」の略で、 連続的な描画命令 を記述
  • 各命令は、 英字コマンド+パラメータ(数値) で構成
  • 命令の流れ は、前の命令の終点が次の命令の始点となる仕様
  • 例:<path d="M 12,4 L 4,12 M 6,4 L 12,4 L 12,10" />など、複数命令の連結が可能

Move(Mコマンド)

  • Mコマンド はペンを指定位置へ移動、描画は行わない
  • パラメータは X座標, Y座標 の2つ指定
  • 描画命令の最初 は必ずMoveで開始
  • 例:<path d="M 10,10" />で座標(10,10)へ移動
  • ペンのスタート位置指定 用途

Line(Lコマンド)

  • Lコマンド は現在位置から指定位置まで直線を描画
  • パラメータは 終点のX座標, Y座標
  • 始点は直前の命令の終点 を自動継承
  • 例:<path d="M 2,2 L 14,14" />で直線描画
  • 直線描画の基本命令

Bézier曲線

  • SVGでは 2種類のBézier曲線 が利用可能
    • Qコマンド:二次(Quadratic)Bézier曲線
      • 制御点1つ で曲線を制御
      • パラメータ: 制御点(X,Y), 終点(X,Y)
      • 例:<path d="M 2,2 Q 2,14 14,14" />
      • 曲線の始点は直前の命令から継承
    • Cコマンド:三次(Cubic)Bézier曲線
      • 制御点2つ でより複雑な曲線表現
      • パラメータ: 制御点1(X,Y), 制御点2(X,Y), 終点(X,Y)
      • 例:<path d="M 2,2 C 2,14 14,2 14,14" />
      • S字型や複雑な曲線 に最適

Arc(Aコマンド)

  • Aコマンド は楕円弧(部分的な円や楕円)を描画
  • 書式:A rx,ry rotation large-arc-flag sweep-flag end-x,end-y
    • rx, ry :楕円の半径(水平・垂直)
    • rotation :楕円の回転角度
    • large-arc-flag :弧の長短(0=短い, 1=長い)
    • sweep-flag :弧の方向(0=反時計回り, 1=時計回り)
    • end-x, end-y :弧の終点座標
  • 始点は直前の命令の終点 から自動継承
  • <ellipse>要素との違い は、中心点指定ではなく始点・終点指定で部分的な弧を描画
  • rx/ryの調整 で弧の深さ・形状をコントロール
  • large-arc-flag/sweep-flag の組み合わせで経路の選択
  • rotation は楕円が回転した状態で弧を描画(通常は0でOK)

Arcコマンドの直感的理解

  • 楕円弧 は、始点・終点を含む仮想楕円を想定し、その一部を描画
  • rx/ryが小さいほど弧は深く、大きいほど弧は浅くなる
  • large-arc-flag で短い弧/長い弧の選択
  • sweep-flag で反時計回り/時計回りの方向選択
  • rotation で楕円自体を回転(通常は0で問題なし)

Arcコマンドのパラメータ再確認

  • M [始点X],[始点Y] A [rx],[ry] [rotation] [large-arc-flag] [sweep-flag] [終点X],[終点Y]
  • 始点は直前命令を継承
  • rx/ry:楕円半径
  • rotation:楕円の回転角度
  • large-arc-flag:弧の長さ選択(0=短い, 1=長い)
  • sweep-flag:弧の方向選択(0=反時計回り, 1=時計回り)
  • 終点:弧の終わりの座標

まとめとコツ

  • SVG <path>要素 は命令とパラメータを連続的に記述することで、自由な形状や曲線を描画
  • Move, Line, Bézier, Arc 各コマンドの意味とパラメータを理解することが重要
  • Arcコマンド はパラメータが多いが、直感的なイメージで理解すると使いやすくなる
  • まずはシンプルな命令から試し、パラメータを変えて挙動を観察 するのが習得の近道
  • 複雑な図形や曲線も、コマンドの組み合わせで自在に表現可能

Hackerたちの意見

これ、めっちゃ良かった!自分のスキルレベルにぴったりだと思った(.svgが何かは知ってるけど、それくらい)。次にアイコンを調整したり最適化したりする時に、学んだことが役立ちそう。音のエフェクトもすごく良かった!ちょっと長いこと、物を拾ったりドラッグしたりしてたかも。ありがとう!

ジョシュの作品は全部金の価値があるね。

彼は本当にいい人っぽいね。

NaNがSVGパスについてすごく良いページを公開してたよ: https://www.nan.fyi/svg-paths

昨年、ランダムに作成されたマップでウェブアドベンチャーゲームを作ってた時に、これがあればよかったな。SVGは、実際に必要になるまで無意味に思えるフロントエンド技術の一つだよね。ゲーム内でユーザーのアクションに応じてSVGを動的に作成することで、冒険のグラフィカルな表現がすごく良くなった。この作品の著者とは違って、私は小文字の相対コマンドが矢印(私の場合は宇宙のセクター)を作るのにめっちゃ役立ったよ。後で移動させることができるしね。

同じタイトルだけど、別の記事だよ:SVGパスのインタラクティブガイド - https://news.ycombinator.com/item?id=36574645 - 2023年7月(コメント39件)

開発者がSVGについて知ってるのは当たり前だと思ってたけど、私はデザインから業界に入ったから、Adobe IllustratorやSketchで何年もベクターをいじってたんだ。SVGは最高だよ。ウェブ仕様にあまり投資されてないから、SVG2が注目されるといいな。

JSXサポート(Reactなど)を通じたSVG操作は、実際にはめっちゃ便利だってことも覚えておくべきだね。過去にスキャンしたドキュメントにマーカーやハイライトを追加するのに使ったし、棒グラフや折れ線グラフも…大きなモジュールライブラリを追加せずにできたから。ちょっとしたデータを表示したいだけなのに、ほとんどのチャートライブラリは異常に大きいんだよね。

2つの端点から楕円弧を定義するもっと直感的な方法があるのかな。次元解析によると、3つのパラメータが必要みたい。SVGの仕様ではrx/ry/回転に加えていくつかのブール値を使ってるけど、ブール値なしでより良いパラメータ化ができるかも?例えば、制御点の2つの座標を使うとか。端点がAとBで、制御点がCの場合、楕円はACとBCに接することになる。そして、Cから楕円を近づけたり遠ざけたりするための追加の正の数値を使う感じ。1以上の値だと弧が外側に膨らむようになる。だから、2つのパラメータ(1つの制御点)を持つ2次ベジェと、4つのパラメータ(2つの制御点)を持つ3次ベジェの間の自然な位置に収まると思う。

直感的な方法はこうかな:スタート地点が角度θ₁の円上にあって、長さΔθ(正または負)の弧を描きたいとする。円は中心(x,y)または半径で定義できる。編集:SVGのドキュメントには、この表現への変換のための数学が含まれているみたい。 https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpoin...

答えはYES。射影2D幾何学に関わる旅の準備をしておいてね。ギリシャ人が円錐曲線に魅了されていたのを思い出してみて。楕円、双曲線、放物線、そしてもちろん円は、すべて射影2D変換の対象として同じものなんだ。無限に延びる(ダブル)円錐を平面で「切る」ことで円錐曲線が得られるから、名前の由来にもなってる。だから、2つの端点を持って(曲線がこれらの点を通過する際に補間する制御点)、3つ目の外挿制御点を持つことができる。3つの制御点を持つ2次ベジェセグメントのような感じだけど、外挿制御点(「中間」制御点)には同次の「w」座標を持たせることができる。だから、3つの点(x₀,y₀)、(x₁,y₁,w₁)、(x₂,y₂)を考えてみて。あるいは、これを(x₀,y₀,1)、(x₁,y₁,w₁)、(x₂,y₂,1)として考えることもできる。これは実質的に、ラショナル2次ベジェセグメントと呼ばれるものだ(NURBSのRと同じ意味でラショナル)。実は、形式(X₀,Y₀,W₀)、(X₁,Y₁,W₁)、(X₂,Y₂,W₂)の3つの同次一般制御点を、標準形(x₀,y₀,1)、(x₁,y₁,w₁)、(x₂,y₂,1)に再パラメータ化することは常に可能なんだ。基本的には、端点のために単位w値を強制する感じ。この標準形では、w₁の値には自然な解釈がある。w₁==1のとき、曲線は放物線セグメントになる(だから、SVGの2次ベジェセグメントに正確に一致するようにパラメータ化されてる)。双曲線セグメントはw₁>1; 楕円セグメントは0。ブール値なしでより良いパラメータ化ができるかも?うん、できるよ。円錐セグメントのパラメータ化にはブール値がない。> SVGの仕様ではrx/ry/回転に加えていくつかのブール値を使ってる。正直、SVGの部分的楕円弧仕様は一見合理的に見えるけど、実際はめちゃくちゃで直感的とは言えない。rx/ry/回転やブール値を変更できるSVGツールで遊んでみると、これらを変えると本当に驚くことがあるよ。円錐セグメントでは、2次ベジェセグメントのような感じだけど、w₁を「引っ張る」ための追加の制御点がある。w₁==1から始めると、それは2次ベジェセグメントになる。wを1以上に増やすと、曲線は「鋭く」なっていく(双曲線的に)。wを1未満に減らすと、曲線は「平ら」になっていく(楕円的に)。まるでテンションコントロールみたいだね。w₁の負の値は問題があるから、w>0の円錐セグメントのスプラインから「大きな弧」(外部円錐セグメントとも呼ばれる)を常に構築できるよ。これは特に難しくない。円錐セグメントには大きな表現上の利点もある。関与するスカラーはすべてスカラー「座標」(x, y, そしてw)なんだ。これを、9つの異なるタイプの値が必要なSVGの部分的楕円弧パラメータ化と対比してみて。2つの長さ(半径)、1つの角度(回転)、2つのブール値(大きなフラグ、スイープ方向)、2つの制御点(4つの座標)。SVGのパラメータ化では双曲線セグメントを描けない!それなのに、360度を超える角度のような変な状況を許容してる(だから弧が何度もループすることができる??)。(SVGは、弧が7つの値だけで指定されているように見せかけているけど、それは前のコマンドから初期の端点を借りているからで、9つの値が「独立した」部分的楕円弧を説明するにはもっと正直だよ。)もし自分の曲線セグメントをGPUに載せるなら、一貫した浮動小数点座標のバッファがあった方がいいよね、異なるタイプの値ではなくて。さらに魅力的なのは、(x₀,y₀,1)、(x₁,y₁,w₁)、(x₂,y₂,1)は、3x3の射影2D行列によって変換できる同次点として扱うことができ、変換された制御点から得られる曲線は、曲線の点を変換するのと同じになるんだ。SVGでパラメータ化された部分的楕円弧にせっかくせんとするなら、シアー/スケール/トランスレート/回転、さらには射影を適用したい?運が必要だね。これを本当にやりたい人へのヒント:SVGの弧を1つ以上の円錐セグメントのスプラインに変換して、その円錐セグメントの制御点を変換行列で変換し、変換された円錐セグメントを不格好なSVGの弧に再構成してみて。基本的に、SVGの弧パラメータ化は、弧の2D変換に対するオイラー角のようなものだよ!

ちょっと考えた方がいいのは、クッキー(そしてローカルストレージ)が無効になっているときに、ページ全体が真っ白にならないようにすることかな。ページが一瞬完全に読み込まれた後、全画面のReactエラーで真っ白になっちゃう。これ、避けられるサイトがいくつかあるのを見たことある。

記事がフレイヤの「ベジェ曲線の美」の動画にリンクしているのが本当に嬉しい。あれは本当に最高の数学・グラフィックス・解説動画の一つだと思う。 https://youtu.be/aVwxzDHniEw