Railsにおいて、Cropper.jsを使用して画像のトリミングを試みているのですが、
うまく表示するときと、表示できないときがあります。
モーダルを表示してそのモーダル内でトリミングを行いたいです。
コード
もとのERB(このコントロールをクリックしてモーダル表示)
erb
1<div class="field image"> 2 <i class="far fa-check-square"></i> 3 <div id="img_field" onClick="$('#icon').click()" > 4 <% if @user.icon.url.present? %> 5 <%= image_tag @user.icon.url %> 6 <% else %> 7 <i class="fas fa-image"></i><i class="fas fa-file-upload add"></i> 8 <% end %> 9 </div> 10 <%= f.file_field :icon, class: 'image', style: 'display:none;', id: 'icon'%> 11</div>
モーダルerb
erb
1<div class="modal fade" data-backdrop="static" id="modal-img" tabindex="-1"> 2 <div class="modal-dialog"> 3 <div class="modal-content"> 4 <div class="modal-body"> 5 <div class="crop_view"></div> 6 </div> 7 <div class="modal-footer"> 8 <button type="button" class="btn btn-default select_icon_btn" data-dismiss="modal">OK</button> 9 <button type="button" class="btn btn-default close_btn" data-dismiss="modal">閉じる</button> 10 </div> 11 </div> 12 </div> 13</div>
モーダル呼び出し元のjs(ユーザー編集画面を想定しているので、ユーザー名などに関する記載もある)
js
1// アイコントリミング 2 3$(function(){ 4 // cropper(トリミング部)のコーディング(詳しくはGitHub参照 5 let cropper; 6 let croppable = false; 7 function initIconCrop(){ 8 cropper = new Cropper(crop_img, { 9 dragMode: 'move', //ドラッグの際にcanvasを動かす 10 aspectRatio: 1, //アクセプト比率 11 restore: false, //ウィンドウのサイズ変更の際、トリミング領域を戻す 12 guides: false, //トリミング領域に破線を表示する 13 highlight: false, //トリミングボックスを強調表示する 14 center: false, //真ん中に+印を表示する 15 cropBoxMovable: false, //ドラッグでCropBoxを動かす 16 cropBoxResizable: false, //ドラッグでCropBoxのサイズを戻す 17 toggleDragModeOnDblclick: false, //ダブルクリックでドラッグモードの切り替えをする 18 minCropBoxWidth: 200, 19 minCropBoxHeight: 200, 20 ready: function(){ 21 croppable = true; 22 } 23 }); 24 } 25 26 // croppedCanvas(トリミング後の画像をプレビューとして表示するための部分) 27 // のコーディング 28 let croppedCanvas; 29 function iconCropping(){ 30 if(!croppable){ 31 alert('トリミングする画像が設定されていません。'); 32 return false; 33 } 34 croppedCanvas = cropper.getCroppedCanvas({ 35 width: 200, 36 height: 200, 37 }); 38 let croppedImage = document.createElement('img'); 39 croppedImage.src = croppedCanvas.toDataURL(); 40 img_field.innerHTML = ''; 41 img_field.appendChild(croppedImage); 42 }; 43 44 // blobへ変換するためのコーディング(blobという形式で画像データを保存するため) 45 let blob; 46 function blobing(){ 47 if (croppedCanvas && croppedCanvas.toBlob){ 48 // if ~.toBlob -> HTMLCanvasElement.toBlob() が使用できる場合 49 croppedCanvas.toBlob(function(b){ 50 blob = b; 51 }); 52 }else if(croppedCanvas && croppedCanvas.msToBlob){ 53 // msToblob -> IE10以降やEDGEで使えるメソッド 54 blob = croppedCanvas.msToBlob(); 55 }else{ 56 blob = null; 57 } 58 }; 59 60 // 入力されたformデータ(textやradioなど)を取得する関数作成 61 function usersVal(formData){ 62 name = $('#user_name').val(); 63 email = $('#user_email').val(); 64 password = $('#user_password').val(); 65 password_confirmation = $('#user_password_confirmation').val(); 66 67 if (blob != null) formData.append('icon', blob); 68 formData.append('name', name); 69 formData.append('email', email); 70 formData.append('password', password); 71 formData.append('password_confirmation', password_confirmation); 72 73 return formData 74 } 75 76 // formデータをまとめてajaxでコントローラーに渡すための準備 77 function sending(){ 78 var formData = new FormData(); 79 const id = $('#idParams').val(); 80 81 // CSRF対策(独自のajax処理を行う場合、head内にあるcsrf-tokenを取得して送る必要がある) 82 $.ajaxPrefilter(function(options, originalOptions, jqXHR){ 83 var token; 84 if (!options.crossDomain){ 85 token = $('meta[name="csrf-token"]').attr('content'); 86 87 if (token){ 88 return jqXHR.setRequestHeader('X-CSRF-Token', token); 89 }; 90 }; 91 }); 92 // 入力されたformデータをformDataに入れる 93 usersVal(formData); 94 95 $.ajax({ 96 url: '/users/' + id, 97 datatype: 'json', 98 type: 'patch', 99 data: formData, 100 processData: false, 101 contentType: false, 102 }); 103 }; 104 105 // 画像選択時 106 $('#icon').on('change', function(e){ 107 file = e.target.files[0]; 108 reader = new FileReader(); 109 110 // 選択されたファイルの確認 111 if(!file || file.type.indexOf('image') < 0) return false; 112 // modal表示 113 $('#modal-img').modal(); 114 // トリミング画面をフェードインさせる 115 reader.onload = (function(e){ 116 $('.crop_view').append($('<img>').attr({ 117 src: e.target.result, 118 class: "preview", 119 id: "crop_img", 120 title: file.name 121 })); 122 initIconCrop(); 123 }); 124 // Cropper.jsが読み込めるようにBase64データとして取得 125 reader.readAsDataURL(file); 126 $(this).val(''); //同じファイルを検知するためにvalueを削除 127 }); 128 129 // トリミング決定時 130 $('.select_icon_btn').on('click', function(){ 131 iconCropping(); 132 //$('.overlay').fadeOut(); 133 $('#crop_img').remove(); 134 $('.cropper-container').remove(); 135 blobing(); 136 }); 137 138 // トリミング画面を閉じる時 139 $('.close_btn').on('click', function(){ 140 //$('.overlay').fadeOut(); 141 $('#crop_img').remove(); 142 $('.cropper-container').remove(); 143 }); 144 145 // コントローラーへ送信 146 $('.submit_btn').on('click', function(){ 147 sending(); 148 }); 149});
cropperに関するscss
scss
1.crop_modal{ 2 max-height: 500px; 3 min-width: 70%; 4 } 5 6.crop_view { 7 width: 466px; 8 height: 500px; 9 } 10 11.cropper-face { 12 border-radius: 50%; 13 } 14 15//TODO: 角を丸くする方法を考える 16.cropper-view-box { 17 border-radius: 50%; 18 outline: none; 19 } 20 21 .modal-content { 22 width: 500px; 23 height: 605px; 24 } 25 26 .cropper-container.cropper-bg { 27 min-width: 100%; 28 min-height: 100%; 29 } 30 31 .cropper-crop-box { 32 width: 200px!important; 33 height: 200px!important; 34}
現状
画面が小さい
画像、切り取り部分が左上にある
というのが解消したい課題であります。
(画像の見た目サイズが大きくないとうまくいかない?)
理想としては、
切り取り部分は常に真ん中にあり、
画像サイズは、上下左右の比率は崩さずに、枠内に収まるよう縮小して表示したいです。
皆様、ご協力お願いします。
環境
Windows10
ruby 2.6.3
rails 5.2.3
Cropper.js v1.5.1
あなたの回答
tips
プレビュー