はじめに
お久しぶりです!
クロスマート株式会社でフロントエンドのタスクを主に担当しております。ナイスガイの福留です。
大腿骨頸部骨折して緊急搬送されたエンジニアが3ヶ月半の入院中でも仕事が出来た訳の執筆後、特に大腿骨周りに異常はなく健康に過ごせております。
日々の散歩とカルシウムは大事ですね。
本日は、弊社プロダクトでも使用しているライブラリであるvue-cropperjsを色々調べてみる記事になります。
また以下から弊社のエンジニアチームによって投稿している記事一覧が閲覧可能です。
xmart-techblog.hatenablog.com xmart-techblog.hatenablog.com
ぜひ読者になるもクリックいただけると嬉しいです!
vue-cropperjsの概要
vue-cropperjsとは、Vue用の画像切り抜きツール(ライブラリ)です。
Cropper.jsというライブラリをVueに最適化させたものであり、画像のサイズを変更したり、回転したり、トリミングしたりすることができます。
具体的には、商品の画像をアップロードし、切り抜き・回転を行い登録するような処理に使用しています。
調査
まずは、あらためて、READMEから情報を攫ってみようかと思います。
(気になったところ、目についたところを適当に抜粋します。)
README
バージョンについて
Vue Version | Package Version |
---|---|
3.x.x | >=5.0.0 |
2.x.x | 4.2.0 |
1.x.x | 1.0.3 |
vue 1系だと1.0.3まで、 vue 2系だと4.2まで、 3系だと5(latest)を使用出来るようです。 対応しないバージョンをinstallしても動作しないのでご注意ください
Props
名称 | 型 | デフォルト値 | 概要 |
---|---|---|---|
containerStyle | Object | - | コンテナのスタイル |
src | String | '' | 画像のソース(URL、Base64、Blobなど) |
alt | String | - | 画像の代替テキスト |
imgStyle | Object | - | 画像のスタイル |
viewMode | Number | - | 表示モード |
dragMode | String | - | ドラッグモード |
initialAspectRatio | Number | - | 初期のアスペクト比 |
aspectRatio | Number | - | クロップボックスのアスペクト比(幅/高さ) |
data | Object | - | クロップデータ |
preview | previewPropType | - | プレビュー要素 |
responsive | Boolean | true | ウィンドウのサイズ変更に応じるかどうか |
restore | Boolean | true | キャンバスの状態を復元するかどうか |
checkCrossOrigin | Boolean | true | クロスオリジンチェックを行うかどうか |
checkOrientation | Boolean | true | Exifのオリエンテーション情報をチェックするかどうか |
crossorigin | String | - | CORS設定(anonymous、use-credentials) |
modal | Boolean | true | モーダルの表示(オーバーレイ) |
guides | Boolean | true | ガイド線の表示 |
center | Boolean | true | センターマーカーの表示 |
highlight | Boolean | true | クロップボックスのハイライト表示 |
background | Boolean | true | キャンバスの背景表示 |
autoCrop | Boolean | true | 自動クロップの有効化 |
autoCropArea | Number | - | 自動クロップ領域のサイズ |
movable | Boolean | true | 画像の移動可能かどうか |
rotatable | Boolean | true | 画像の回転可能かどうか |
scalable | Boolean | true | 画像の拡大縮小可能かどうか |
zoomable | Boolean | true | 画像のズーム可能かどうか |
zoomOnTouch | Boolean | true | タッチデバイスでズーム可能かどうか |
zoomOnWheel | Boolean | true | マウスホイールでズーム可能か |
wheelZoomRatio | Number | - | マウスホイールでのズームの速さを設定 |
cropBoxMovable | Boolean | true | クロップボックスを移動できるかどうか |
cropBoxResizable | Boolean | true | クロップボックスのサイズを変更できるかどうか |
toggleDragModeOnDblclick | Boolean | true | ダブルクリックでドラッグモードを切り替えるかどうか |
minCanvasWidth | Number | - | キャンバスの最小幅を設定 |
minCanvasHeight | Number | - | キャンバスの最小高さを設定 |
minCropBoxWidth | Number | - | クロップボックスの最小幅を設定 |
minCropBoxHeight | Number | - | クロップボックスの最小高さを設定 |
minContainerWidth | Number | - | コンテナの最小幅を設定 |
minContainerHeight | Number | - | コンテナの最小高さを設定 |
おおよそ、よく使うオプションは以下ではないかと思います。
- src
- 画像のソースを指定(URL、Base64、Blob形式)
- aspectRatio
- クロップボックスのアスペクト比を設定(幅/高さ)
- viewMode
- 画像とクロップボックスの相互作用を制御
- dragMode
- ドラッグ操作のモードを選択("crop"、"move"、"none")
- autoCrop
- 画像読み込み時に自動クロップボックス作成を設定
- zoomOnTouch
- タッチデバイスでピンチジェスチャによるズーム設定
- zoomOnWheel
- マウスホイールでのズーム設定
コールバック
名称 | 概要 |
---|---|
ready | 画像が読み込まれたときに呼び出されるコールバック関数 |
cropstart | クロップが開始されたときに呼び出されるコールバック関数 |
cropmove | クロップが移動されたときに呼び出されるコールバック関数 |
cropend | クロップが終了されたときに呼び出されるコールバック関数 |
crop | クロップが完了したときに呼び出されるコールバック関数 |
zoom | ズームイベントが発生したときに呼び出されるコールバック関数 |
それぞれの挙動についてですが、codesandboxを用意しました。
consoleから、各コールバックの挙動や、カスタムイベントの型について観察することが出来ます。
実装編
とりあえずsandboxで公式exampleを動かしてみました。
Vue3 (Composition API ver.)
これらを見るとわかりますが、vue-cropperの最大の旨味としては、簡単に画像編集機能を実装できるだけでなく、refを使用してコンポーネントにアクセスし、イベントを取得したり、現在の画像の状況を取得できることです。
画像編集機能において、柔軟性や拡張性をもたらすことが出来ます。
応用編
またそれらを利用し、以下のような実装を行うことが可能です。
円形切り取り
円形切り取りとは言いますが、実際に円形の画像を生成するというより、正方形に画像を出力・表示する際に円形表示するという手法を取ります。
さまざまなSNSのプロフィール画像等が円形切り取りの例ですが、画像URLを直接表示すると四角形の画像が表示されることがあります。
具体的には上のようなExampleから、切り取りエリア・プレビューを円形に表示するようなCSSを実装します。
例えば、以下のようなものです。
.cropper-view-box, .cropper-face { border-radius: 50%; }
Cropper.jsの機能で追加される切り取りエリアに、.cropper-view-box, .cropper-face等のクラスが振られるように設定されているため、上書きすることが可能です。
プレビューの表示も同様に、受け取った画像の表示をborder-radius: 50%することでSNSのアイコンの設定画面を実装することが可能です。
画像サイズの自動調整
ユーザーのアップロードフォームにvue-cropperjsのコンポーネントを設置する場合、およその割合でアップロードされた画像・作成された画像をデータベースないしストレージサービスに保存すると思われます。
その時、ユーザーが好き勝手に画像をアップロードしてしまうと、サーバーの容量を圧迫したり、追加で料金が必要となる場合があります。
対策としては、アップロードされた時や登録時にファイルの容量をチェック・一定量を超える容量であればエラーメッセージをアラート形式で表示する、等があります。
しかし、画像をアップするために選択・切り取りを行った後にそのようなエラーが出て、作業がやり直しとなった場合はやるせない気持ちになります。私なら悲しく感じます。
よって、容量や通信がシビアな場合、vue-cropperjsやその周辺で画像のリサイズをおこなってしまうのが良いかと考えます。
例えば、以下のような実装になります。
async cropHandler() { // 切り取り時に切り取られた画像を取得 const cropImage = this.$refs.cropper.getCroppedCanvas().toDataURL(); this.resize( cropImage, 70, 70, await function (image) { // リサイズされた画像データが入っている return image; } ); }, resize(cropImage, width, height, callback) { const imageType = cropImage.substring(5, cropImage.indexOf(";")); const image = new Image(); image.onload = function () { let canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; let ctx = canvas.getContext("2d"); ctx.drawImage(image, 0, 0, width, height); const ImageDst = canvas.toDataURL(imageType); callback(ImageDst); }; },
切り取られた画像を取得し、仮想のcanvasに特定の画像サイズで描画のみせずに出力・仮想のcanvasから再度取得し画像サイズをある程度削る、というものです。
こういった応用的な実装を行うことで、vue-cropperjsを使い一段階上のアプリケーションを開発することが可能かと思います。
最後に
最後まで読んでいただいて、ありがとうございました!
弊社ではバックエンド、フロントエンドエンジニアの方を募集しています。
社員を第一に考える、とても働きやすくチャレンジしやすい・スキルを上げながら働くことの出来る会社です。
クロスマート株式会社について気になった方がいらっしゃいましたら、以下のリンクから「話を聞きに行きたい」をお願いします!
www.wantedly.com