@@ -12,9 +12,10 @@ import {
12
12
SimpleChanges ,
13
13
Inject ,
14
14
TemplateRef ,
15
- ViewContainerRef
15
+ ViewContainerRef ,
16
+ Optional
16
17
} from '@angular/core' ;
17
- import { Subject , Observable , merge , ReplaySubject } from 'rxjs' ;
18
+ import { Subject , Observable , merge , ReplaySubject , combineLatest } from 'rxjs' ;
18
19
import {
19
20
map ,
20
21
mergeMap ,
@@ -24,10 +25,12 @@ import {
24
25
pairwise ,
25
26
share ,
26
27
filter ,
27
- count
28
+ count ,
29
+ startWith
28
30
} from 'rxjs/operators' ;
29
31
import { CurrentDragData , DraggableHelper } from './draggable-helper.provider' ;
30
32
import { DOCUMENT } from '@angular/common' ;
33
+ import { DraggableScrollContainerDirective } from './draggable-scroll-container.directive' ;
31
34
32
35
export interface Coordinates {
33
36
x : number ;
@@ -174,6 +177,8 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
174
177
175
178
private ghostElement : HTMLElement | null ;
176
179
180
+ private destroy$ = new Subject ( ) ;
181
+
177
182
/**
178
183
* @hidden
179
184
*/
@@ -183,6 +188,7 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
183
188
private draggableHelper : DraggableHelper ,
184
189
private zone : NgZone ,
185
190
private vcr : ViewContainerRef ,
191
+ @Optional ( ) private scrollContainer : DraggableScrollContainerDirective ,
186
192
@Inject ( DOCUMENT ) private document : any
187
193
) { }
188
194
@@ -210,53 +216,83 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
210
216
) ;
211
217
this . document . head . appendChild ( globalDragStyle ) ;
212
218
219
+ const startScrollPosition = this . getScrollPosition ( ) ;
220
+
221
+ const scrollContainerScroll$ = new Observable ( observer => {
222
+ const scrollContainer = this . scrollContainer
223
+ ? this . scrollContainer . elementRef . nativeElement
224
+ : 'window' ;
225
+ return this . renderer . listen ( scrollContainer , 'scroll' , e =>
226
+ observer . next ( e )
227
+ ) ;
228
+ } ) . pipe (
229
+ startWith ( startScrollPosition ) ,
230
+ map ( ( ) => this . getScrollPosition ( ) )
231
+ ) ;
232
+
213
233
const currentDrag$ = new Subject < CurrentDragData > ( ) ;
214
234
const cancelDrag$ = new ReplaySubject < void > ( ) ;
215
235
216
236
this . zone . run ( ( ) => {
217
237
this . dragPointerDown . next ( { x : 0 , y : 0 } ) ;
218
238
} ) ;
219
239
220
- const pointerMove = this . pointerMove . pipe (
221
- map ( ( pointerMoveEvent : PointerEvent ) => {
240
+ const pointerMove = combineLatest <
241
+ PointerEvent ,
242
+ { top : number ; left : number }
243
+ > ( this . pointerMove , scrollContainerScroll$ ) . pipe (
244
+ map ( ( [ pointerMoveEvent , scroll ] ) => {
222
245
return {
223
246
currentDrag$,
224
- x : pointerMoveEvent . clientX - pointerDownEvent . clientX ,
225
- y : pointerMoveEvent . clientY - pointerDownEvent . clientY ,
247
+ transformX : pointerMoveEvent . clientX - pointerDownEvent . clientX ,
248
+ transformY : pointerMoveEvent . clientY - pointerDownEvent . clientY ,
226
249
clientX : pointerMoveEvent . clientX ,
227
- clientY : pointerMoveEvent . clientY
250
+ clientY : pointerMoveEvent . clientY ,
251
+ scrollLeft : scroll . left ,
252
+ scrollTop : scroll . top
228
253
} ;
229
254
} ) ,
230
255
map ( moveData => {
231
256
if ( this . dragSnapGrid . x ) {
232
- moveData . x =
233
- Math . round ( moveData . x / this . dragSnapGrid . x ) *
257
+ moveData . transformX =
258
+ Math . round ( moveData . transformX / this . dragSnapGrid . x ) *
234
259
this . dragSnapGrid . x ;
235
260
}
236
261
237
262
if ( this . dragSnapGrid . y ) {
238
- moveData . y =
239
- Math . round ( moveData . y / this . dragSnapGrid . y ) *
263
+ moveData . transformY =
264
+ Math . round ( moveData . transformY / this . dragSnapGrid . y ) *
240
265
this . dragSnapGrid . y ;
241
266
}
242
267
243
268
return moveData ;
244
269
} ) ,
245
270
map ( moveData => {
246
271
if ( ! this . dragAxis . x ) {
247
- moveData . x = 0 ;
272
+ moveData . transformX = 0 ;
248
273
}
249
274
250
275
if ( ! this . dragAxis . y ) {
251
- moveData . y = 0 ;
276
+ moveData . transformY = 0 ;
252
277
}
253
278
254
279
return moveData ;
255
280
} ) ,
281
+ map ( moveData => {
282
+ const scrollX = moveData . scrollLeft - startScrollPosition . left ;
283
+ const scrollY = moveData . scrollTop - startScrollPosition . top ;
284
+ return {
285
+ ...moveData ,
286
+ x : moveData . transformX + scrollX ,
287
+ y : moveData . transformY + scrollY
288
+ } ;
289
+ } ) ,
256
290
filter (
257
291
( { x, y } ) => ! this . validateDrag || this . validateDrag ( { x, y } )
258
292
) ,
259
- takeUntil ( merge ( this . pointerUp , this . pointerDown , cancelDrag$ ) ) ,
293
+ takeUntil (
294
+ merge ( this . pointerUp , this . pointerDown , cancelDrag$ , this . destroy$ )
295
+ ) ,
260
296
share ( )
261
297
) ;
262
298
@@ -394,26 +430,28 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
394
430
} ) ,
395
431
map ( ( [ previous , next ] ) => next )
396
432
)
397
- . subscribe ( ( { x, y, currentDrag$, clientX, clientY } ) => {
398
- this . zone . run ( ( ) => {
399
- this . dragging . next ( { x, y } ) ;
400
- } ) ;
401
- if ( this . ghostElement ) {
402
- const transform = `translate(${ x } px, ${ y } px)` ;
403
- this . setElementStyles ( this . ghostElement , {
404
- transform,
405
- '-webkit-transform' : transform ,
406
- '-ms-transform' : transform ,
407
- '-moz-transform' : transform ,
408
- '-o-transform' : transform
433
+ . subscribe (
434
+ ( { x, y, currentDrag$, clientX, clientY, transformX, transformY } ) => {
435
+ this . zone . run ( ( ) => {
436
+ this . dragging . next ( { x, y } ) ;
437
+ } ) ;
438
+ if ( this . ghostElement ) {
439
+ const transform = `translate(${ transformX } px, ${ transformY } px)` ;
440
+ this . setElementStyles ( this . ghostElement , {
441
+ transform,
442
+ '-webkit-transform' : transform ,
443
+ '-ms-transform' : transform ,
444
+ '-moz-transform' : transform ,
445
+ '-o-transform' : transform
446
+ } ) ;
447
+ }
448
+ currentDrag$ . next ( {
449
+ clientX,
450
+ clientY,
451
+ dropData : this . dropData
409
452
} ) ;
410
453
}
411
- currentDrag$ . next ( {
412
- clientX,
413
- clientY,
414
- dropData : this . dropData
415
- } ) ;
416
- } ) ;
454
+ ) ;
417
455
}
418
456
419
457
ngOnChanges ( changes : SimpleChanges ) : void {
@@ -427,6 +465,7 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
427
465
this . pointerDown . complete ( ) ;
428
466
this . pointerMove . complete ( ) ;
429
467
this . pointerUp . complete ( ) ;
468
+ this . destroy$ . next ( ) ;
430
469
}
431
470
432
471
private checkEventListeners ( ) : void {
@@ -594,4 +633,18 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
594
633
this . renderer . setStyle ( element , key , styles [ key ] ) ;
595
634
} ) ;
596
635
}
636
+
637
+ private getScrollPosition ( ) {
638
+ if ( this . scrollContainer ) {
639
+ return {
640
+ top : this . scrollContainer . elementRef . nativeElement . scrollTop ,
641
+ left : this . scrollContainer . elementRef . nativeElement . scrollLeft
642
+ } ;
643
+ } else {
644
+ return {
645
+ top : window . pageYOffset || document . documentElement . scrollTop ,
646
+ left : window . pageXOffset || document . documentElement . scrollLeft
647
+ } ;
648
+ }
649
+ }
597
650
}
0 commit comments