アスペクト比を固定した画像アップローダ

以前[JavaScriptで画像をリサイズしてから画像をアップロードする](https://qiita.com/horikeso/items/c98e4607eb9a633fc806)を試しましたが、
CMS等で使用する画像アップロード類は最終的に画面に出力するためにアスペクト比が重要になることが多そうなので試してみました。


[Croppie](https://foliotek.github.io/Croppie/)とBootstrap4（主にモーダルとファイルセレクタ）を使いました。

作ってみたところズームしたくなったから最大ズームサイズを設定したいんだけど？
https://github.com/Foliotek/Croppie/issues/232

まだないのでとりあえず動的にスライダーのminとmaxが変わるのでファイル選択時に設定する。

```js
document.addEventListener('DOMContentLoaded', function() {

    // bootstrap input file
    $(document).on('change', '.custom-file-input', function(){
        $(this).next('.custom-file-label').html($(this)[0].files[0].name);
    });

    setFileEventListenner();
    var element = document.getElementById('demo-croppie');
    croppie = new Croppie(element, {
        enableExif: false,
        viewport: {
            width: 1050,
            height: 600,
            type: 'square'
        },
        boundary: {
            width: 1150,
            height: 700
        },
        showZoomer: true,
        enableResize: false,
        enableOrientation: true,
        mouseWheelZoom: 'ctrl',
        url: '/dummy_1150_700.png'// default image
    });
    document.getElementById('demo-result').addEventListener('click', function (){
        croppie.result('blob').then(function(blob) {
            var formData = new FormData();
            formData.append('file', blob, 'filename');

            // input type file の 値はjavascriptで上書き出来ないのでajaxで送信する
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function() {
                if (xhr.readyState === XMLHttpRequest.DONE) {
                    if (xhr.status === 200) {
                        // success
                    } else {
                        // error
                    }
                    $('#croppieModal').modal('hide');
                }
            }
            xhr.open('POST', '/upload');
            xhr.send(formData);
        });
    });
});

function setFileEventListenner() {
    document.getElementById('demo-upload').addEventListener('change', loadCroppie);
}

function loadCroppie(event) {

    var fileObject = event.target.files[0];

    if (typeof fileObject === "undefined") {
        return;
    }

    if (fileObject.type.match(/^image\/(jpeg|png)$/) === null) {
        // jpegとpng以外の場合はクリアして終了
        var fileArea = document.getElementById("file-input");
        fileArea.innerHTML = fileArea.innerHTML;
        setFileEventListenner();
        return;
    }

    var reader = new FileReader();

    reader.onload = function(event) {
        croppie.bind({
            url: event.target.result// base64
        }).then(function(){
            var slider = document.querySelector('.cr-slider');
            slider.setAttribute('max', parseFloat(slider.getAttribute('min')) + 5);
        });
    };

    reader.readAsDataURL(fileObject);
}
```


バックエンドが無いので失敗しますが、ローカルではきちんとトリミングされた画像が保存できました。

[full](https://codepen.io/horikeso/full/pXzzwp)

<p class="codepen" data-height="800" data-theme-id="0" data-default-tab="result" data-user="horikeso" data-slug-hash="pXzzwp" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Croppie File Uploader">
  <span>See the Pen <a href="https://codepen.io/horikeso/pen/pXzzwp/">
  Croppie File Uploader</a> by horikeso (<a href="https://codepen.io/horikeso">@horikeso</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>