@@ -20,8 +20,8 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
2020 private _handles : { [ key : string ] : ResizeHandle } = { } ;
2121 private _handleType : string [ ] = [ ] ;
2222 private _handleResizing : ResizeHandle = null ;
23-
2423 private _aspectRatio = 0 ;
24+ private _containment : HTMLElement = null ;
2525 private _origMousePos : Position = null ;
2626
2727 /** Original Size and Position */
@@ -36,6 +36,8 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
3636 private _initSize : Size = null ;
3737 private _initPos : Position = null ;
3838
39+ private _bounding : any = null ;
40+
3941 /** Disables the resizable if set to false. */
4042 @Input ( ) set ngResizable ( v : any ) {
4143 if ( v !== undefined && v !== null && v !== '' ) {
@@ -59,7 +61,17 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
5961 * boolean: When set to true, the element will maintain its original aspect ratio.
6062 * number: Force the element to maintain a specific aspect ratio during resizing.
6163 */
62- @Input ( ) rzAspectRatio : boolean | number = false ;
64+ @Input ( ) rzAspectRatio : boolean | number = false ;
65+
66+ /**
67+ * Constrains resizing to within the bounds of the specified element or region.
68+ * Multiple types supported:
69+ * Selector: The resizable element will be contained to the bounding box of the first element found by the selector.
70+ * If no element is found, no containment will be set.
71+ * Element: The resizable element will be contained to the bounding box of this element.
72+ * String: Possible values: "parent".
73+ */
74+ @Input ( ) rzContainment : string | HTMLElement = null ;
6375
6476 /** emitted when start resizing */
6577 @Output ( ) rzStart = new EventEmitter < IResizeEvent > ( ) ;
@@ -70,7 +82,7 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
7082 /** emitted when stop resizing */
7183 @Output ( ) rzStop = new EventEmitter < IResizeEvent > ( ) ;
7284
73- constructor ( private el : ElementRef , private renderer : Renderer2 ) { }
85+ constructor ( private el : ElementRef < HTMLElement > , private renderer : Renderer2 ) { }
7486
7587 ngOnChanges ( changes : SimpleChanges ) {
7688 if ( changes [ 'rzHandles' ] && ! changes [ 'rzHandles' ] . isFirstChange ( ) ) {
@@ -80,6 +92,10 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
8092 if ( changes [ 'rzAspectRatio' ] && ! changes [ 'rzAspectRatio' ] . isFirstChange ( ) ) {
8193 this . updateAspectRatio ( ) ;
8294 }
95+
96+ if ( changes [ 'rzContainment' ] && ! changes [ 'rzContainment' ] . isFirstChange ( ) ) {
97+ this . updateContainment ( ) ;
98+ }
8399 }
84100
85101 ngOnInit ( ) {
@@ -88,6 +104,7 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
88104
89105 ngOnDestroy ( ) {
90106 this . removeHandles ( ) ;
107+ this . _containment = null ;
91108 }
92109
93110 ngAfterViewInit ( ) {
@@ -97,6 +114,7 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
97114 this . _currSize = Size . copy ( this . _initSize ) ;
98115 this . _currPos = Position . copy ( this . _initPos ) ;
99116 this . updateAspectRatio ( ) ;
117+ this . updateContainment ( ) ;
100118 }
101119
102120 /** A method to reset size */
@@ -106,7 +124,7 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
106124 this . doResize ( ) ;
107125 }
108126
109- /** A method to reset size */
127+ /** A method to get current status */
110128 public getStatus ( ) {
111129 if ( ! this . _currPos || ! this . _currSize ) {
112130 return null ;
@@ -152,6 +170,24 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
152170 }
153171 }
154172
173+ /** Use it to update containment */
174+ private updateContainment ( ) {
175+ if ( ! this . rzContainment ) {
176+ this . _containment = null ;
177+ return ;
178+ }
179+
180+ if ( typeof this . rzContainment === 'string' ) {
181+ if ( this . rzContainment === 'parent' ) {
182+ this . _containment = this . el . nativeElement . parentElement ;
183+ } else {
184+ this . _containment = document . querySelector < HTMLElement > ( this . rzContainment ) ;
185+ }
186+ } else {
187+ this . _containment = this . rzContainment ;
188+ }
189+ }
190+
155191 /** Use it to create handle divs */
156192 private createHandles ( ) {
157193 if ( ! this . rzHandles ) {
@@ -226,6 +262,9 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
226262 this . _origPos = Position . getCurrent ( elm ) ; // x: left, y: top
227263 this . _currSize = Size . copy ( this . _origSize ) ;
228264 this . _currPos = Position . copy ( this . _origPos ) ;
265+ if ( this . _containment ) {
266+ this . getBounding ( ) ;
267+ }
229268 this . startResize ( handle ) ;
230269 }
231270 }
@@ -240,6 +279,9 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
240279 this . _origMousePos = null ;
241280 this . _origSize = null ;
242281 this . _origPos = null ;
282+ if ( this . _containment ) {
283+ this . resetBounding ( ) ;
284+ }
243285 }
244286 }
245287
@@ -286,8 +328,21 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
286328
287329 if ( this . _handleResizing . type . match ( / n / ) ) {
288330 // n, ne, nw
289- this . _currSize . height = this . _origSize . height - p . y ;
290331 this . _currPos . y = this . _origPos . y + p . y ;
332+ this . _currSize . height = this . _origSize . height - p . y ;
333+
334+ // check bounds
335+ if ( this . _containment ) {
336+ if ( this . _currPos . y < 0 ) {
337+ this . _currPos . y = 0 ;
338+ this . _currSize . height = this . _origSize . height + this . _origPos . y ;
339+ }
340+ }
341+
342+ if ( this . _currSize . height < 1 ) {
343+ this . _currSize . height = 1 ;
344+ this . _currPos . y = this . _origPos . y + ( this . _origSize . height - 1 ) ;
345+ }
291346
292347 // aspect ratio
293348 this . adjustByRatio ( 'h' ) ;
@@ -310,10 +365,24 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
310365 this . _currSize . width = this . _origSize . width - p . x ;
311366 this . _currPos . x = this . _origPos . x + p . x ;
312367
368+ // check bounds
369+ if ( this . _containment ) {
370+ if ( this . _currPos . x < 0 ) {
371+ this . _currPos . x = 0 ;
372+ this . _currSize . width = this . _origSize . width + this . _origPos . x ;
373+ }
374+ }
375+
376+ if ( this . _currSize . width < 1 ) {
377+ this . _currSize . width = 1 ;
378+ this . _currPos . x = this . _origPos . x + ( this . _origSize . width - 1 ) ;
379+ }
380+
313381 // aspect ratio
314382 this . adjustByRatio ( 'w' ) ;
315383 }
316384
385+ this . checkBounds ( ) ;
317386 this . doResize ( ) ;
318387 }
319388
@@ -334,4 +403,46 @@ export class AngularResizableDirective implements OnInit, OnChanges, OnDestroy,
334403 }
335404 }
336405 }
406+
407+ private checkBounds ( ) {
408+ if ( this . _containment ) {
409+ const container = this . _containment ;
410+ const maxWidth = this . _bounding . width - this . _bounding . pr - this . el . nativeElement . offsetLeft ;
411+ const maxHeight = this . _bounding . height - this . _bounding . pb - this . el . nativeElement . offsetTop ;
412+
413+ if ( this . _currSize . width > maxWidth ) {
414+ this . _currSize . width = maxWidth ;
415+ }
416+
417+ if ( this . _currSize . height > maxHeight ) {
418+ this . _currSize . height = maxHeight ;
419+ }
420+ }
421+ }
422+
423+ private getBounding ( ) {
424+ const el = this . _containment ;
425+ const computed = window . getComputedStyle ( el ) ;
426+ if ( computed ) {
427+ let p = computed . getPropertyValue ( 'position' ) ;
428+
429+ this . _bounding = { } ;
430+ this . _bounding . width = el . clientWidth ;
431+ this . _bounding . height = el . clientHeight ;
432+ this . _bounding . pr = parseInt ( computed . getPropertyValue ( 'padding-right' ) , 10 ) ;
433+ this . _bounding . pb = parseInt ( computed . getPropertyValue ( 'padding-bottom' ) , 10 ) ;
434+ this . _bounding . position = computed . getPropertyValue ( 'position' ) ;
435+
436+ if ( p === 'static' ) {
437+ this . renderer . setStyle ( el , 'position' , 'relative' ) ;
438+ }
439+ }
440+ }
441+
442+ private resetBounding ( ) {
443+ if ( this . _bounding && this . _bounding . position === 'static' ) {
444+ this . renderer . setStyle ( this . _containment , 'position' , 'relative' ) ;
445+ }
446+ this . _bounding = null ;
447+ }
337448}
0 commit comments