写真をアップロードして切り抜きが出来るcropboxにタッチイベントを付けてみる

公開日: : android, javascript

画像加工 cropbox.js

Git Hub の cropbox

写真をアップロードしてカット出来るjQueryのプラグイン cropbox というものが Git Hub にあり、手軽に設置出来て気に入りました。

cropbox のスクリーンショットはこんな感じです。デモは一番最後にあります。
画像加工 cropbox.js
cropbox は、パソコンだとマウスで移動できるし、スクロールで拡大・縮小もついていますが、スマホだと出来ないので、タッチイベントを追加してみようと思います。

cropbox の設置

index.html と cropbox.js と style.css を以下のように設置します。

index.html

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"></script>
<![endif]-->
<title>Tinny Cropper</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<script src="cropbox.js"></script>
<div class="container">
    <div class="imageBox">
        <div class="thumbBox"></div>
        <div class="spinner" style="display: none">Loading...</div>
    </div>
    <div class="action">
        <input type="file" id="file" style="float:left; width: 250px">
        <input type="button" id="btnCrop" value="Crop" style="float: right">
        <input type="button" id="btnZoomIn" value="+" style="float: right">
        <input type="button" id="btnZoomOut" value="-" style="float: right">
    </div>
    <div class="cropped">

    </div>
</div>
<script type="text/javascript">
    window.onload = function() {
        var options =
        {
            imageBox: '.imageBox',
            thumbBox: '.thumbBox',
            spinner: '.spinner',
            imgSrc: 'avatar.png'
        }
        var cropper;
        document.querySelector('#file').addEventListener('change', function(){
            var reader = new FileReader();
            reader.onload = function(e) {
                options.imgSrc = e.target.result;
                cropper = new cropbox(options);
            }
            reader.readAsDataURL(this.files[0]);
            this.files = [];
        })
        document.querySelector('#btnCrop').addEventListener('click', function(){
            var img = cropper.getDataURL()
            document.querySelector('.cropped').innerHTML += '<img src="'+img+'">';
        })
        document.querySelector('#btnZoomIn').addEventListener('click', function(){
            cropper.zoomIn();
        })
        document.querySelector('#btnZoomOut').addEventListener('click', function(){
            cropper.zoomOut();
        })
    };
</script>
</body>
</html>

style.css

.container{
	position: absolute;
	top: 10%; left: 10%; right: 0; bottom: 0;
}
.action{
	width: 400px;
	height: 30px;
	margin: 10px 0;
}
.cropped>img{
	margin-right: 10px;
}
.imageBox{
    position: relative;
    height: 400px;
    width: 400px;
    border:1px solid #aaa;
    background: #fff;
    overflow: hidden;
    background-repeat: no-repeat;
    cursor:move;
}
.imageBox .thumbBox{
    position: absolute;
    top: 50%;
    left: 50%;
    width: 200px;
    height: 200px;
    margin-top: -100px;
    margin-left: -100px;
    box-sizing: border-box;
    border: 1px solid rgb(102, 102, 102);
    box-shadow: 0 0 0 1000px rgba(0, 0, 0, 0.5);
    background: none repeat scroll 0% 0% transparent;
}
.imageBox .spinner{
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    text-align: center;
    line-height: 400px;
    background: rgba(0,0,0,0.7);
}

cropbox.js

