@@ -25,6 +25,15 @@ export interface CropperConfiguration {
2525 } [ ] ;
2626}
2727
28+ function inSelection ( selection : Selection , maxSelection : Selection ) : boolean {
29+ return (
30+ selection . x >= maxSelection . x &&
31+ selection . y >= maxSelection . y &&
32+ selection . x + selection . width <= maxSelection . x + maxSelection . width &&
33+ selection . y + selection . height <= maxSelection . y + maxSelection . height
34+ ) ;
35+ }
36+
2837abstract class ImageCropper {
2938 readonly configuration : CropperConfiguration ;
3039 readonly file : File ;
@@ -128,7 +137,7 @@ abstract class ImageCropper {
128137 protected setCropperStyle ( ) {
129138 this . cropperCanvas ! . style . aspectRatio = `${ this . width } /${ this . height } ` ;
130139
131- if ( this . width > this . height ) {
140+ if ( this . width >= this . height ) {
132141 this . cropperCanvas ! . style . width = `min(70vw, ${ this . width } px)` ;
133142 this . cropperCanvas ! . style . height = "auto" ;
134143 } else {
@@ -153,33 +162,34 @@ abstract class ImageCropper {
153162 if ( this . orientation ) {
154163 this . cropperImage ! . $rotate ( `${ this . orientation } deg` ) ;
155164 }
156- this . cropperImage ! . $center ( "contain" ) ;
157- this . cropperSelection ! . $center ( ) ;
158- this . cropperSelection ! . scrollIntoView ( { block : "center" , inline : "center" } ) ;
165+
166+ this . centerSelection ( ) ;
159167
160168 // Limit the selection to the canvas boundaries
161169 this . cropperSelection ! . addEventListener ( "change" , ( event : CustomEvent ) => {
162170 // see https://fengyuanchen.github.io/cropperjs/v2/api/cropper-selection.html#limit-boundaries
163171 const cropperCanvasRect = this . cropperCanvas ! . getBoundingClientRect ( ) ;
164172 const selection = event . detail as Selection ;
165173
174+ const cropperImageRect = this . cropperImage ! . getBoundingClientRect ( ) ;
166175 const maxSelection : Selection = {
167- x : 0 ,
168- y : 0 ,
169- width : cropperCanvasRect . width ,
170- height : cropperCanvasRect . height ,
176+ x : Math . round ( cropperImageRect . left - cropperCanvasRect . left ) ,
177+ y : Math . round ( cropperImageRect . top - cropperCanvasRect . top ) ,
178+ width : Math . round ( cropperImageRect . width ) ,
179+ height : Math . round ( cropperImageRect . height ) ,
171180 } ;
172181
173- if (
174- selection . x < maxSelection . x ||
175- selection . y < maxSelection . y ||
176- selection . x + selection . width > maxSelection . x + maxSelection . width ||
177- selection . y + selection . height > maxSelection . y + maxSelection . height
178- ) {
182+ if ( ! inSelection ( selection , maxSelection ) ) {
179183 event . preventDefault ( ) ;
180184 }
181185 } ) ;
182186 }
187+
188+ protected centerSelection ( ) : void {
189+ this . cropperImage ! . $center ( "contain" ) ;
190+ this . cropperSelection ! . $center ( ) ;
191+ this . cropperSelection ! . scrollIntoView ( { block : "center" , inline : "center" } ) ;
192+ }
183193}
184194
185195class ExactImageCropper extends ImageCropper {
@@ -284,11 +294,11 @@ class MinMaxImageCropper extends ImageCropper {
284294
285295 protected getCropperTemplate ( ) : string {
286296 return `<div class="cropperContainer">
287- <cropper-canvas background>
297+ <cropper-canvas background scale-step="0.0" >
288298 <cropper-image skewable scalable translatable rotatable></cropper-image>
289299 <cropper-shade hidden></cropper-shade>
290- <cropper-handle action="move" plain ></cropper-handle>
291- <cropper-selection movable zoomable resizable outlined>
300+ <cropper-handle action="scale" hidden disabled ></cropper-handle>
301+ <cropper-selection movable resizable outlined>
292302 <cropper-grid role="grid" bordered covered></cropper-grid>
293303 <cropper-crosshair centered></cropper-crosshair>
294304 <cropper-handle action="move" theme-color="rgba(255, 255, 255, 0.35)"></cropper-handle>
@@ -308,18 +318,18 @@ class MinMaxImageCropper extends ImageCropper {
308318 protected setCropperStyle ( ) {
309319 super . setCropperStyle ( ) ;
310320
311- this . cropperSelection ! . width = this . minSize . width ;
312- this . cropperSelection ! . height = this . minSize . height ;
313- this . cropperCanvas ! . style . minWidth = `min(${ this . maxSize . width } px, ${ this . width } px)` ;
314- this . cropperCanvas ! . style . minHeight = `min(${ this . maxSize . height } px, ${ this . height } px)` ;
321+ if ( this . width >= this . height ) {
322+ this . cropperCanvas ! . style . width = `${ Math . min ( this . maxSize . width , this . width ) } px` ;
323+ } else {
324+ this . cropperCanvas ! . style . height = `${ Math . min ( this . maxSize . height , this . height ) } px` ;
325+ }
315326 }
316327
317328 protected createCropper ( ) {
318329 super . createCropper ( ) ;
319330
320331 this . dialog ! . addEventListener ( "extra" , ( ) => {
321- this . cropperImage ! . $center ( "contain" ) ;
322- this . cropperSelection ! . $reset ( ) ;
332+ this . centerSelection ( ) ;
323333 } ) ;
324334
325335 // Limit the selection to the min/max size
@@ -336,6 +346,23 @@ class MinMaxImageCropper extends ImageCropper {
336346 }
337347 } ) ;
338348 }
349+
350+ protected centerSelection ( ) : void {
351+ this . cropperImage ! . $center ( "contain" ) ;
352+
353+ const { width : imageWidth } = this . cropperImage ! . getBoundingClientRect ( ) ;
354+
355+ this . cropperSelection ! . $change (
356+ 0 ,
357+ 0 ,
358+ imageWidth ,
359+ 0 ,
360+ this . configuration . aspectRatio ,
361+ true ,
362+ ) ;
363+ this . cropperSelection ! . $center ( ) ;
364+ this . cropperSelection ! . scrollIntoView ( { block : "center" , inline : "center" } ) ;
365+ }
339366}
340367
341368export async function cropImage (
0 commit comments