console.lealog();

@leader22のWeb系に関する勉強めもブログですのだ

今さらcanvasにフリーハンドで絵が書けるライブラリ

20161119 追記: まさか使ってる人がいると思ってなかったけどいたので、`npm`から利用できるようにしときました

を書いてました。
なんと7月に下書きしてたのでもはや覚えてません。

でもきっとこの世の誰かの役には立つかもしれないので、いちおう記事にしておきます。

GitHub - leader22/simple-drawing-board.js: Just simple minimal canvas drawing.

特長とモチベーション

  • 依存ライブラリなし
  • バイルでも動く
  • 7KBと軽量

この手のcanvasのライブラリって探してみるとドンピシャなのが意外に少なくて、

  • 先人によるjQueryプラグインとか
  • UIパーツもセットになってるのとか
  • めっちゃ高機能で持て余すやつとか

はあるんですけど、
昨今の流行りもそうですが、あれこれ詰め込むのはあまり好きじゃないし、
最低限で良いの!っていう気持ちがあったので作りました。

というわけでこちらは、
ブラウザで「canvasにフリーハンドでちょろっと何か書く」っていう用途に限定したライブラリとなっております!

デモも置いておきまーす。

SimpleDrawingBoard Demo

開発時のハマりどころ / メモ

透明とは

いわゆる消しゴム的な処理とか、綺麗さっぱり消したいときとかにどうするか。
背景に色が付いてるならその色で塗ればいいだけなんですが、背景が透明の場合。
透明で塗る、とは・・?ってなるかもですが、これ実は簡単にできます。

canvasコンテキストに、globalCompositeOperationってプロパティがあって、それを使います。

ctx.globalCompositeOperation = 'destination-out';

これだけで新しく描いた部分が(正確には新しく描かれることで重なった古い部分が)消せます。
色とか別になんでもいいです。

一つ気をつけるなら、値を戻し忘れないようにすることで、

// 消す準備
var oldGCO = ctx.globalCompositeOperation;
ctx.globalCompositeOperation = 'destination-out';

// 消す処理

// 消し終わったら戻す
ctx.globalCompositeOperation = oldGCO;

これ忘れると書けない!ナンデ!ってなります。

globalCompositeOperation プロパティ - Canvasリファレンス - HTML5.JP

canvasの便利メソッド

コード書いてて地味に便利やな・・ってなったのでメモ。

toDataURL
ctx.canvas.toDataURL('image/png');

ってするだけで、そう!
canvasの状態をbase64な画像URLで取得できてしまうんですねー。

  • 履歴の保存に使ったり
  • 書いた内容をサーバーに保存したり

に使えます。

これも一つ気をつけるなら、外部の画像を取り込んで表示とかしてる場合、

Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': tainted canvases may not be exported

って言われてしまいます。

CORS Enabled Image - HTML | MDN

drawImage

これも便利ですね!

ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height)

5つの引数のうち、後ろ4つは描画する範囲で、
最初の1つが描画したい内容なんですがコレがなんと。

  • HTMLImageElement: 画像も
  • HTMLCanvasElement: Canvasも!
  • HTMLVideoElement: Videoも!!

なので再生中のvideoのシーンキャプチャも取れるっていうことです。
WebRTCとか組み合わせると夢が広がりますね。

CanvasRenderingContext2D.drawImage() - Web API インターフェイス | MDN

toDataURLした文字列を使えば、簡単にcanvasを復元できます!便利!

座標の計算

こういうライブラリ書いてて一番ありそうなのは、マウスの位置と描画位置がズレる・・ってやつかなーと。

  • canvasにはwidth/heightをしっかり指定する
  • getBoundingClientRectなりでcanvasの位置を特定する
  • スクロール位置も加味する

と、マウスの位置ぴったりに描画できるようになるはず。

// canvas位置が動かないなら、getBoundingClientRect/scrollの値はキャッシュすべし
ev.pageX - (ctx.canvas.getBoundingClientRect().left + window.scrollX)

おわりに

というわけで、何かあればお気軽にどうぞ。