WEBアプリ開発記

~備忘録としてね~

html5のcanvas × スクロールで自由描画がずれる?

html5canvasの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度と面倒くさいことをしないようにする仕事をするくらい面倒くさがりだから開発者なのであって、そーゆー面倒くさい奴は、大体開発者に向いてると思う。

CSSの優先順位

CSSは、書いても思い通り適用されない、複雑になるというイメージがある。

確かに複雑なのだが、少しだけ救われるヒント。

 

・基本的には、後に書いたもの、読み込まれたものが優先される。

CSSはポイント制になっており、ポイントに従って適用される優先順位が変わる。

 

[ポイントについて]

 <div id="section-a" class="section-block">こんにちは</div>

という要素があるとして、

 

1.タグ(divなど)での指定は1ポイント

 例)

 div {

    color: #F00;

}

 

2.クラスでの指定は10ポイント

例)

.section-block {

    color: #0F0;

}

 

3.IDでの指定は100ポイント

例)

#section-a {

    color: #00F;

}

 

上記3つがすべてCSSに指定されていたら、書かれた順(読み込み順)に関係なく、文字色は最高ポイントを持ったスタイルが適用され、青くなる。

 

これらを踏まえて、、

 

div.section-block {

    color: #FF0;

}

 

 のようなセレクタ指定では、1 + 10 = 11ポイント。

 

.section-block#section-a {

    color: #0FF;

}

 

のようなセレクタ指定では、10 + 100 = 110ポイントとなる。

 

後に書かれていても、ポイントが高い方に書かれているスタイルが適用される。

また、ポイントが同じスタイルが存在した場合は、後に書かれている(読み込まれている)スタイルが適用される。

 

それでもやはりCSSは複雑なのだが、知ってると少しはマシになるだろう。