@angular/animations#group TypeScript Examples

The following examples show how to use @angular/animations#group. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: animations.ts    From Angular-Cookbook with MIT License 6 votes vote down vote up
ANIMATIONS = {
  flyInOut: trigger('flyInOut', [
    state('in', style({
      width: 120,
      transform: 'translateX(0)', opacity: 1
    })),
    transition('void => *', [
      style({ width: 10, transform: 'translateX(50px)', opacity: 0 }),
      group([
        animate('0.3s 0.1s ease', style({
          transform: 'translateX(0)',
          // width: 120
        })),
        animate('0.3s ease', style({
          opacity: 1
        }))
      ])
    ]),
    transition('* => void', [
      group([
        animate('0.3s ease', style({
          transform: 'translateX(50px)',
          // width: 10
        })),
        animate('0.3s 0.2s ease', style({
          opacity: 0
        }))
      ])
    ])
  ])
}
Example #2
Source File: fade.animation.ts    From onchat-web with Apache License 2.0 6 votes vote down vote up
fadeRouteAnimation = trigger('fadeRouteAnimation', [
    transition('* <=> *', [
        style({ position: 'relative' }),
        query(':enter, :leave', [
            style({
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%',
                height: '100%'
            }),
            animateChild(),
        ], options),
        query(':enter', [
            style({ opacity: 0 })
        ], options),
        group([
            query(':leave', [
                animate('5s ease-in', style({ opacity: 0 }))
            ], options),
            query(':enter', [
                animate('5s ease-in', style({ opacity: 1 }))
            ], options)
        ]),
    ])
])
Example #3
Source File: app.component.ts    From Angular-Cookbook with MIT License 5 votes vote down vote up
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  animations: [
    trigger('socialBtnText', [
      state(
        'btn-active-text',
        style({
          width: '80px',
          visibility: 'visible',
        })
      ),
      state(
        'btn-inactive-text',
        style({
          width: '0px',
          visibility: 'hidden',
        })
      ),
      transition('btn-active-text => btn-inactive-text', [
        group([
          animate(
            '0s',
            style({
              width: '80px',
            })
          ),
          animate(
            '0s',
            style({
              visibility: 'hidden',
            })
          ),
        ]),
      ]),
      transition('btn-inactive-text => btn-active-text', [
        animate(
          '0.3s ease',
          style({
            width: '80px',
          })
        ),
        animate(
          '0.3s ease',
          style({
            visibility: 'visible',
          })
        ),
      ]),
    ]),
  ],
})
export class AppComponent {
  title = 'ng-dynamic-components';
  selectedCardType: SocialCardType;
  cardTypes = SocialCardType;

  setCardType(type: SocialCardType) {
    this.selectedCardType = type;
  }
}
Example #4
Source File: slide.animation.ts    From ng-ant-admin with MIT License 5 votes vote down vote up
horizontalSlideInRouteAnimation = trigger('horizontalSlideInRouteAnimation', [
  transition(':increment', [
    style({position: 'relative'}),
    query(':enter, :leave', [
      style({
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%'
      }),
      animateChild(),
    ], options),

    query(':enter', [
      style({transform: 'translate3d(100%,0,0)'})
    ], options),

    group([
      query(':leave', [
        animate('.3s ease-out', style({transform: 'translate3d(-100%,0,0)'}))
      ], options),
      query(':enter', [
        animate('.3s ease-out', style({transform: 'none'}))
      ], options)
    ]),
  ]),

  transition(':decrement', [
    style({position: 'relative'}),
    query(':enter, :leave', [
      style({
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%'
      }),
      animateChild(),
    ], options),

    query(':enter', [
      style({transform: 'translate3d(-100%,0,0)'})
    ], options),

    group([
      query(':leave', [
        animate('.3s ease-out', style({transform: 'translate3d(100%,0,0)'}))
      ], options),
      query(':enter', [
        animate('.3s ease-out', style({transform: 'none'}))
      ], options)
    ])
  ])
])
Example #5
Source File: animation.ts    From mns with MIT License 5 votes vote down vote up
slideInAnimation =
  trigger('routeAnimations', [
    transition('HomePage <=> ProductsPage', [
      style({ position: 'relative' }),
      query(':enter, :leave', [
        style({
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%'
        })
      ]),
      query(':enter', [
        style({ left: '-100%' })
      ]),
      query(':leave', animateChild()),
      group([
        query(':leave', [
          animate('300ms ease-out', style({ left: '100%' }))
        ]),
        query(':enter', [
          animate('300ms ease-out', style({ left: '0%' }))
        ])
      ]),
      query(':enter', animateChild()),
    ]),
    transition('* <=> BlogPage', [
      style({ position: 'relative' }),
      query(':enter, :leave', [
        style({
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%'
        })
      ]),
      query(':enter', [
        style({ left: '-100%' })
      ]),
      query(':leave', animateChild()),
      group([
        query(':leave', [
          animate('200ms ease-out', style({ left: '100%' }))
        ]),
        query(':enter', [
          animate('300ms ease-out', style({ left: '0%' }))
        ])
      ]),
      query(':enter', animateChild()),
    ]),
    transition('* <=> ContactPage', [
      style({ position: 'relative' }),
      query(':enter, :leave', [
        style({
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%'
        })
      ]),
      query(':enter', [
        style({ left: '-100%' })
      ]),
      query(':leave', animateChild()),
      group([
        query(':leave', [
          animate('200ms ease-out', style({ left: '100%' }))
        ]),
        query(':enter', [
          animate('300ms ease-out', style({ left: '0%' }))
        ])
      ]),
      query(':enter', animateChild()),
    ])
  ])
