jnobuyukiのブログ

研究していて困ったことやその解決に関するメモ。同じように困ったあなたのために。twitter ID: @j_nobuyuki

clippathを利用した画像の切り取り

SVGオブジェクトに画像ファイルを読みこむ際、周囲の形を変形させたいことがあります。イラストレーターのクリッピングマスクを利用した画像の切り取りのような場合です。javascriptでこれをやろうとすると、クリッピングパスの作り方が少しややこしいです。そのうえ、参考になる情報がネット上に少なく、作業に意外なほど時間がかかりました。そこで今回は、クリップパスによる画像の切り取り方法をまとめます。必須ではないのですが、D3.jsのチェインメソッドを使うところがユニークかもしれません。


なお参考にしたウエブページは以下の通りです。
http://www.html5rocks.com/en/tutorials/masking/adobe/?redirect_from_locale=ja

目標は以下の画像を六角形として表示することです。

1.HTMLに必要最小限の情報を書き込む

基本的にはhtmlファイルであることを知らせるタグの他に、svg要素を埋め込むためのbody要素かdiv要素があればそれで充分です。

<!DOCTYPE html>
<html lang="ja">
  <body>
    <div id = "divid">
    </div>
  </body>
</html>
2.svg要素を加える

画像を張り付けるキャンバスになるsvg要素を加えます。HTML内であらかじめidを設定しておき、それを利用してselectでsvg要素の挿入位置を決めます。そのままチェインでsvgの高さと幅を設定します。

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8">
   var svg = d3.select("#divid").append("svg").attr("width",500).attr("height", 500);
</script>
3.svg要素にクリップパスの定義を加える

次は、画像を切り取るためのクリップパスの定義をsvgへ先に加えておきましょう。画面に直接結果を反映させないで、定義のみを加えるのでdefs要素を利用します。次にdefsの下位にclippath要素をチェインで加えます。clippathにはidを設定しておきます。後でこのidを利用してパスを呼び出すためです。path要素を加えて、d属性にパスを書き込みます。今回は一辺が100ピクセルの正六角形を設定しました。その他に、rectやcircleなどの単純図形をせっていすることができます。

  var clippath = svg.append("defs").append("clipPath").attr("id", "clipping").append("path").attr("d", function () {
    return "M100,0L186.6025,50L186.6025,150L100,200L13.3975,150L13.3975,50z";
});
4. svg要素に画像を加える

最後に画像を加えます。svg上に画像を加えるにはimageではなくsvg:imageとしなければならないようです。属性としてwidth(幅)、height(高さ)、x、y(位置)、xlink:hred(ファイル名)に加えてclip-pathとして先ほどのクリップパスのidを設定します。さらに後からsvg上の位置をかえられるようにtransform属性の中でtranslate(0,0)と設定しておきます。画像の場所を変えたい時はtranslateの直後の()でx,y座標を設定します。

 var image = svg.append("svg:image").attr("width", 200).attr("height",200)
 .attr("x", "0").attr("y", "0").attr("xlink:href", "http://jsrun.it/assets/g/l/K/e/glKev.jpg" ).attr("clip-path","url(#clipping)")
 .attr("transform", "translate(0,0)");

ここまでをまとめると次のようになります。



defs内に複数のクリップパスを定義すれば、同一ページ内の複数の画像を色々な形に切り取れます。