写真をアップロードして切り抜きが出来るcropboxにタッチイベントを付けてみる
公開日:
:
android, javascript
Git Hub の cropbox
写真をアップロードしてカット出来るjQueryのプラグイン cropbox というものが Git Hub にあり、手軽に設置出来て気に入りました。
cropbox のスクリーンショットはこんな感じです。デモは一番最後にあります。
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 写真ギャラリー サムネイルスライド横 レスポンシブ対応
Javascript でマウスドラッグのテストをしていきます。 分かりやすいように、ボールを投げる
-
canvas タグでお絵描き(レスポンシブ)
簡単なメモ張みたいなものが欲しいので作ってみました。 canvas のレスポンシブが少しひっかかっ
-
Javascript タイピング ゲーム スマホ用 をつくる
JavaScript スマホ用 切り替え 前回の記事のゲームですが、スマホだとサイズが合わなくてや
-
javascriptで複数同じ名前のformの値を取得するとエラー Cannot read property ‘value’ of undefined
Javascript で value の値を取得する このようなHTMLフォームがあった場合、
-
Three.jsで360°パノラマ画像を VR させる
Three.jsで360°パノラマ画像を VR させる VRを作るのに前回のプラグイン「WP-VR
-
Javascript ES5,6 の新機能(letとconst,アロー関数,クラスなど)
ESとはECMASCriptの略で、ECMA という国際的な標準化機関が定めた JavaScript
-
WEBページをアプリっぽくする(サービスワーカーでホーム画面に追加)
前回作ったお絵かきページを、簡単にアプリっぽくしようと思います。 具体的には、スマホで最近よく見か
-
HTML5 audio タグ を使って音声を出す
HTML5からaudioタグを使えば、Flashなどのプラグインを使わなくてもブラウザ上で音声を再生
-
画像の拡大縮小を javascript の touch イベントでやってみる
画像の幅と高さを取得 まずは、neko.jpg という画像を用意して、幅と高さを取得します。
-
Javascript ノードの取得や挿入
ノードの取得 ノードの取得(ダイレクトアクセス) document.getElementById