Example #6
Source File: slide.animation.ts    From onchat-web with Apache License 2.0 5 votes vote down vote up
horizontalSlideInRouteAnimation = trigger('horizontalSlideInRouteAnimation', [
    transition(':increment', [
        style({ position: 'relative' }),
        query(':enter, :leave', [
            style({
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%'
            }),
            animateChild(),
        ], options),

        query(':enter', [
            style({ transform: 'translate3d(100%,0,0)' })
        ], options),

        group([
            query(':leave', [
                animate('.3s ease-out', style({ transform: 'translate3d(-100%,0,0)' }))
            ], options),
            query(':enter', [
                animate('.3s ease-out', style({ transform: 'none' }))
            ], options)
        ]),
    ]),

    transition(':decrement', [
        style({ position: 'relative' }),
        query(':enter, :leave', [
            style({
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%'
            }),
            animateChild(),
        ], options),

        query(':enter', [
            style({ transform: 'translate3d(-100%,0,0)' })
        ], options),

        group([
            query(':leave', [
                animate('.3s ease-out', style({ transform: 'translate3d(100%,0,0)' }))
            ], options),
            query(':enter', [
                animate('.3s ease-out', style({ transform: 'none' }))
            ], options)
        ])
    ])
])
Example #7
Source File: animations.ts    From Angular-Cookbook with MIT License 4 votes vote down vote up
ROUTE_ANIMATION = trigger('routeAnimation', [
  transition('* <=> *', [
    style({
      position: 'relative',
      perspective: '1000px',
    }),
    query(
      ':enter, :leave',
      [
        style({
          position: 'absolute',
          width: '100%',
        }),
      ],
      optional
    ),
    query(
      ':enter',
      [
        style({
          opacity: 0,
        }),
      ],
      optional
    ),
    group([
      query(
        ':leave',
        [
          animate(
            '1s ease-in',
            keyframes([
              style({
                opacity: 1,
                offset: 0,
                transform: 'rotateY(0) translateX(0) translateZ(0)',
              }),
              style({
                offset: 0.25,
                transform:
                  'rotateY(45deg) translateX(25%) translateZ(100px) translateY(5%)',
              }),
              style({
                offset: 0.5,
                transform:
                  'rotateY(90deg) translateX(75%) translateZ(400px) translateY(10%)',
              }),
              style({
                offset: 0.75,
                transform:
                  'rotateY(135deg) translateX(75%) translateZ(800px) translateY(15%)',
              }),
              style({
                opacity: 0,
                offset: 1,
                transform:
                  'rotateY(180deg) translateX(0) translateZ(1200px) translateY(25%)',
              }),
            ])
          ),
        ],
        optional
      ),

      query(
        ':enter',
        [
          animate(
            '1s ease-out',
            keyframes([
              style({
                opacity: 0,
                offset: 0,
                transform: 'rotateY(180deg) translateX(25%) translateZ(1200px)',
              }),
              style({
                offset: 0.25,
                transform:
                  'rotateY(225deg) translateX(-25%) translateZ(1200px)',
              }),
              style({
                offset: 0.5,
                transform: 'rotateY(270deg) translateX(-50%) translateZ(400px)',
              }),
              style({
                offset: 0.75,
                transform: 'rotateY(315deg) translateX(-50%) translateZ(25px)',
              }),
              style({
                opacity: 1,
                offset: 1,
                transform: 'rotateY(360deg) translateX(0) translateZ(0)',
              }),
            ])
          ),
        ],
        optional
      ),
    ]),
  ]),
])
Example #8
Source File: emote-list.component.ts    From App with MIT License 4 votes vote down vote up
@Component({
	selector: 'app-emote-list',
	templateUrl: './emote-list.component.html',
	styleUrls: ['./emote-list.component.scss'],
	styles: ['.selected-emote-card { opacity: 0 }'],
	animations: [
		trigger('fadeout', [
			state('true', style({ transform: 'translateY(200%)', opacity: 0 })),

			transition('* => true', animate('100ms'))
		]),

		trigger('emotes', [
			transition('* => *', [
				query('.is-emote-card:enter', [
					style({ opacity: 0, transform: 'translateX(0.5em) translateY(-0.5em)', position: 'relative' }),
					stagger(-4, [
						animate('275ms ease-in-out', keyframes([
							style({ opacity: 0, offset: 0.475 }),
							style({ opacity: 1, transform: 'none', offset: 1 })
						]))
					])
				], { optional: true }),

				group([
					query('.is-emote-card:not(.selected-emote-card):leave', [
						style({ opacity: 1 }),
						stagger(2, [
							animate('100ms', style({ transform: 'scale(0)' }))
						])
					], { optional: true }),

					query('.selected-emote-card', [
						style({ opacity: 1 }),
						animate('550ms', keyframes([
							style({ offset: 0, opacity: 1, transform: 'scale(1)' }),
							style({ offset: .2, transform: 'scale(.91)' }),
							style({ offset: .38, transform: 'scale(.64)' }),
							style({ offset: .44, transform: 'scale(.82)' }),

							style({ offset: 1, transform: 'scale(12) translateY(25%)', opacity: 0 })
						])),
					], { optional: true })
				])
			])
		])
	],
	changeDetection: ChangeDetectionStrategy.OnPush
})
export class EmoteListComponent implements  AfterViewInit, OnDestroy {
	destroyed = new Subject<any>().pipe(take(1)) as Subject<void>;
	selecting = new BehaviorSubject(false).pipe(takeUntil(this.destroyed)) as BehaviorSubject<boolean>;
	emotes = new BehaviorSubject<any>([]).pipe(takeUntil(this.destroyed)) as BehaviorSubject<EmoteStructure[]>;
	newPage = new Subject();
	loading = new Subject();
	totalEmotes = new BehaviorSubject<number>(0);
	resized = new Subject<[number, number]>();