var cropbox = function(options){
    var el = document.querySelector(options.imageBox),
    obj =
    {
        state : {},
        ratio : 1,
        options : options,
        imageBox : el,
        thumbBox : el.querySelector(options.thumbBox),
        spinner : el.querySelector(options.spinner),
        image : new Image(),
        getDataURL: function ()
        {
            var width = this.thumbBox.clientWidth,
                height = this.thumbBox.clientHeight,
                canvas = document.createElement("canvas"),
                dim = el.style.backgroundPosition.split(' '),
                size = el.style.backgroundSize.split(' '),
                dx = parseInt(dim[0]) - el.clientWidth/2 + width/2,
                dy = parseInt(dim[1]) - el.clientHeight/2 + height/2,
                dw = parseInt(size[0]),
                dh = parseInt(size[1]),
                sh = parseInt(this.image.height),
                sw = parseInt(this.image.width);

            canvas.width = width;
            canvas.height = height;
            var context = canvas.getContext("2d");
            context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
            var imageData = canvas.toDataURL('image/png');
            return imageData;
        },
        getBlob: function()
        {
            var imageData = this.getDataURL();
            var b64 = imageData.replace('data:image/png;base64,','');
            var binary = atob(b64);
            var array = [];
            for (var i = 0; i < binary.length; i++) {
                array.push(binary.charCodeAt(i));
            }
            return  new Blob([new Uint8Array(array)], {type: 'image/png'});
        },
        zoomIn: function ()
        {
            this.ratio*=1.1;
            setBackground();
        },
        zoomOut: function ()
        {
            this.ratio*=0.9;
            setBackground();
        }
    },
    attachEvent = function(node, event, cb)
    {
        if (node.attachEvent)
            node.attachEvent('on'+event, cb);
        else if (node.addEventListener)
            node.addEventListener(event, cb);
    },
    detachEvent = function(node, event, cb)
    {
        if(node.detachEvent) {
            node.detachEvent('on'+event, cb);
        }
        else if(node.removeEventListener) {
            node.removeEventListener(event, render);
        }
    },
    stopEvent = function (e) {
        if(window.event) e.cancelBubble = true;
        else e.stopImmediatePropagation();
    },
    setBackground = function()
    {
        var w =  parseInt(obj.image.width)*obj.ratio;
        var h =  parseInt(obj.image.height)*obj.ratio;

        var pw = (el.clientWidth - w) / 2;
        var ph = (el.clientHeight - h) / 2;

        el.setAttribute('style',
                'background-image: url(' + obj.image.src + '); ' +
                'background-size: ' + w +'px ' + h + 'px; ' +
                'background-position: ' + pw + 'px ' + ph + 'px; ' +
                'background-repeat: no-repeat');
    },
    imgMouseDown = function(e)
    {
        stopEvent(e);

        obj.state.dragable = true;
        obj.state.mouseX = e.clientX;
        obj.state.mouseY = e.clientY;
    },
    imgMouseMove = function(e)
    {
        stopEvent(e);

        if (obj.state.dragable)
        {
            var x = e.clientX - obj.state.mouseX;
            var y = e.clientY - obj.state.mouseY;

            var bg = el.style.backgroundPosition.split(' ');

            var bgX = x + parseInt(bg[0]);
            var bgY = y + parseInt(bg[1]);

            el.style.backgroundPosition = bgX +'px ' + bgY + 'px';

            obj.state.mouseX = e.clientX;
            obj.state.mouseY = e.clientY;
        }
    },
    imgMouseUp = function(e)
    {
        stopEvent(e);
        obj.state.dragable = false;
    },
    zoomImage = function(e)
    {
        var evt=window.event || e;
        var delta=evt.detail? evt.detail*(-120) : evt.wheelDelta;
        delta > -120 ? obj.ratio*=1.1 : obj.ratio*=0.9;
        setBackground();
    }

    obj.spinner.style.display = 'block';
    obj.image.onload = function() {
        obj.spinner.style.display = 'none';
        setBackground();

        attachEvent(el, 'mousedown', imgMouseDown);
        attachEvent(el, 'mousemove', imgMouseMove);
        attachEvent(document.body, 'mouseup', imgMouseUp);
        var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
        attachEvent(el, mousewheel, zoomImage);
    };
    obj.image.src = options.imgSrc;
    attachEvent(el, 'DOMNodeRemoved', function(){detachEvent(document.body, 'DOMNodeRemoved', imgMouseUp)});

    return obj;
};

Git Hub の MITライセンス とは?

cropbox はGit HubのMITライセンスがついています。

MITライセンス

MITライセンスのもとで配布されているものは、改変でも、再配布でも、商用利用でも、有料販売でも、どんなことにでも自由に無料でつかうことができます。

<参考サイト>
MITライセンスってなに?どうやって使うの?商用でも無料で使えるの?

という訳で、cropbox.js と style.css にこんな感じで付けておけばOKかと思われます。

/**
 * Copyright (c) 2014 Nguyen Hong Khanh
 * Copyright (c) 2014 ezgoing
 * Released under the MIT license
 * https://github.com/hongkhanh/cropbox/blob/master/LICENSE
 */

cropbox にタッチイベントを追加してみる

6行目辺りの ratio : 1,の下に以下を追加します。

touchmove_bar : 0,
touchstart_bar : 0,

