画像トリミング機能実装その1
2018年08月8日
目次
画像のトリミング機能実装
こんにちは!ウェブエンジニアのジワタネホです!
今日は久しぶりにフロントエンドっぽい記事を書こうと思います。
今日は画像トリミングに関して!
ユーザー登録などのフォームをリッチな仕様にするには持ってこいのはず!
長くなるので記事を3つに分けます。
誰かの開発の参考になれば!!

ざっくり要件定義
ざっくり要件定義します。
よくあるアプリのマイページで自分のアバターを投稿できたりする機能で、画像をトリミングできるやつですwww
ざっくりですね。
UI的には、
- 1:ボタンをクリックしてユーザーのローカルファイルを選択
- 2:選択した画像ファイルを表示する
- 3:トリミングボタンをクリックしてモーダルを表示させてトリミングを開始する
- 4:トリミング完了ボタンをクリックして画像をトリミングして、トリミングされた画像を表示
ここまでが今回の要件となります。
本当はその画像をajaxでPOSTするところもやろうと思いましたが、記事が長くなるのでやめますwww
ちなみにトリミング画像は、input type="file"では送信できないため、ajaxでのPOSTのみ可能となります。
ご注意ください。
デモ
http://zihuatanejo.jp/demoes/trimming.html
ちなみにコードは以下に置いてあります。トリミング以外もありますが悪しからず。

実装の手順
- 必要なライブラリの実装
- 静的部分のコーディング
- Bootstrapでモーダル実装
- File API実装
- Cropper.jsでトリミング実装
記事毎のレジュメ
画像トリミング機能実装その1(本記事)
必要なライブラリの実装
Cropper.jsとBootstrap4の実装
静的コーディング
まずは下ごしらえです。
Bootstrap4のモーダル実装
やり方というほどのことはありませんが、一応ですね。
本来はFile APIの実装からが順番的には良いのですが、Bootstrap4の実装はすぐなのでこちらから書いていきます。
画像トリミング機能実装その2
File API実装
File APIを使ってローカルのファイルを取得して表示するところまで。
画像トリミング機能実装その3
Cropper.jsを使用してトリミング機能実装
いよいよトリミングっす
必要なライブラリの実装
Bootstrap4

