1. Qiita
  2. 投稿
  3. SVG

SVGでフリーハンドお絵描き

  • 12
    いいね
  • 0
    コメント

svgでお絵描きサンプルを作ってみました。
線を滑らかにしたかったので色々と思考錯誤してみました。

やりたいこと

  • svg上でドラッグしたらpathを追加したい
  • pathをベジェにして滑らかにしたい
  • 頂点を間引いて滑らかにしたい

svg上でドラッグしたらpathを追加したい

これは、単純にマウスイベントとフラグ管理でドラッグしている時にsvg要素にpath要素を追加していきました。

pathをベジェにして滑らかにしたい

これがけっこう大変でした。

通過点のみで曲線を描くのはcatmull曲線があるのですが、まだpath要素には実装されていないようでした。
ここによると下記のようです。

R,r1 Catmull-Romスプライン曲線を引く
SVG2での新機能.詳細仕様は策定中であり,動作する環境はまだない.

したがって、ベジェ曲線を使うことになるのですが、通過点の他に制御点が必要です。
イラレでよく見かけるアンカーポイントのことです。

svgでベジェ曲線サンプル

通過点から制御点を求める関数を上げている人がいたので、これを拝借しました。

ソースコードのみ抜粋

catmullRom2bezier
function catmullRom2bezier(pts){
    var cubics = [];
    for ( var i = 0, iLen = pts.length; i < iLen ; i++ ){
        var p = [
            pts[i - 1],
            pts[i],
            pts[i + 1],
            pts[i + 2]
        ];
        if( i === 0 ){
            p[0] = {
                x: pts[ 0 ].x,
                y: pts[ 0 ].y
            }
        }
        if( i === iLen - 2 ){
            p[3] = {
                x: pts[iLen - 2].x,
                y: pts[iLen - 2].y
            };
        }
        if ( i === iLen - 1 ) {
            p[2] = {
                x: pts[iLen - 1].x, 
                y: pts[iLen - 1].y
            };
            p[3] = {
                x: pts[iLen - 1].x, 
                y: pts[iLen - 1].y
            };
        }
      const val = 6;
        cubics.push([
            (-p[0].x + val * p[1].x + p[2].x) / val,
            (-p[0].y + val * p[1].y + p[2].y) / val,
            (p[1].x + val * p[2].x - p[3].x) / val,
            (p[1].y + val * p[2].y - p[3].y) / val,
            p[2].x,
            p[2].y
        ]);
    }
    return cubics;
}

引数に通過点の座標配列を入れれば、制御点を含んだベジェ曲線用の座標配列を返してくれます。

他にも、npmで公開している人もいました。
実際に使う時はこれをインストールしても良いさそうです。

頂点を間引いて滑らかにしたい

最初、単純に距離が近すぎる点を間引いていたのですが、あまりうまく機能しませんでした。
そこでポリゴンの線を単純化してくれるSimplify.jsを使うことにしました。
(CDNで公開されているものが見つからなかったので、成果物ではコードをコピペして使っています。)

成果物

http://codepen.io/kwst/pen/vgGgqN
上が滑らかにした線、下がフリーハンドで描いた線
スクリーンショット 2017-01-12 14.40.30.png
割りとなめらかになったかなと思います。
単純なお絵描きですが、線をなめらかにするだけでも結構骨が折れました。

Githubに公開してみました。
SVGCatmullRomSpline