Skip to content

Commit

Permalink
Merge pull request #163 from MurhafSousli/6.1
Browse files Browse the repository at this point in the history
Run gestures outside angular zone
  • Loading branch information
MurhafSousli authored Aug 6, 2018
2 parents 2635da5 + ceb6a26 commit 6fabf6c
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 72 deletions.
84 changes: 46 additions & 38 deletions projects/core/src/lib/components/gallery-slider.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ import {
OnInit,
OnChanges,
Inject,
NgZone,
ElementRef,
EventEmitter,
ChangeDetectionStrategy,
PLATFORM_ID
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { GalleryState, GalleryConfig, SlidingDirection } from '../models';

import { BehaviorSubject, Observable, Subscription, fromEvent } from 'rxjs';
import { map, tap, debounceTime } from 'rxjs/operators';
import { GalleryState, GalleryConfig, SlidingDirection } from '../models';
import { SliderState, WorkerState } from '../models/slider.model';
import { Gallery } from '../services/gallery.service';

declare const Hammer: any;

Expand All @@ -24,11 +26,11 @@ declare const Hammer: any;
changeDetection: ChangeDetectionStrategy.OnPush,
preserveWhitespaces: false,
template: `
<div *ngIf="slider$ | async; let sliderState"
<div *ngIf="sliderState$ | async; let sliderState"
class="g-items-container"
[ngStyle]="zoom">
<div class="g-items-slider"
<div class="g-slider"
[class.g-no-transition]="sliderState.active"
[ngStyle]="sliderState.style">
Expand All @@ -49,7 +51,7 @@ declare const Hammer: any;
export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {

/** Sliding worker */
private readonly _slidingWorker$ = new BehaviorSubject({value: 0, active: false});
private readonly _slidingWorker$ = new BehaviorSubject<WorkerState>({value: 0, active: false});

/** HammerJS instance */
private _hammer: any;
Expand All @@ -58,7 +60,7 @@ export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {
private _resizeSub$: Subscription;

/** Stream that emits sliding state */
slider$: Observable<{ style: any, active: boolean }>;
sliderState$: Observable<SliderState>;

/** Gallery state */
@Input() state: GalleryState;
Expand All @@ -80,14 +82,13 @@ export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {
return {transform: `perspective(50px) translate3d(0, 0, ${-this.config.zoomOut}px)`};
}

constructor(private _el: ElementRef, @Inject(PLATFORM_ID) private platform: Object) {
constructor(private gallery: Gallery, private _el: ElementRef, private _zone: NgZone, @Inject(PLATFORM_ID) private platform: Object) {

// Activate sliding worker
this.slider$ = this._slidingWorker$.pipe(map(
(state: any) => ({
style: this.sliderStyle(state.value),
active: state.active
})));
this.sliderState$ = this._slidingWorker$.pipe(map((state: WorkerState) => ({
style: this.getSliderState(state),
active: state.active
})));
}

ngOnChanges() {
Expand All @@ -102,24 +103,26 @@ export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {
this._hammer = new Hammer(this._el.nativeElement);
this._hammer.get('pan').set({direction: Hammer.DIRECTION_ALL});

// Move the slider
this._hammer.on('pan', (e) => {

switch (this.config.slidingDirection) {
case SlidingDirection.Horizontal:
this.updateSlider({value: e.deltaX, active: true});
if (e.isFinal) {
this.updateSlider({value: 0, active: false});
this.horizontalPan(e);
}
break;
case SlidingDirection.Vertical:
this.updateSlider({value: e.deltaY, active: true});
if (e.isFinal) {
this.updateSlider({value: 0, active: false});
this.verticalPan(e);
}
}
this._zone.runOutsideAngular(() => {
// Move the slider
this._hammer.on('pan', (e) => {

switch (this.config.slidingDirection) {
case SlidingDirection.Horizontal:
this.updateSlider({value: e.deltaX, active: true});
if (e.isFinal) {
this.updateSlider({value: 0, active: false});
this.horizontalPan(e);
}
break;
case SlidingDirection.Vertical:
this.updateSlider({value: e.deltaY, active: true});
if (e.isFinal) {
this.updateSlider({value: 0, active: false});
this.verticalPan(e);
}
}
});
});
}

Expand All @@ -131,10 +134,12 @@ export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {
).subscribe();
}

// Fix wrong slider width on init
// This component width is set to 100%, therefore its width gives 0 at the beginning
// TODO: find a cleaner way to refresh the gallery once slider width is available
// Current workaround: wait 500ms then refresh the slider to fix gallery items' width
setTimeout(() => {
this.updateSlider({value: 0, active: false});
}, 300);
}, 500);
}

ngOnDestroy() {
Expand All @@ -147,19 +152,22 @@ export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {
this._slidingWorker$.complete();
}

private sliderStyle(delta: number) {
/**
* Convert sliding state to styles
*/
private getSliderState(state: WorkerState): any {
switch (this.config.slidingDirection) {
case SlidingDirection.Horizontal:
return {
transform: `translate3d(${-(this.state.currIndex * this._el.nativeElement.offsetWidth) + delta}px, 0, 0)`,
transform: `translate3d(${-(this.state.currIndex * this._el.nativeElement.offsetWidth) + state.value}px, 0, 0)`,
width: this._el.nativeElement.offsetWidth * this.state.items.length + 'px',
height: '100%'
};
case SlidingDirection.Vertical:
return {
transform: `translate3d(0, ${-(this.state.currIndex * this._el.nativeElement.offsetHeight) + delta}px, 0)`,
transform: `translate3d(0, ${-(this.state.currIndex * this._el.nativeElement.offsetHeight) + state.value}px, 0)`,
width: '100%',
height: this._el.nativeElement.offsetHeight * this.state.items.length + 'px',
height: this._el.nativeElement.offsetHeight * this.state.items.length + 'px'
};
}
}
Expand Down Expand Up @@ -204,7 +212,7 @@ export class GallerySliderComponent implements OnInit, OnChanges, OnDestroy {
this.action.emit('prev');
}

private updateSlider(state: any) {
this._slidingWorker$.next({...this._slidingWorker$, ...state});
private updateSlider(state: WorkerState) {
this._slidingWorker$.next({...this._slidingWorker$.value, ...state});
}
}
62 changes: 32 additions & 30 deletions projects/core/src/lib/components/gallery-thumbs.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import {
OnInit,
OnChanges,
HostBinding,
NgZone,
ElementRef,
EventEmitter,
ChangeDetectionStrategy
} from '@angular/core';
import { GalleryConfig, GalleryState, ThumbnailsPosition, ThumbnailsMode } from '../models';

import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { GalleryConfig, GalleryState, ThumbnailsPosition, ThumbnailsMode } from '../models';
import { SliderState, WorkerState } from '../models/slider.model';

declare const Hammer: any;

Expand All @@ -22,11 +23,11 @@ declare const Hammer: any;
changeDetection: ChangeDetectionStrategy.OnPush,
preserveWhitespaces: false,
template: `
<div *ngIf="slider$ | async; let slider"
<div *ngIf="sliderState$ | async; let sliderState"
class="g-thumbs-container">
<div class="g-thumbs-slider"
[class.g-no-transition]="slider.active"
[ngStyle]="slider.style">
<div class="g-slider"
[class.g-no-transition]="sliderState.active"
[ngStyle]="sliderState.style">
<gallery-thumb *ngFor="let item of state.items;let i = index"
[type]="item.type"
Expand All @@ -43,7 +44,7 @@ declare const Hammer: any;
export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {

/** Sliding worker */
private readonly _slidingWorker$ = new BehaviorSubject({value: 0, active: false});
private readonly _slidingWorker$ = new BehaviorSubject<WorkerState>({value: 0, active: false});

/** HammerJS instance */
private _hammer: any;
Expand All @@ -52,7 +53,7 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
private _freeModeCurrentOffset = 0;

/** Stream that emits sliding state */
slider$: Observable<{ style: any, active: boolean }>;
sliderState$: Observable<SliderState>;

/** Gallery state */
@Input() state: GalleryState;
Expand All @@ -72,14 +73,13 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
/** Host width */
@HostBinding('style.width') width: string;

constructor(private _el: ElementRef) {
constructor(private _el: ElementRef, private _zone: NgZone) {

// Activate sliding worker
this.slider$ = this._slidingWorker$.pipe(
map((state: any) => ({
style: this.thumbsStyle(state.value),
active: state.active
})));
this.sliderState$ = this._slidingWorker$.pipe(map((state: WorkerState) => ({
style: this.getSliderState(state),
active: state.active
})));
}

ngOnChanges() {
Expand All @@ -95,14 +95,16 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
this._hammer = new Hammer(this._el.nativeElement);
this._hammer.get('pan').set({direction: Hammer.DIRECTION_ALL});

// Move the slider
switch (this.config.thumbMode) {
case ThumbnailsMode.Strict:
this._hammer.on('pan', (e) => this.strictMode(e));
break;
case ThumbnailsMode.Free:
this._hammer.on('pan', (e) => this.freeMode(e));
}
this._zone.runOutsideAngular(() => {
// Move the slider
switch (this.config.thumbMode) {
case ThumbnailsMode.Strict:
this._hammer.on('pan', (e) => this.strictMode(e));
break;
case ThumbnailsMode.Free:
this._hammer.on('pan', (e) => this.freeMode(e));
}
});
}
}

Expand Down Expand Up @@ -187,14 +189,14 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
/**
* Convert sliding state to styles
*/
private thumbsStyle(delta: number) {
private getSliderState(state: WorkerState): any {
let value: number;
switch (this.config.thumbPosition) {
case ThumbnailsPosition.Top:
case ThumbnailsPosition.Bottom:
this.width = '100%';
this.height = this.config.thumbHeight + 'px';
value = -(this.state.currIndex * this.config.thumbWidth) - (this.config.thumbWidth / 2 - delta);
value = -(this.state.currIndex * this.config.thumbWidth) - (this.config.thumbWidth / 2 - state.value);
return {
transform: `translate3d(${value}px, 0, 0)`,
width: this.state.items.length * this.config.thumbWidth + 'px',
Expand All @@ -204,16 +206,16 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
case ThumbnailsPosition.Right:
this.width = this.config.thumbWidth + 'px';
this.height = '100%';
value = -(this.state.currIndex * this.config.thumbHeight) - (this.config.thumbHeight / 2 - delta);
value = -(this.state.currIndex * this.config.thumbHeight) - (this.config.thumbHeight / 2 - state.value);
return {
transform: `translate3d(0, ${value}px, 0)`,
width: '100%',
height: this.state.items.length * this.config.thumbHeight + 'px',
height: this.state.items.length * this.config.thumbHeight + 'px'
};
}
}

private verticalPan(e) {
private verticalPan(e: any) {
if (e.velocityY > 0.3) {
this.prev();
} else if (e.velocityY < -0.3) {
Expand All @@ -229,7 +231,7 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
}
}

private horizontalPan(e) {
private horizontalPan(e: any) {
if (e.velocityX > 0.3) {
this.prev();
} else if (e.velocityX < -0.3) {
Expand All @@ -253,7 +255,7 @@ export class GalleryThumbsComponent implements OnInit, OnChanges, OnDestroy {
this.action.emit('prev');
}

private updateSlider(state: any) {
this._slidingWorker$.next({...this._slidingWorker$, ...state});
private updateSlider(state: WorkerState) {
this._slidingWorker$.next({...this._slidingWorker$.value, ...state});
}
}
4 changes: 2 additions & 2 deletions projects/core/src/lib/components/gallery.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@ export class GalleryComponent implements OnInit, OnChanges, OnDestroy {

// Subscribes to indexChange and itemsChange events when user bind them
if (this.indexChange.observers.length) {
this._indexChange$ = this.galleryRef.indexChanged.subscribe((e: GalleryState) => this.indexChange.next(e));
this._indexChange$ = this.galleryRef.indexChanged.subscribe((state: GalleryState) => this.indexChange.next(state));
}
if (this.itemsChange.observers.length) {
this._itemChange$ = this.galleryRef.itemsChanged.subscribe((e: GalleryState) => this.itemsChange.next(e));
this._itemChange$ = this.galleryRef.itemsChanged.subscribe((state: GalleryState) => this.itemsChange.next(state));
}
}

Expand Down
4 changes: 2 additions & 2 deletions projects/core/src/lib/directives/lazy.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class LazyDirective implements OnDestroy {
private _worker$ = new Subject();

@Input('lazyImage')
set lazyImage(imagePath) {
set lazyImage(imagePath: string) {
this.loadImage(imagePath);
}

Expand Down Expand Up @@ -47,7 +47,7 @@ export class LazyDirective implements OnDestroy {
).subscribe();
}

loadImage(imagePath) {
loadImage(imagePath: string) {
this._worker$.next(imagePath);
}

Expand Down
9 changes: 9 additions & 0 deletions projects/core/src/lib/models/slider.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface SliderState {
style: any;
active: boolean;
}

export interface WorkerState {
value: number;
active: boolean;
}

0 comments on commit 6fabf6c

Please sign in to comment.