個人的にcssはbootstrapをあまり好んでいませんww
そもそもnormalizeよりreset派です。
が、bootstrapのモーダルはものすごく使いやすいです。
実は引数にオブジェクト渡せたりしますしね。余談ですが。
ということでモーダルのためにbootstrapを入れます。
ちなみにbootstarp4です。
おそらく巷ではbootstrap3の方が実装数は多いかもですがせっかくなんでね。
インストール手順は細かく書いません。
上記リンク先に従ってインストールしてください。
npmでもCDNでも直ダウンロードでも良いです。
Cropper.js
ものすごく優秀なライブラリです。というかトリミング系のライブラリでこれ以外の選択肢はあるのだろうか。。
インストール手順はgithubがあるので以下から
https://github.com/fengyuanchen/cropperjs
cssとjs両方を使えるように落としてください。
静的コーディング
ここも細かくは書きません。
今回のデモはわかりやすく全部デカくはしてありますwww
HTML
<!DOCTYPE html>
<html>
<head>
<meta name=”robots” content=”noindex”>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0, user-scalable=no">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>トリミングのデモ</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div class="wrapper">
<div class="container">
<div class="demoes-header">
<h1 class="__title">トリミングのデモ</h1>
<!-- /.demoes-header --></div>
<div class="demoes-body">
<label class="__label">
<input id="image-file" type="file" class="__input js-imageFile" accept="image/jpeg">
<span class="__text">ファイルを選択</span>
</label>
<p class="__file-name js-fileName" data-file-name="1">ファイルは選択されていません。</p>
<div class="file-image-preview js-previewImageBlock">
<img src="" class="__img js-preaviewImage" id="trimming-image">
<!-- /.file-image-preview --></div>
<button class="trimming-btn" type="button" data-toggle="modal" data-target="#myModal">上の画像をトリミングする</button>
<div class="file-image-trimmed">
<h2 class="__h2">トリミング後の画像が表示されます</h2>
<img id="image" class="__img js-trimmedImg" src="">
</div>
<!-- /.demoes-body --></div>
<!-- / .container --></div>
<!-- / .wrapper --></div>
<div class="modal fade js-trimmingModal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">トリミンングしてください</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<div class="trimming-area">
<img src="" class="js-trimmingAreaImg">
<!-- /.trimming-area --></div>
<!-- /.modal-body --></div>
<div class="modal-footer">
<button type="button" class="btn btn-danger js-trimmingBtn" data-option="">これで決定</button>
</div>
<!-- /.modal-content --></div>
<!-- /.modal-dialog --></div>
<!-- /.modal --></div>
<script src="js/vendor/cropper.js"></script>
<script src="js/page/trimming.js"></script>
<script src="js/vendor/bootstrap.min.js"></script>
</body>
</html>
CSS
@charset "UTF-8";
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,a, abbr, acronym, address, big, cite, code,del, dfn, em, img, ins, kbd, q, s, samp,small, strike, strong, sub, sup, tt, var, b, u, i, center,dl, dt, dd, ol, ul, li,fieldset, form, label, legend,table, caption, tbody, tfoot, thead, tr, th, td,article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary,time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
html, body{
height: 100%;
}
.wrapper{
width: 100%;
padding: 40px 0;
background-color: #eee;
}
.container{
width: 980px;
margin: 0 auto;
background-color: #fff;
}
.demoes-header{
width: 100%;
padding: 16px;
border-bottom: 1px solid #eee;
}
.demoes-header .__title{
font-size: 40px;
text-align: center;
font-weight: bold;
}
.demoes-body{
padding: 16px;
font-size: 24px;
}
.demoes-body .__label{
width: 360px;
display: block;
margin: 0 auto;
border: 1px solid #555;
background-color: #eee;
border-radius: 4px;
text-align: center;
line-height: 2;
cursor: pointer;
}
.demoes-body .__label:hover{
opacity: 0.5;
}
.demoes-body .__input{
display: none;
}
.demoes-body .__text{
font-size: 24px;
}
.demoes-body .__file-name{
margin-top: 16px;
text-align: center;
font-size: 16px;
}
.demoes-body .file-image-preview{
width: 500px;
min-height: 300px;
margin: 16px auto;
border: 1px solid #555;
background-size: contain;
background-repeat: no-repeat;
}
.demoes-body .file-image-preview .__img{
max-width: 100%;
/*width: 100%;*/
}
.demoes-body .trimming-btn{
width: 500px;
display: block;
margin: 0 auto;
background-color: red;
border: none;
border-radius: 8px;
font-size: 32px;
text-align: center;
line-height: 2;
cursor: pointer;
color: #fff;
}
.demoes-body .trimming-btn:hover{
opacity: 0.5;
}
.modal-body .trimming-area{
max-width: 100%;
}
.modal-body .trimming-area img{
width: 100%;
}
.file-image-trimmed{
width: 500px;
margin: 40px auto;
}
.file-image-trimmed .__h2{
font-size: 24px;
text-align: center;
}
.file-image-trimmed .__img{
width: 100%;
}
※CSSに関しては、実際には複数ファイルに分けていますが、上記コードは分けたファイルをひとまとめにしたものです。
※HTMLのbody閉じタグの直前でjsを読み込んでいます。パスは各自で設定してください。また、ライブラリ以外にこちらで編集する用のtrimming.js(名前は任意)を新規で作成してください。
Bootstrap4でモーダル実装
本記事の最後にモーダルの実装をします。
と言ってもBootstrapのモーダルはものすごく簡単です。
というか上記静的コーディングでモーダルも実装されていますww
上記33行目の「上の画像をトリミングする」ボタンをクリックすればモーダルが表示されるはず!
Bootstrapのモーダルは、モーダルを表示させるボタンの要素に以下のデータ属性を二つ追記します。
<button data-toggle="modal" data-target="#myModal">ボタン</button>
上記のdata-targetで指定した#myModal(任意)という要素がモーダルとして表示されます。
最後に
長くなりましたが、本日はここまで!
ちなみに今回はファイル選択ボタンもオリジナルでCSSをあてています。
input type="file"等のオリジナルデザインの作り方に関しては今回は省かせてください。
次回からはいよいよjsをゴリゴリ書いていきます。
乞うご期待!!