@@ -10,7 +10,7 @@ import {
10
10
OnInit ,
11
11
Output
12
12
} from '@angular/core' ;
13
- import { Subscription } from 'rxjs' ;
13
+ import { fromEvent , Subscription , withLatestFrom , zipWith } from 'rxjs' ;
14
14
15
15
import { IntersectionService } from '../../services/intersection.service' ;
16
16
import { IListenersConfig , ListenersService } from '../../services/listeners.service' ;
@@ -58,6 +58,12 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
58
58
* @type {'hover' | 'focus' | 'click' }
59
59
*/
60
60
@Input ( ) pause : Triggers | Triggers [ ] | false = 'hover' ;
61
+ /**
62
+ * Support left/right swipe interactions on touchscreen devices.
63
+ * @type boolean
64
+ * @default true
65
+ */
66
+ @Input ( ) touch : boolean = true ;
61
67
/**
62
68
* Set type of the transition.
63
69
* @type {'slide' | 'crossfade' }
@@ -90,6 +96,7 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
90
96
private timerId ! : any ;
91
97
private intersectingSubscription ?: Subscription ;
92
98
private activeItemInterval = 0 ;
99
+ private swipeSubscription ?: Subscription ;
93
100
94
101
constructor (
95
102
@Inject ( CarouselConfig ) private config : CarouselConfig ,
@@ -110,13 +117,15 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
110
117
this . clearListeners ( ) ;
111
118
this . carouselStateSubscribe ( false ) ;
112
119
this . intersectionServiceSubscribe ( false ) ;
120
+ this . swipeSubscribe ( false ) ;
113
121
}
114
122
115
123
ngAfterContentInit ( ) : void {
116
124
this . intersectionService . createIntersectionObserver ( this . hostElement ) ;
117
125
this . intersectionServiceSubscribe ( ) ;
118
126
this . carouselState . state = { activeItemIndex : this . activeIndex , animate : this . animate } ;
119
127
this . setListeners ( ) ;
128
+ this . swipeSubscribe ( ) ;
120
129
}
121
130
122
131
private setListeners ( ) : void {
@@ -140,9 +149,11 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
140
149
set visible ( value ) {
141
150
this . _visible = value ;
142
151
}
152
+
143
153
get visible ( ) {
144
154
return this . _visible ;
145
155
}
156
+
146
157
private _visible : boolean = true ;
147
158
148
159
setTimer ( ) : void {
@@ -185,4 +196,25 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
185
196
this . intersectingSubscription ?. unsubscribe ( ) ;
186
197
}
187
198
}
199
+
200
+ private swipeSubscribe ( subscribe : boolean = true ) : void {
201
+ if ( this . touch && subscribe ) {
202
+ const carouselElement = this . hostElement . nativeElement ;
203
+ const touchStart$ = fromEvent < TouchEvent > ( carouselElement , 'touchstart' ) ;
204
+ const touchEnd$ = fromEvent < TouchEvent > ( carouselElement , 'touchend' ) ;
205
+ const touchMove$ = fromEvent < TouchEvent > ( carouselElement , 'touchmove' ) ;
206
+ this . swipeSubscription = touchStart$ . pipe ( zipWith ( touchEnd$ . pipe ( withLatestFrom ( touchMove$ ) ) ) )
207
+ . subscribe ( ( [ touchstart , [ touchend , touchmove ] ] ) => {
208
+ touchstart . stopPropagation ( ) ;
209
+ touchmove . stopPropagation ( ) ;
210
+ const distanceX = touchstart . touches [ 0 ] . clientX - touchmove . touches [ 0 ] . clientX ;
211
+ if ( Math . abs ( distanceX ) > 0.3 * carouselElement . clientWidth && touchstart . timeStamp <= touchmove . timeStamp ) {
212
+ const nextIndex = this . carouselState . direction ( distanceX > 0 ? 'next' : 'prev' ) ;
213
+ this . carouselState . state = { activeItemIndex : nextIndex } ;
214
+ }
215
+ } ) ;
216
+ } else {
217
+ this . swipeSubscription ?. unsubscribe ( ) ;
218
+ }
219
+ }
188
220
}
0 commit comments