@@ -31,15 +31,31 @@ export class CarouselComponent implements AfterViewInit, OnDestroy, OnChanges {
3131
3232 originalItems : any [ ] = [ ] ;
3333 displayItems : any [ ] = [ ] ;
34+ isLoading : boolean = true ;
35+ skeletonItems : any [ ] = new Array ( 6 ) . fill ( 0 ) ;
3436
3537 constructor (
3638 private ngZone : NgZone ,
3739 private dialog : MatDialog
3840 ) { }
3941
4042 ngOnChanges ( changes : SimpleChanges ) {
41- if ( changes [ 'data' ] && this . data ) {
42- this . buildCarouselItems ( ) ;
43+ if ( changes [ 'data' ] ) {
44+ if ( this . data && this . data . length > 0 ) {
45+ this . buildCarouselItems ( ) ;
46+ } else {
47+ this . isLoading = true ;
48+ }
49+ }
50+ }
51+
52+ initializeScroll ( ) {
53+ const container = this . scrollContainer ?. nativeElement ;
54+ if ( container && container . scrollWidth > 0 ) {
55+ const singleSetWidth = container . scrollWidth / 3 ;
56+ container . scrollLeft = singleSetWidth ;
57+ // Trigger one calculation to set initial sizes
58+ this . onScroll ( { target : container } as any ) ;
4359 }
4460 }
4561
@@ -51,31 +67,64 @@ export class CarouselComponent implements AfterViewInit, OnDestroy, OnChanges {
5167 ...item
5268 } ;
5369 } ) ;
70+
5471 this . originalItems = mappedData ;
5572 let loopList = [ ...mappedData ] ;
73+
5674 // If you have 2 items, we duplicate them until we have at least 12.
5775 const MIN_ITEMS = 12 ;
5876 if ( loopList . length > 0 ) {
5977 while ( loopList . length < MIN_ITEMS ) {
6078 loopList = [ ...loopList , ...loopList ] ;
6179 }
6280 }
63- //CREATE 3 SETS: [Left Buffer] [Middle (Active)] [Right Buffer]
81+
6482 this . displayItems = [ ...loopList , ...loopList , ...loopList ] ;
83+
84+ this . preloadImages ( ) ;
85+ }
86+
87+ //Logic to download all images before showing UI
88+ preloadImages ( ) {
89+ this . isLoading = true ;
90+ const uniqueUrls = [ ...new Set ( this . displayItems . map ( item => item . img ) ) ] . filter ( url => url ) ;
91+
92+ let loadedCount = 0 ;
93+ const total = uniqueUrls . length ;
94+
95+ if ( total === 0 ) {
96+ this . finishLoading ( ) ;
97+ return ;
98+ }
99+
100+ uniqueUrls . forEach ( url => {
101+ const img = new Image ( ) ;
102+ img . src = url ;
103+
104+ const onImageComplete = ( ) => {
105+ loadedCount ++ ;
106+ if ( loadedCount === total ) {
107+ this . finishLoading ( ) ;
108+ }
109+ } ;
110+
111+ img . onload = onImageComplete ;
112+ img . onerror = onImageComplete ;
113+ } ) ;
114+ }
115+
116+ finishLoading ( ) {
117+ this . isLoading = false ;
118+ setTimeout ( ( ) => {
119+ this . initializeScroll ( ) ;
120+ } , 0 ) ;
65121 }
66122
67123 ngAfterViewInit ( ) {
68124 this . ngZone . runOutsideAngular ( ( ) => {
69125 const container = this . scrollContainer ?. nativeElement ;
70126 if ( container ) {
71127 container . addEventListener ( 'scroll' , this . onScroll . bind ( this ) ) ;
72- setTimeout ( ( ) => {
73- if ( container . scrollWidth > 0 ) {
74- const singleSetWidth = container . scrollWidth / 3 ;
75- container . scrollLeft = singleSetWidth ;
76- this . onScroll ( { target : container } as any ) ;
77- }
78- } , 50 ) ;
79128 }
80129 } ) ;
81130 }
@@ -88,6 +137,8 @@ export class CarouselComponent implements AfterViewInit, OnDestroy, OnChanges {
88137 }
89138
90139 onScroll ( event : Event ) {
140+ if ( this . isLoading ) return ;
141+
91142 const container = event . target as HTMLElement ;
92143 if ( ! container ) return ;
93144
@@ -101,6 +152,7 @@ export class CarouselComponent implements AfterViewInit, OnDestroy, OnChanges {
101152 } else if ( currentScroll >= singleSetWidth * 2 - 100 ) {
102153 container . scrollLeft = currentScroll - singleSetWidth ;
103154 }
155+
104156 const containerRect = container . getBoundingClientRect ( ) ;
105157 if ( containerRect . width === 0 ) return ;
106158
0 commit comments