【Laravel Blade】Cropperで画像の加工をやってみる

## 書くこと
* LaravelにCropper導入
* Cropperを使った画像データの受け渡し

## 書かないこと
* Cropperからもらったデータでの処理
* CSSなどのUI部分

## 前提
* templateはbladeです
* Laravel 5.6での実装（たぶん、ほかのVersionでもいけます）
* Composerやnpmでのモジュール導入ができる
* ある程度のLaravelの前提知識がある
* 今回のcropperはJQuery用なのでJQueryが読み込まれていること

## 流れ
1. Cropperって？
2. Cropperの準備
3. Cropperの読み込み
4. Cropperの最適化

## 1. Cropperって？
1. 必要なモジュール準備
* フロントの実装
* バックエンドの実装

## 1. 必要なモジュール準備
[cropper](https://fengyuanchen.github.io/cropper/)（[git](https://github.com/fengyuanchen/cropper)） & jquery

* 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にコードあげます笑