書くこと
- LaravelにCropper導入
- Cropperを使った画像データの受け渡し
書かないこと
- Cropperからもらったデータでの処理
- CSSなどのUI部分
前提
- templateはbladeです
- Laravel 5.6での実装(たぶん、ほかのVersionでもいけます)
- Composerやnpmでのモジュール導入ができる
- ある程度のLaravelの前提知識がある
- 今回のcropperはJQuery用なのでJQueryが読み込まれていること
流れ
- Cropperって?
- Cropperの準備
- Cropperの読み込み
- Cropperの最適化
1. Cropperって?
- 必要なモジュール準備
- フロントの実装
- バックエンドの実装
1. 必要なモジュール準備
- JavaScriptを使った画像加工の便利なモジュール。
- 基本的には擬似加工処理をするだけで実際の加工は裏側で行う(はず)
2. Cropperの準備
Laravelで使うnodeにて管理できるのでnpm(nodeオーケストレーション)で準備する。
1. Cropperのinstall
コンソール画面にて以下のコマンドを入力する
npm install cropper
2. Cropperのファイルを配備
Laravelにあるwebpackの機能を使いCropperで使うファイルをpublicディレクトリ配下に置く。
publicにcopyしておくことで、勝手に更新されたり、気づかないうちに差分が出て動かなくなるなどを防ぐのが目的。
webpack.mix.js に記載
mix.copy('node_modules/cropper/dist/cropper.min.css', 'public/css/cropper.min.css').version();
mix.copy('node_modules/cropper/dist/cropper.min.js', 'public/js/cropper.min.js').version();
3. Cropperの読み込み
読み込みたい箇所に記載
<link href="{{ mix('css/cropper.min.css') }}" rel="stylesheet">
<script src="{{ mix('js/cropper.min.js') }}"></script>
4. Cropperの最適化
HTML部分(blade)
<!-- cropperの領域 -->
<div id="img-cropper-image" data-name="image">
<div class="close-area">
<i class="fa fa-times" aria-hidden="true"></i>
</div>
<div class="wrapper"></div>
<div class="btn btn-primary">画像を加工する</div>
</div>
{!! Form::open(['route' => ['store'], 'files' => true]) !!}
<div class="cropper-file" data-name="image">
{{ Form::file('image', ['id' => 'datafile']) }}
<label for="datafile">画像を選ぶ</label>
<!-- プレビューが表示される枠 -->
<div class="img-preview">
@if($image)
{{ Html::image($image->path, null, ['width' => '420px']) }}
@endif
</div>
<!-- Cropperで計算したデータをformで送るためのhidden要素 -->
{{ Form::hidden('image_cropp_width', null) }}
{{ Form::hidden('image_cropp_height', null) }}
{{ Form::hidden('image_cropp_x', null) }}
{{ Form::hidden('image_cropp_y', null) }}
</div>
{{!! Form::close() !!}}
JS部分
<script>
$(function () {
// 「画像を加工する」もしくはモーダルを閉じたことで発火
// CropperのデータをHTMLに挿入する
$('[id="img-cropper-image"]').on('click', '.btn,.fa-times', function () {
var imgCropper = $(this).parents('[id="img-cropper-image"]');
var imageName = imgCropper.data('name');
var data = imgCropper.find('.wrapper > img').cropper('getData');
$('input[name="'+ imageName +'_cropp_width"]').val(Math.round(data.width));
$('input[name="'+ imageName +'_cropp_height"]').val(Math.round(data.height));
$('input[name="'+ imageName +'_cropp_x"]').val(Math.round(data.x));
$('input[name="'+ imageName +'_cropp_y"]').val(Math.round(data.y));
imgCropper.css({'width':'0','height':'0','position':'static'});
});
// ファイルがアップロードされたことで発火
// Cropperを起動する
$('[id^="datafile"]').on('change', function (e) {
var file = e.target.files[0],
reader = new FileReader(),
previewDiv = $(this).parents('.cropper-file').find(".img-preview"),
croppDiv = $('#img-cropper-' + $(this).parents('.cropper-file').data('name'));
// 画像ファイル以外の場合は何もしない
if(file.type.indexOf("image") < 0){
return false;
}
// check over 2MB
if (file.size > 2097152) {
alert('お手数ですが、画像のサイズは2MB以下のものをご用意ください。');
return;
}
img = new Image();
img.onload = function () {
// ファイル読み込みが完了した際のイベント登録
reader.onload = (function(file) {
return function(e) {
//既存のプレビューを削除
previewDiv.empty();
// .prevewの領域の中にロードした画像を表示するimageタグを追加
previewDiv.append($('<img>').attr({
src: e.target.result,
title: file.name
})).show();
croppDiv.css({'width':'100%','height':'100%','position':'fixed'}).show();
//既存のcropper用画像を削除
croppDiv.find('.wrapper').empty();
// #img-cropperの領域の中にロードした画像を表示するimageタグを追加
var appendImage = $('<img>').attr({
src: e.target.result,
title: file.name
});
croppDiv.find('.wrapper').append(appendImage);
appendImage.ready(function () {
var image = croppDiv.find('img');
image.cropper({
preview: previewDiv,
@if(isset($aspectRatio) && $aspectRatio)
aspectRatio: 3 / 2,
@endif
});
});
};
})(file);
reader.readAsDataURL(file);
};
img.src = (window.URL || window.webkitURL).createObjectURL(file);
});
});
</script>
おわりに
冒頭にも書いたんですが、CSS部分は一切記載ないので
このままつかってもうまく動かないと思います。あくまでJSとHTML(blade)部分の
参考と思ってください。
余力あればGitにコードあげます笑