	@ViewChild('emotesContainer') emotesContainer: ElementRef<HTMLDivElement> | undefined;
	@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator | undefined;
	@ViewChild('contextMenu') contextMenu: ContextMenuComponent | undefined;
	pageOptions: EmoteListComponent.PersistentPageOptions | undefined;
	pageSize = new BehaviorSubject<number>(16);
	currentSearchOptions: RestV2.GetEmotesOptions | undefined;
	currentSearchQuery = '';
	skipNextQueryChange = false;
	firstPageEvent = true;

	constructor(
		private restService: RestService,
		private renderer: Renderer2,
		private router: Router,
		private route: ActivatedRoute,
		private appService: AppService,
		private dataService: DataService,
		public themingService: ThemingService
	) { }

	selectEmote(ev: MouseEvent, el: any, emote: EmoteStructure): void {
		if (!emote.getID()) return undefined;
		ev.preventDefault();

		this.selecting.next(true);
		this.renderer.addClass(el, 'selected-emote-card');
		this.emotes.next([]);

		setTimeout(() => {
			this.router.navigate(['emotes', emote.getID()]);
		}, 775);
	}

	private updateQueryParams(replaceUrl: boolean = false): void {
		const merged = {
			...this.currentSearchOptions,
			...{ page: (this.pageOptions?.pageIndex ?? 0) }
		};

		this.skipNextQueryChange = true;
		this.router.navigate(['.'], {
			relativeTo: this.route,
			queryParams: Object.keys(merged).map(k => ({ [k]: (merged as any)[k as any] })).reduce((a, b) => ({ ...a, ...b })),
			queryParamsHandling: 'merge',
			replaceUrl
		});
	}

	handleSearchChange(change: Partial<RestV2.GetEmotesOptions>): void {
		const queryString = Object.keys(change).map(k => `${k}=${change[k as keyof RestV2.GetEmotesOptions]}`).join('&');

		this.appService.pushTitleAttributes({ name: 'SearchOptions', value: `- ${queryString}` });
		this.currentSearchOptions = { ...this.currentSearchOptions, ...change as RestV2.GetEmotesOptions };
		this.updateQueryParams();

		this.goToFirstPage();
		this.getEmotes(undefined, this.currentSearchOptions).pipe(
			delay(50),
			tap(emotes => this.emotes.next(emotes))
		).subscribe();
	}

