html5のcanvas × スクロールで自由描画がずれる?
html5のcanvasのmoveToやlineToを駆使して、お絵かきツールを作成するような参考ソースは、ggればたくさん出てくる。しかし、表題の通り、画面をスクロールすると、ペンの描画がカーソルと全然違うところから始まってイライラすることはないだろうか。
この原因は、以下、
// 開始位置を取得
var startX, startY;
$("#canvas").on("mousedown", function(e) {
startX = e.x;
startY = e.y;
});
$("#canvas").on("mouseup", function(e) {
var ctx = document.getElementById("canvas").getContext("2d");
ctx.moveTo(startX, startY);
ctx.lineTo(e.x, e.y);
ctx.closePath();
ctx.stroke();
});
と、まぁソースはこんな感じになるだろうが、曲者は、
「e.x, e.y」
こいつらである。つまり、マウスの開始終了座標の指定方法にある。
なんとなく察しはつくと思うが、スクロール分が考慮されていないのである。
マウスが持つ座標の取得方法としては、
- e.pageX = スクロールしてもhtmlの一番左上からの距離
- e.layerX = スクロールしても対象要素の一番左上からの距離
- e.clientX = ブラウザの描画画面の左上からの距離(スクロール無視して)
- e.screenX = PCモニターの左上からの距離(スクロール無視して)
- e.x = e.clientXと同じ
のように、モダンブラウザでは多様にプロパティを持つため、適切なプロパティを選択してやる必要がある。
上記サンプルでは、clientXとして座標を取られてしまうため、スクロール分を無視して描画されるというわけだ。よって、pageXに変更することで、このズレを解消できるはずだ。
上記サンプルのように簡単な例なら問題ないが、これが、独自のスクロールを持つdivブロックがhtml中に存在すると、body本体のスクロール量と、divのスクロール量とを引き算して、、とか訳わからん計算で十中八九死ぬ。
私が今使っている、fabric.jsというcanvasのフレームワークは、有難いことにこれら問題を簡単にやっつけてくれるのだ。
http://fabricjs.com/freedrawing/
fabric.jsの細かい説明はしないが、自由描画デモのリンクだけ貼っておく。
以下のように、fabric.utilに対して、scrollする可能性があるブロック要素を全てリッスンする。
var canvas = new fabric.Canvas("canvas");
fabric.util.addListener($("body")[0], "scroll", function() {
canvas.calcOffset();
});
fabric.util.addListener($("#div-block")[0], "scroll", function() {
canvas.calcOffset();
});
すると、指定されたブロックがスクロールするたびに、自動で描画開始終了位置を再計算し直してくれるのだ!神だ!
全ての開発者が、こんな細かいところまで好き好んでごにょごにょできない。
このような面倒を減らしてくれるフレームワーク開発者は素晴らしい。
開発者は基本面倒くさいからフレームワーク作って2度と面倒くさいことをしないようにする仕事をするくらい面倒くさがりだから開発者なのであって、そーゆー面倒くさい奴は、大体開発者に向いてると思う。