139行目辺りの attachEvent(el, mousewheel…行の下にタッチイベントを追加します。

attachEvent(el, 'touchstart', imgTouchstart,false);
attachEvent(el, 'touchmove', imgTouchmove);
attachEvent(el, 'touchend', imgTouchend);

122行目辺りの zoomImage の下に以下のタッチイベントに対する関数を追加します。

,
imgTouchstart = function(e){
	if(e.touches.length > 1){
		this.touchstart_bar =Math.abs(e.touches[1].pageX - e.touches[0].pageX)*Math.abs(e.touches[1].pageY - e.touches[0].pageY);
	}
	else{
		stopEvent(e);
		obj.state.dragable = true;
		obj.state.mouseX = e.touches[0].pageX;
		obj.state.mouseY = e.touches[0].pageY;
	}
},
imgTouchmove = function(e){
	if(e.touches.length > 1){
		this.touchmove_bar = Math.abs(e.touches[1].pageX - e.touches[0].pageX)*Math.abs(e.touches[1].pageY - e.touches[0].pageY);
		var area_bar = this.touchstart_bar-this.touchmove_bar;
		area_bar<0 ? obj.ratio*=1.1 : obj.ratio*=0.9;
		setBackground();
	}
	else{
		stopEvent(e);
		if (obj.state.dragable){
			var x = e.touches[0].pageX - obj.state.mouseX;
			var y = e.touches[0].pageY - obj.state.mouseY;
			var bg = el.style.backgroundPosition.split(' ');
			var bgX = x + parseInt(bg[0]);
			var bgY = y + parseInt(bg[1]);
			el.style.backgroundPosition = bgX +'px ' + bgY + 'px';
			obj.state.mouseX = e.touches[0].pageX;
			obj.state.mouseY = e.touches[0].pageY;
		}
	}
},
imgTouchend = function(e){
	if(e.touches.length == 1){
		 stopEvent(e);
       	 obj.state.dragable = false;
	}
}

cropbox にタッチイベントを追加してみたデモです。
DEMO を見る
javascriptを変更した全文はこちらです → cropbox_mobile.js

関連記事

Javascript let const アロー関数 クラス

Javascript ES5,6 の新機能(letとconst,アロー関数,クラスなど)

ESとはECMASCriptの略で、ECMA という国際的な標準化機関が定めた JavaScript

記事を読む

canvas タグでお絵描き(レスポンシブ)

canvas タグでお絵描き(レスポンシブ)

簡単なメモ張みたいなものが欲しいので作ってみました。 canvas のレスポンシブが少しひっかかっ

記事を読む

JavaScript 規制標識 タイピングゲーム(自分用・激ムズ)

HTML5 audio タグ を使って音声を出す

HTML5からaudioタグを使えば、Flashなどのプラグインを使わなくてもブラウザ上で音声を再生

記事を読む

Three.jsで360°パノラマ画像を VR させる

Three.jsで360°パノラマ画像を VR させる

Three.jsで360°パノラマ画像を VR させる VRを作るのに前回のプラグイン「WP-VR

記事を読む

Javascript ノード の取得や挿入

Javascript ノードの取得や挿入

ノードの取得 ノードの取得(ダイレクトアクセス) document.getElementById

記事を読む

WEBページをアプリっぽくする(サービスワーカーでホーム画面に追加)

WEBページをアプリっぽくする(サービスワーカーでホーム画面に追加)

前回作ったお絵かきページを、簡単にアプリっぽくしようと思います。 具体的には、スマホで最近よく見か

記事を読む

Strict モード JavaScript

Javascript Strictモード “use strict”;

Strict モード(厳格モード) Strict モードとは、ECMAScript5(2009年1

記事を読む

画像の拡大・縮小 タッチイベント

画像の拡大縮小を javascript の touch イベントでやってみる

画像の幅と高さを取得 まずは、neko.jpg という画像を用意して、幅と高さを取得します。

記事を読む

javascriptで複数同じ名前のformの値を取得する

javascriptで複数同じ名前のformの値を取得するとエラー Cannot read property ‘value’ of undefined

Javascript で value の値を取得する このようなHTMLフォームがあった場合、

記事を読む

Wordpress VR Test

WordPress で VR させて、360°のパノラマ画像を表示する

WordPress.com内ショートコードで VR させる WordPress.com内で、VR(

記事を読む

android javascript

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

wordpress タイトルの変更
WordPress タイトルの変更

テンプレートタグ the_title(); get_the_title

All-in-One WP Migration で サーバ移動
「All-in-One WP Migration」プラグインで 簡単に WordPress のサーバー移行する手順メモ

1.移行元サイトでのデータエクスポート 「All-in-One WP

DNSサーバーとは
ドメインとは?DNSサーバーとは?

ドメインとは? ドメインとは? ドメインとは、インターネット上のネ

javascriptで複数同じ名前のformの値を取得する
javascriptで複数同じ名前のformの値を取得するとエラー Cannot read property ‘value’ of undefined

Javascript で value の値を取得する このようなHT

リビジョンを削除し、テーブルを最適化してDBの容量を削減
WordPress リビジョンを削除し、テーブルを最適化してDBの容量を削減

WordPress リビジョン機能 リビジョンは過去の記事を保存して

→もっと見る

    • 202112
      Mon Tue Wed Thu Fri Sat Sun
      12345
      6789101112
      13141516171819
      20212223242526
      2728293031
    にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ PHPへ にほんブログ村 IT技術ブログ WordPressへ
    にほんブログ村 FC2 Blog Ranking
    PAGE TOP ↑