	getEmotes(page = 0, options?: Partial<RestV2.GetEmotesOptions>): Observable<EmoteStructure[]> {
		this.emotes.next([]);
		this.newPage.next(page);
		const timeout = setTimeout(() => this.loading.next(true), 1000);
		const cancelSpinner = () => {
			this.loading.next(false);
			clearTimeout(timeout);
		};

		const size = this.calculateSizedRows();
		return this.restService.awaitAuth().pipe(
			switchMap(() => this.restService.v2.SearchEmotes(
				(this.pageOptions?.pageIndex ?? 0) + 1,
				Math.max(EmoteListComponent.MINIMUM_EMOTES, size ?? EmoteListComponent.MINIMUM_EMOTES),
				options ?? this.currentSearchOptions
			)),

			takeUntil(this.newPage.pipe(take(1))),
			tap(res => this.totalEmotes.next(res?.total_estimated_size ?? 0)),
			delay(200),
			map(res => res?.emotes ?? []),
			mergeAll(),
			map(data => this.dataService.add('emote', data)[0]),
			toArray(),
			defaultIfEmpty([] as EmoteStructure[]),

			tap(() => cancelSpinner()),
			catchError(() => defer(() => cancelSpinner()))
		) as Observable<EmoteStructure[]>;
	}

	onOpenCardContextMenu(emote: EmoteStructure): void {
		if (!this.contextMenu) {
			return undefined;
		}

		this.contextMenu.contextEmote = emote;
		emote.getOwner().pipe(
			tap(usr => !!this.contextMenu ? this.contextMenu.contextUser = (usr ?? null) : noop())
		).subscribe();
	}

	goToFirstPage(): void {
		this.paginator?.page.next({
			pageIndex: 0,
			pageSize: this.pageOptions?.pageSize ?? 0,
			length: this.pageOptions?.length ?? 0,
		});
	}

	/**
	 * Handle pagination changes
	 */
	onPageEvent(ev: PageEvent): void {
		this.pageOptions = {
			...ev
		};

		if (this.firstPageEvent) {
			this.updateQueryParams(true);
			this.firstPageEvent = false;
		}
		else {
			this.updateQueryParams();
		}

		// Save PageIndex title attr
		this.appService.pushTitleAttributes({ name: 'PageIndex', value: `- ${ev.pageIndex}/${Number((ev.length / ev.pageSize).toFixed(0))}` });

		// Fetch new set of emotes
		this.getEmotes(ev.pageIndex).pipe(
			tap(emotes => this.emotes.next(emotes))
		).subscribe();
	}

	isEmpty(): Observable<boolean> {
		return this.totalEmotes.pipe(
			take(1),
			map(size => size === 0)
		);
	}

	/**
	 * Calculate how many rows and columns according to the container's size
	 *
	 * @returns the result of rows * columns
	 */
	calculateSizedRows(): number | null {
		if (!this.emotesContainer) {
			return null;
		}

		const marginBuffer = 28; // The margin _in pixels between each card
		const cardSize = 137; // The size of the cards in pixels
		const width = this.emotesContainer.nativeElement.scrollWidth - 32; // The width of emotes container
		const height = this.emotesContainer.nativeElement.clientHeight - 16; // The height of the emotes container

		const rows = Math.floor((width / (cardSize + marginBuffer))); // The calculated amount of rows
		const columns = Math.floor(height / (cardSize + marginBuffer)); // The calculated amount of columns

		// Return the result of rows multiplied by columns
		return rows * columns;
	}

	@HostListener('window:resize', ['$event'])
	onWindowResize(ev: Event): void {
		const size = this.calculateSizedRows();
		this.pageSize.next(size ?? 0);

		this.resized.next([0, 0]);
		timer(1000).pipe(
			takeUntil(this.resized.pipe(take(1))),

			switchMap(() => this.getEmotes(this.pageOptions?.pageIndex, {})),
			tap(emotes => this.emotes.next(emotes))
		).subscribe();
	}

	ngAfterViewInit(): void {
		// Get persisted page options?
		this.route.queryParamMap.pipe(
			defaultIfEmpty({} as ParamMap),
			map(params => {
				return {
					page: params.has('page') ? Number(params.get('page')) : 0,
					search: {
						sortBy: params.get('sortBy') ?? 'popularity',
						sortOrder: params.get('sortOrder'),
						globalState: params.get('globalState'),
						query: params.get('query'),
						submitter: params.get('submitter'),
						channel: params.get('channel')
					}
				};
			}),
			tap(() => setTimeout(() => this.skipNextQueryChange = false, 0)),
			filter(() => !this.skipNextQueryChange)
		).subscribe({
			next: opt => {
				const d = {
					pageIndex: !isNaN(opt.page) ? opt.page : 0,
					pageSize: Math.max(EmoteListComponent.MINIMUM_EMOTES, this.calculateSizedRows() ?? 0),
					length: 0,
				};
				this.updateQueryParams(true);
				this.currentSearchOptions = opt.search as any;

				this.paginator?.page.next(d);
				this.pageOptions = d;
			}
		});

		this.pageSize.next(this.calculateSizedRows() ?? 0);
	}

	ngOnDestroy(): void {
		this.loading.complete();
	}

}