@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 |
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 |
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 |
@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 |
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 |
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 |
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 |
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 |
@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();
}
}