@thorikiriのてょりっき

@thorikiriがWebとかAndroidとかの技術ネタや本を読んだブログです

hammer.jsを使ってCanvas上の画像を移動させる

前回はFile APIを使って、画像ファイルをCanvasで描画してみました。
この時にCanvasのサイズを画像のサイズに合わせていたのですが、Canvasのサイズを固定にしたい時もありますよね。
ということで、300px * 300pxのCanvasに対して、画像の好きなところだけを表示したいと思います。
hammer.jsは、タッチジェスチャーを使えるようにするライブラリです。やっぱスマホでも使えると良いですもんね。
hammer.fakemultitouch.jsを使えば、PCでもタッチジェスチャーがエミュレート出来ますので、こちらを使って開発します。
また、hammer.showtouches.jsを使えば、PC上のタッチ操作を画面に表示することが出来ますので、こちらも使います。
onload時に次のコードを実行すれば良いかと思います。

Hammer.plugins.showTouches();
Hammer.plugins.fakeMultitouch();

さらに、jQueryと組み合わせるために、jquery.hammer.jsも使用します。
hammer.jsでは、次のような感じで使えます。

$('#canvas').hammer()
    .on('dragstart', dragstart)
    .on('drag', drag);

dragstartでドラッグ開始するときに呼び出す関数を登録、dragでドラッグ中に呼び出す関数を登録します。今回は利用していませんが、ドラッグ終了時には、dragendイベントが発生しますので、こちらを利用しましょう。
それぞれの関数はイベントオブジェクトを引数でもらいます。ev.gestureにジェスチャー操作の情報がありますので、こちらで座標などを判定しましょう。
最後に、取得した座標でもって、Canvasに再描画すればよいです。

context.clearRect(0, 0, 300, 300);
context.drawImage(image, left, top);

こんな感じですね。
最終的なコードは次の通りです。次回は同様に拡大縮小をピンチイン、ピンチアウトの操作でやってみたいと思います。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>画像表示</title>
  <style type="text/css">
html, body, #wrapper {
  background-color: #ccc;
}
  </style>
</head>
<body>
  <div id="wrapper">
    <input type="file" name="file" id="file">
    <div>
      <canvas id="canvas" width="300" height="300"></canvas>
    </div>
  </div>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
  <script src="js/libs/hammer.min.js"></script>
  <script src="js/libs/jquery.hammer.js"></script>
  <script src="js/libs/hammer.showtouches.js"></script>
  <script src="js/libs/hammer.fakemultitouch.js"></script>
  <script type="text/javascript">
(function() {
    $(function() {
        var canvas = $('#canvas')[0],
            context = canvas.getContext('2d'),
            image = new Image(),
            left = 0,
            top = 0,
            width = 0,
            height = 0,
            dragStartX = 0,
            dragStartY = 0;
        
        Hammer.plugins.showTouches();
        Hammer.plugins.fakeMultitouch();
        
        $('#file').change(function(ev) {
            var files = ev.target.files;
            $.each(files, function(index, item) {
                var reader = new FileReader();
                reader.onload = function(file) {
                    var dataUrl = file.target.result;
                    image.src = dataUrl;
                    image.onload = function() {
                        left = 0;
                        top = 0;
                        width = image.width;
                        height = image.height;
                        context.drawImage(image, left, top);
                    }
                }
                reader.readAsDataURL(item);
            });
        });
        
        $('#canvas').hammer()
            .on('dragstart', dragstart)
            .on('drag', drag);
        
        function drag(ev) {
            left += (ev.gesture.center.pageX - dragStartX);
            top += (ev.gesture.center.pageY - dragStartY);
            if (top > 0) {
                top = 0;
            } else if (top < -1 * height + 300) {
                top = -1 * height + 300;
            }
            if (left > 0) {
                left = 0;
            } else if (left < -1 * width + 300) {
                left = -1 * width + 300;
            }
            context.clearRect(0, 0, 300, 300);
            context.drawImage(image, left, top);
            dragStartX = ev.gesture.center.pageX;
            dragStartY = ev.gesture.center.pageY;
        }
        
        function dragstart(ev) {
            dragStartX = ev.gesture.center.pageX;
            dragStartY = ev.gesture.center.pageY;
        }
    });
})();
  </script>
</body>
</html>